Skip to content

Instantly share code, notes, and snippets.

@JCKodel
Created July 3, 2025 18:51
Show Gist options
  • Save JCKodel/4d8a0d7ac720ba153dee1b910e22de4d to your computer and use it in GitHub Desktop.
Save JCKodel/4d8a0d7ac720ba153dee1b910e22de4d to your computer and use it in GitHub Desktop.
Dart i18n_extension translator
// ignore_for_file: avoid_print
import 'dart:collection';
import 'dart:convert';
import 'dart:io';
void main(List<String> arguments) {
final dartFiles = Directory(
"lib",
).listSync(recursive: true).where((entity) => entity.path.endsWith(".dart"));
final i18nStrings = <String>{};
final stringRegex = RegExp(
r'(?:"""([\s\S]*?)"""|"([^"]*)")\s*\.(trs|fill)',
multiLine: true,
);
for (final file in dartFiles) {
final content = File(file.path).readAsStringSync();
final matches = stringRegex.allMatches(content);
if (matches.isNotEmpty) {
print("Processing ${file.path}: ${matches.length}");
for (final match in matches) {
final key = match.group(1)?.trim() ?? match.group(2)?.trim();
if (key != null) {
i18nStrings.add(key);
}
}
}
}
updateTranslationFile("en", i18nStrings);
updateTranslationFile("pt", i18nStrings);
}
Future<void> updateTranslationFile(String language, Set<String> i18nStrings) async {
final file = File("assets/translations/$language.json");
final json = file.readAsStringSync();
final translations = LinkedHashMap<String, dynamic>.from(jsonDecode(json) as Map);
final tasks = <Future<String>>[];
var updated = false;
for (final key in i18nStrings) {
if (translations.containsKey(key) == false) {
if (language == "pt") {
translations[key] = key;
} else {
translations[key] = "";
tasks.add(
_translate(key, language).then((value) => translations[key] = value),
);
}
updated = true;
}
}
await Future.wait(tasks);
final numberOfKeys = translations.length;
translations.removeWhere(
(key, value) => key.contains(".") == false && i18nStrings.contains(key) == false,
);
if (updated || numberOfKeys != translations.length) {
file.writeAsStringSync(
const JsonEncoder.withIndent(
" ",
).convert(Map<String, dynamic>.from(translations)),
);
print("Updated $language with ${translations.length} keys");
}
}
Future<String> _translate(String text, String language) async {
final result = await Process.run('./trans.sh', [
'-b',
'-e',
'bing',
':${language}',
text,
], runInShell: true);
if (result.exitCode != 0) {
return "";
}
return result.stdout.toString().trim();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment