runLocalizationCleaner function
Scans the project for unused localization keys and removes them from .arb files.
Implementation
void runLocalizationCleaner({bool keepUnused = false}) {
final File yamlFile = File('l10n.yaml'); // Path to the l10n.yaml file
if (!yamlFile.existsSync()) {
print('✅ Error: l10n.yaml file not found!');
return;
}
// Read & parse YAML
final String yamlContent = yamlFile.readAsStringSync();
final Map yamlData = loadYaml(yamlContent);
// Extract values dynamically
final String arbDir = yamlData['arb-dir'] as String;
// Construct values
final Directory localizationDir = Directory(arbDir);
final Set<String> excludedFiles = {'$arbDir/app_localizations.dart'};
// Read .arb file
final List<File> localizationFiles =
localizationDir
.listSync()
.whereType<File>()
.where((file) => file.path.endsWith('.arb'))
.toList();
if (localizationFiles.isEmpty) {
print('✅ No .arb files found in ${localizationDir.path}');
return;
}
final Set<String> allKeys = <String>{};
final Map<File, Set<String>> fileKeyMap = <File, Set<String>>{};
// Read all keys from ARB files
for (final File file in localizationFiles) {
final Map<String, dynamic> data =
json.decode(file.readAsStringSync()) as Map<String, dynamic>;
final Set<String> keys =
data.keys.where((key) => !key.startsWith('@')).toSet();
allKeys.addAll(keys);
fileKeyMap[file] = keys;
}
final Set<String> usedKeys = <String>{};
final List<String> dartScanDirs = _getDartScanDirs();
// Scan Dart files for key usage
for (final String dirPath in dartScanDirs) {
final Directory dir = Directory(dirPath);
if (!dir.existsSync()) {
print('⚠️ Warning: dart-scan-dir "$dirPath" does not exist, skipping.');
continue;
}
for (final FileSystemEntity file in dir.listSync(recursive: true)) {
if (file is File &&
file.path.endsWith('.dart') &&
!excludedFiles.contains(file.path)) {
final String content = file.readAsStringSync();
usedKeys.addAll(findUsedKeysInContent(content, allKeys));
}
}
}
// Determine unused keys
final Set<String> unusedKeys = allKeys.difference(usedKeys);
if (unusedKeys.isEmpty) {
print('✅ No unused localization keys found.');
return;
}
print("✅ Unused keys found: ${unusedKeys.join(', ')}");
if (keepUnused) {
// Keep unused keys to a file instead of deleting them
final File unusedKeysFile = File('unused_localization_keys.txt');
unusedKeysFile.writeAsStringSync(unusedKeys.join('\n'));
print('✅ Unused keys saved to ${unusedKeysFile.path}');
} else {
// Remove unused keys from all .arb files
for (final MapEntry<File, Set<String>> entry in fileKeyMap.entries) {
final File file = entry.key;
final Set<String> keys = entry.value;
final Map<String, dynamic> data =
json.decode(file.readAsStringSync()) as Map<String, dynamic>;
bool updated = false;
for (final key in keys) {
if (unusedKeys.contains(key)) {
data.remove(key);
data.remove('@$key');
updated = true;
}
}
if (updated) {
file.writeAsStringSync(
const JsonEncoder.withIndent(' ').convert(data),
);
print('✅ Updated ${file.path}, removed unused keys.');
}
}
print('✅ Unused keys successfully removed.');
}
}