/// migrates chosen strings from lemmy-translations into flutter's i18n solution import 'dart:convert'; import 'dart:io'; import 'common.dart'; /// Map, if `renamedKey` is null then no rename is performed const toExtract = { 'settings': null, }; const repoName = 'lemmy-translations'; const baseLanguage = 'en'; const flutterIntlPrefix = 'intl_'; Future main(List args) async { final force = args.contains('-f') || args.contains('--force'); final repoCleanup = await cloneLemmyTranslations(); final lemmyTranslations = await loadLemmyStrings(); final lemmurTranslations = await loadLemmurStrings(); portStrings(lemmyTranslations, lemmurTranslations, force: force); await save(lemmurTranslations); await Process.run('flutter', ['gen-l10n']); await repoCleanup(); print("Don't forget to format the arb files!"); } /// returns a cleanup function Future Function()> cloneLemmyTranslations() async { await Process.run('git', ['clone', 'https://github.com/LemmyNet/$repoName']); return () => Directory(repoName).delete(recursive: true); } /// Map> Future>> loadLemmyStrings() async { final translationsDir = Directory('$repoName/translations'); final translations = >{}; await for (final file in translationsDir.list()) { final transFile = File.fromUri(file.uri); final trans = Map.from( jsonDecode(await transFile.readAsString()) as Map, ); final localeName = file.uri.pathSegments.last.split('.json').first; translations[localeName] = trans; } return translations; } /// Map> + some metadata Future>> loadLemmurStrings() async { final translationsDir = Directory('lib/l10n'); final translations = >{}; await for (final file in translationsDir.list()) { if (!file.path.endsWith('.arb')) continue; final transFile = File.fromUri(file.uri); final trans = jsonDecode(await transFile.readAsString()) as Map; final localeName = file.uri.pathSegments.last .split('.arb') .first .split(flutterIntlPrefix) .last; translations[localeName] = trans; } return translations; } /// will port them into `lemmurTranslations` void portStrings( Map> lemmyTranslations, Map> lemmurTranslations, { bool force = false, }) { // port all languages for (final language in lemmyTranslations.keys) { if (!lemmurTranslations.containsKey(language)) { lemmurTranslations[language] = {}; lemmurTranslations[language]['@@locale'] = language; } } for (final extract in toExtract.entries) { final key = extract.key; final renamedKey = extract.value ?? key; if (!lemmyTranslations[baseLanguage].containsKey(key)) { printError( '"$key" does not exist in $repoName', shouldExit: true, ); } if (lemmurTranslations[baseLanguage].containsKey(key) && !force) { confirm('"$key" already exists in lemmur, overwrite?'); } for (final trans in lemmyTranslations.entries) { final language = trans.key; final strings = trans.value; lemmurTranslations[language][renamedKey] = strings[key]; } lemmurTranslations[baseLanguage]['@$renamedKey'] = {}; } } Future save(Map> lemmurTranslations) async { // remove null fields // Vec<(language, key)> final toRemove = >[]; for (final translations in lemmurTranslations.entries) { final language = translations.key; for (final strings in translations.value.entries) { if (strings.value == null) { toRemove.add([language, strings.key]); } } } for (final rem in toRemove) { lemmurTranslations[rem[0]].remove(rem[1]); } for (final language in lemmurTranslations.keys) { await File('lib/l10n/$flutterIntlPrefix$language.arb') .writeAsString(jsonEncode(lemmurTranslations[language])); } }