app/packages/sct_dev_tools/bin/auto_l10n.dart

259 lines
8.1 KiB
Dart
Raw Normal View History

2024-03-14 21:49:21 +08:00
import 'dart:convert';
import 'dart:io';
import 'package:analyzer/dart/analysis/utilities.dart';
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/ast/ast.dart';
2024-03-17 12:44:50 +08:00
import 'package:translator/translator.dart';
2024-03-14 21:49:21 +08:00
import 'package:uuid/v4.dart';
final stringResult = <String>[];
class AutoL10nTools {
2024-03-17 16:54:09 +08:00
final skipPaths = ["lib/generated"];
2024-03-14 21:49:21 +08:00
void genL10nFiles() {
2024-03-17 16:54:09 +08:00
final dir = Directory('lib/');
2024-03-14 21:49:21 +08:00
for (var entity in dir.listSync(recursive: true)) {
2024-03-17 16:54:09 +08:00
bool shouldSkip = false;
for (var path in skipPaths) {
if (entity.path.replaceAll("\\", "/").startsWith(path)) {
shouldSkip = true;
}
break;
}
if (shouldSkip) continue;
2024-03-14 21:49:21 +08:00
if (entity is File && entity.path.endsWith('.dart')) {
print('Processing ${entity.path}...');
_processDartFile(entity);
}
}
if (stringResult.isNotEmpty) {
final outputMap = <String, String>{};
for (var value in stringResult) {
if (outputMap.containsValue(value)) {
continue;
}
2024-03-17 16:54:09 +08:00
var key = UuidV4().generate();
final l10nFile = File("./lib/l10n/intl_zh_CN.arb");
final cnJsonMap = json.decode(l10nFile.readAsStringSync()) as Map;
for (var element in cnJsonMap.entries) {
if (element.value == value) {
key = element.key;
}
}
2024-03-14 21:49:21 +08:00
outputMap[key] = value;
}
// output to json
final j = json.encode(outputMap);
2024-03-14 23:22:56 +08:00
File("./lib/generated/l10n_temp.json").writeAsStringSync(j);
2024-03-14 21:49:21 +08:00
print(
2024-12-14 13:48:24 +08:00
"output to json file (length: ${outputMap.length}): ./lib/generated/l10n_temp.json");
2024-03-14 21:49:21 +08:00
}
2024-03-14 23:22:56 +08:00
}
void replaceL10nFiles() {
final l10nFile = File("./lib/l10n/intl_zh_CN.arb");
// readToJsonMap
final jsonMap = json.decode(l10nFile.readAsStringSync());
// read all dart File
2024-03-17 16:54:09 +08:00
final dir = Directory('lib/');
2024-03-14 23:22:56 +08:00
for (var entity in dir.listSync(recursive: true)) {
2024-03-17 16:54:09 +08:00
bool shouldSkip = false;
for (var path in skipPaths) {
if (entity.path.replaceAll("\\", "/").startsWith(path)) {
shouldSkip = true;
}
break;
}
if (shouldSkip) continue;
2024-03-15 00:01:06 +08:00
if (entity is File &&
entity.path.endsWith('.dart') &&
!(entity.path.endsWith(".g.dart") &&
2024-11-03 18:32:12 +08:00
!entity.path.endsWith(".freezed.dart"))) {
2024-03-14 23:22:56 +08:00
print('Processing ${entity.path}...');
2024-03-15 00:01:06 +08:00
// sort map with value length
2024-03-17 16:54:09 +08:00
final newMap = Map<String, dynamic>.fromEntries(
2024-03-15 00:01:06 +08:00
jsonMap.entries.toList()
2024-12-14 13:48:24 +08:00
..sort((a, b) => (b.value.toString())
.length
.compareTo((a.value.toString()).length)),
2024-03-15 00:01:06 +08:00
);
_replaceDartFile(entity, newMap);
2024-03-14 23:22:56 +08:00
}
}
2024-03-14 21:49:21 +08:00
}
2024-03-17 12:44:50 +08:00
Future<void> autoTranslate({required String form, required String to}) async {
final formFile = File("./lib/l10n/intl_$form.arb");
final toFile = File("./lib/l10n/intl_$to.arb");
final translator = GoogleTranslator();
final formMap =
2024-12-14 13:48:24 +08:00
json.decode(formFile.readAsStringSync()) as Map<String, dynamic>;
2024-03-17 12:44:50 +08:00
final toMap =
2024-12-14 13:48:24 +08:00
json.decode(toFile.readAsStringSync()) as Map<String, dynamic>;
2024-03-17 12:44:50 +08:00
2024-07-07 17:49:15 +08:00
final formLocaleCode = formMap["@@auto_translate_locale"].toString();
final toLocaleCode = toMap["@@auto_translate_locale"].toString();
2024-03-17 12:44:50 +08:00
print("formLocaleCode: $formLocaleCode, toLocaleCode: $toLocaleCode");
final newMap = <String, dynamic>{};
try {
for (var key in formMap.keys) {
if (toMap.keys.contains(key)) {
newMap[key] = toMap[key];
continue;
}
if (key.toString().startsWith("@") || key == "locale_code") {
continue;
}
final value = formMap[key] as String;
final result = await translator.translate(value,
from: formLocaleCode, to: toLocaleCode);
var resultValue = result.text;
// 如果目标语言是英文,则首字母大写
if (toLocaleCode == "en") {
resultValue = resultValue[0].toUpperCase() + resultValue.substring(1);
}
print("translate $key: $value -> $resultValue");
newMap[key] = resultValue;
await Future.delayed(Duration(milliseconds: 500));
}
} catch (e) {
print(e);
toMap.addAll(newMap);
toFile.writeAsStringSync(json.encode(toMap));
}
toMap.addAll(newMap);
toFile.writeAsStringSync(json.encode(toMap));
}
2024-03-14 21:49:21 +08:00
void _processDartFile(File file) {
final parseResult = parseFile(
path: file.path, featureSet: FeatureSet.latestLanguageVersion());
final unit = parseResult.unit;
unit.accept(MyAstVisitor());
}
2024-03-14 23:22:56 +08:00
void _replaceDartFile(File entity, jsonMap) {
2024-03-15 00:01:06 +08:00
for (var key in jsonMap.keys) {
if (key == "@@locale") continue;
2024-03-17 16:54:09 +08:00
final mapValue = jsonMap[key].toString();
2024-03-17 12:44:50 +08:00
if (mapValue.contains("{") && mapValue.contains("}")) {
2024-05-05 16:34:38 +08:00
// print("skipping args value === $mapValue");
2024-03-15 00:01:06 +08:00
continue;
}
// 使用 CheckContainsVisitor.visitStringLiteral 获取是否有匹配的值 ,返回 true false
final parseResult = parseFile(
path: entity.path, featureSet: FeatureSet.latestLanguageVersion());
final unit = parseResult.unit;
final visitor = CheckContainsVisitor(mapValue);
unit.accept(visitor);
if (visitor.hasValue) {
// replaceDartFile with line
final lines = entity.readAsLinesSync();
final newLines = <String>[];
for (var line in lines) {
if (line.contains(mapValue) && !line.contains("\$")) {
line = line.replaceAll(mapValue, "\${S.current.$key}");
}
newLines.add(line);
}
entity.writeAsStringSync(newLines.join("\n"));
}
}
2024-03-14 23:22:56 +08:00
}
}
2024-03-15 00:01:06 +08:00
class CheckContainsVisitor extends GeneralizingAstVisitor {
final String mapValue;
2024-03-14 23:22:56 +08:00
2024-03-15 00:01:06 +08:00
CheckContainsVisitor(this.mapValue);
bool hasValue = false;
2024-03-14 23:22:56 +08:00
@override
2024-03-15 00:01:06 +08:00
visitStringLiteral(StringLiteral node) {
final value = node.stringValue ?? "";
if (value == mapValue) {
print('Found->visitStringLiteral: $value');
hasValue = true;
2024-03-14 23:22:56 +08:00
}
2024-03-15 00:01:06 +08:00
return super.visitStringLiteral(node);
2024-03-14 23:22:56 +08:00
}
2024-03-14 21:49:21 +08:00
}
class MyAstVisitor extends GeneralizingAstVisitor {
@override
visitStringLiteral(StringLiteral node) {
final value = node.stringValue ?? "";
if (containsChinese(value)) {
print('Found->visitStringLiteral: $value');
addStringResult(value);
}
return super.visitStringLiteral(node);
}
@override
visitAdjacentStrings(AdjacentStrings node) {
int interpolationIndex = 0;
var result = '';
for (var string in node.strings) {
if (string is SimpleStringLiteral) {
result += string.value;
} else if (string is StringInterpolation) {
for (var element in string.elements) {
if (element is InterpolationString) {
result += element.value;
} else if (element is InterpolationExpression) {
2024-03-16 17:35:52 +08:00
result += '{v${interpolationIndex++}}';
2024-03-14 21:49:21 +08:00
}
}
}
}
if (containsChinese(result)) {
print('Found->visitAdjacentStrings: $result');
addStringResult(result);
}
return super.visitAdjacentStrings(node);
}
@override
visitStringInterpolation(StringInterpolation node) {
int interpolationIndex = 0;
var result = '';
for (var element in node.elements) {
if (element is InterpolationString) {
result += element.value;
} else if (element is InterpolationExpression) {
2024-03-16 17:35:52 +08:00
result += '{v${interpolationIndex++}}';
2024-03-14 21:49:21 +08:00
}
}
if (containsChinese(result)) {
print('Found->visitStringInterpolation: $result');
addStringResult(result);
}
return super.visitStringInterpolation(node);
}
@override
visitInterpolationExpression(InterpolationExpression node) {
int interpolationIndex = 0;
2024-03-16 17:35:52 +08:00
final value = '{v${interpolationIndex++}}';
2024-03-14 21:49:21 +08:00
if (containsChinese(value)) {
print('Found->visitInterpolationExpression: $value');
addStringResult(value);
}
return super.visitInterpolationExpression(node);
}
bool containsChinese(String input) {
return RegExp(r'[\u4e00-\u9fa5]').hasMatch(input);
}
addStringResult(String value) {
stringResult.add(value);
}
}