From d3a6c6fe291ff3b12f1d79affed1358945fcb252 Mon Sep 17 00:00:00 2001 From: MSOB7YY Date: Fri, 24 Nov 2023 03:10:39 +0200 Subject: [PATCH] core: more language scripts 1. tr_unused: find unused keys 2. tr_refine: unifies all language files to follow en_US.json 3. tr (update): now accepts multiple keys to add/remove --- tr.dart | 53 ++++++++++++++++++++++++++++++++++---------------- tr_refine.dart | 52 +++++++++++++++++++++++++++++++++++++++++++++++++ tr_unused.dart | 38 ++++++++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 17 deletions(-) create mode 100644 tr_refine.dart create mode 100644 tr_unused.dart diff --git a/tr.dart b/tr.dart index 20ce4425..88f8a545 100644 --- a/tr.dart +++ b/tr.dart @@ -10,14 +10,20 @@ import 'dart:io'; /// * Notes: /// - Key is not case sensitive, ex: `my_key`, `MY_KEY` & `My_key` are all valid. /// - Key words should be separated with underscore. +/// * NEW: +/// - now supports multiple insertions, deletions. +/// - only: `KEY` format is approved, ex: `KEY1,KEY2,KEY3`. +/// - separated by commas (,) +/// - if `KEY1,KEY2 VALUE` was used, only first key will be inserted void main(List argumentsPre) async { final args = List.from(argumentsPre); final shouldRemove = args.remove('-r'); - final argKey = args[0].toUpperCase(); + final argKeyhh = args[0].toUpperCase(); + final argKeys = argKeyhh.split(','); // should remove if (shouldRemove) { - await _removeKey(argKey); + await _removeKeys(argKeys); return; } @@ -25,20 +31,24 @@ void main(List argumentsPre) async { if (args.length == 2) { // should add `KEY: value` normally final value = args[1]; - await _addKey(argKey, value); + await _addKey({argKeys.first: value}); } else // want to add `KEY` with identical value // ex: `MY_NAME` : `My name` if (args.length == 1) { - final valuePre = argKey.replaceAll('_', ' ').toLowerCase(); - final value = "${valuePre[0].toUpperCase()}${valuePre.substring(1)}"; - await _addKey(argKey, value); + final map = {}; + for (final argKey in argKeys) { + final valuePre = argKey.replaceAll('_', ' ').toLowerCase(); + final value = "${valuePre[0].toUpperCase()}${valuePre.substring(1)}"; + map[argKey] = value; + } + await _addKey(map); } else { - print('Error(Missing Arguments): Supported arguments: `KEY VALUE` | `KEY` | `-r KEY`'); + print('Error(Missing Arguments): Supported arguments: `KEY VALUE` | `KEY` | `KEY1,KEY2` |`-r KEY`'); } } -Future _addKey(String argKey, String argValue) async { +Future _addKey(Map argKeysVals) async { try { // -- Keys File final file = File(_keysFilePath); @@ -58,7 +68,9 @@ Future _addKey(String argKey, String argValue) async { // keys.add(withoutSC.join()); // } } - keys.insertWithOrder(argKey); + for (final argKey in argKeysVals.keys) { + keys.insertWithOrder(argKey); + } await file.writeAsString(""" // ignore_for_file: non_constant_identifier_names // AUTO GENERATED FILE @@ -91,28 +103,33 @@ ${keys.map((e) => " String get $e => _getKey('$e');").join('\n')} if (fileSystem.path.endsWith('.json')) { final str = await fileSystem.readAsString(); final map = await jsonDecode(str) as Map; - map.addAll({argKey: argValue}); + map.addAll(argKeysVals); final sorted = Map.fromEntries(map.entries.toList()..sort((a, b) => a.key.compareTo(b.key))); await fileSystem.writeAsString(encoder.convert(sorted)); } } } - print('Added Successfully'); + print('Added ${argKeysVals.length} ${argKeysVals.length > 1 ? 'keys' : 'key'} Successfully'); return true; } on Exception catch (e) { - print('Error Adding: $e\nRemoving Key...'); - _removeKey(argKey); + print('Error Adding: $e\nRemoving Keys...'); + _removeKeys(argKeysVals.keys); return false; } } -Future _removeKey(String keyToRemove) async { +Future _removeKeys(Iterable keysToRemove) async { try { // -- Keys File final file = File(_keysFilePath); final lines = await file.readAsLines(); - final indToRemove = lines.indexWhere((element) => element.contains("String get $keyToRemove => _getKey('$keyToRemove');")); - lines.removeAt(indToRemove); + // -- reverse looping for index-related issues + for (int i = lines.length - 1; i >= 0; i--) { + final line = lines[i]; + if (keysToRemove.any((keyToRemove) => line.contains("String get $keyToRemove => _getKey('$keyToRemove');"))) { + lines.removeAt(i); + } + } await file.writeAsString('${lines.join('\n')}\n'); // -- Controller file @@ -134,7 +151,9 @@ Future _removeKey(String keyToRemove) async { if (fileSystem.path.endsWith('.json')) { final str = await fileSystem.readAsString(); final map = await jsonDecode(str) as Map; - map.remove(keyToRemove); + for (final keyToRemove in keysToRemove) { + map.remove(keyToRemove); + } await fileSystem.writeAsString(encoder.convert(map)); } } diff --git a/tr_refine.dart b/tr_refine.dart new file mode 100644 index 00000000..fea791ae --- /dev/null +++ b/tr_refine.dart @@ -0,0 +1,52 @@ +// ignore_for_file: avoid_print, depend_on_referenced_packages + +import 'dart:convert'; +import 'dart:io'; +import 'package:path/path.dart' as p; + +void main(List args) async { + Future?> parseJSONFile(File file) async { + try { + final str = await file.readAsString(); + final langMap = await jsonDecode(str) as Map; + return langMap; + } catch (e) { + print('Error parsing the map $e'); + } + return null; + } + + const engJsonFileName = 'en_US.json'; + final mainMap = {}; + final mainFile = File("$_languagesDirectoryPath\\$engJsonFileName"); + final mainParsed = await parseJSONFile(mainFile); + if (mainParsed == null || mainParsed.isEmpty) { + print('Error parsing the main map, aborting...'); + return; + } + mainMap.addAll(mainParsed); + + const encoder = JsonEncoder.withIndent(' '); + await for (final fileSystem in Directory(_languagesDirectoryPath).list()) { + if (fileSystem is File) { + if (p.basename(fileSystem.path) != engJsonFileName && fileSystem.path.endsWith('.json')) { + final copyMap = Map.from(mainMap); + final langMap = await parseJSONFile(fileSystem); + if (langMap == null || langMap.isEmpty) { + print('Error parsing the json of $fileSystem, skipping...'); + continue; + } + for (final e in langMap.keys) { + if (copyMap[e] != null) { + // -- only assign if the key exists in the main map + // -- remaining keys (ones exists in main but not in lang) will have the same value of default map. + copyMap[e] = langMap[e]; + } + } + await fileSystem.writeAsString(encoder.convert(copyMap)); + } + } + } +} + +const _languagesDirectoryPath = 'assets\\language\\translations'; diff --git a/tr_unused.dart b/tr_unused.dart new file mode 100644 index 00000000..4d508902 --- /dev/null +++ b/tr_unused.dart @@ -0,0 +1,38 @@ +// ignore_for_file: avoid_print + +import 'dart:io'; + +void main(List args) async { + final filesPathsAndText = {}; + await for (final d in Directory('lib').list(recursive: true)) { + if (d is File && d.path != _keysFilePath) { + filesPathsAndText[d.path] = await File(d.path).readAsString(); + } + } + + bool findMatchInProject(String value) { + for (final f in filesPathsAndText.keys) { + final string = filesPathsAndText[f] ?? ''; + if (string.contains(value)) return true; + } + return false; + } + + final file = File(_keysFilePath); + final lines = await file.readAsLines(); + + final notUsedKeys = []; + for (final line in lines) { + final regexRes = RegExp(r'(?<=String get )(.*)(?= =>)'); + final match = regexRes.firstMatch(line)?[0]; + if (match != null) { + final hasMatch = findMatchInProject(match); + if (!hasMatch) notUsedKeys.add(match); + } + } + print("${notUsedKeys.length} not used keys were found"); + print("--------------------------------"); + print(notUsedKeys.toString()); +} + +const _keysFilePath = 'lib\\core\\translations\\keys.dart';