Skip to content

Commit 6504f28

Browse files
authored
Adds menuBarMenuLabel, and removes unneeded key localizations (#102100)
When I added localizations for shortcut keys, I added some that actually can't be shortcut keys, so I'm removing them again. These are mostly Japanese-specific keys that don't even appear on modern keyboards for the most part. Also, added menuBarMenuLabel for an accessibility label for menu bar menus. I modified the code for the localization generation scripts to add a --remove-undefined flag that will remove any localizations that don't appear in the canonical locale.
1 parent 84ffdad commit 6504f28

File tree

86 files changed

+527
-4209
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+527
-4209
lines changed

dev/bots/analyze.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,7 @@ Future<void> verifyInternationalizations(String workingDirectory, String dartExe
742742
<String>[
743743
path.join('dev', 'tools', 'localization', 'bin', 'gen_localizations.dart'),
744744
'--material',
745+
'--remove-undefined',
745746
],
746747
workingDirectory: workingDirectory,
747748
);
@@ -750,6 +751,7 @@ Future<void> verifyInternationalizations(String workingDirectory, String dartExe
750751
<String>[
751752
path.join('dev', 'tools', 'localization', 'bin', 'gen_localizations.dart'),
752753
'--cupertino',
754+
'--remove-undefined',
753755
],
754756
workingDirectory: workingDirectory,
755757
);

dev/tools/localization/bin/gen_localizations.dart

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@
3232
// dart dev/tools/localization/bin/gen_localizations.dart
3333
// ```
3434
//
35+
// If you have removed localizations from the canonical localizations, then
36+
// add the '--remove-undefined' flag to also remove them from the other files.
37+
//
38+
// ```
39+
// dart dev/tools/localization/bin/gen_localizations.dart --remove-undefined
40+
// ```
41+
//
3542
// If the data looks good, use the `-w` or `--overwrite` option to overwrite the
3643
// packages/flutter_localizations/lib/src/l10n/generated_material_localizations.dart
3744
// and packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart file:
@@ -542,12 +549,17 @@ void main(List<String> rawArgs) {
542549
);
543550

544551
try {
545-
validateLocalizations(materialLocaleToResources, materialLocaleToResourceAttributes);
546-
validateLocalizations(cupertinoLocaleToResources, cupertinoLocaleToResourceAttributes);
552+
validateLocalizations(materialLocaleToResources, materialLocaleToResourceAttributes, removeUndefined: options.removeUndefined);
553+
validateLocalizations(cupertinoLocaleToResources, cupertinoLocaleToResourceAttributes, removeUndefined: options.removeUndefined);
547554
} on ValidationError catch (exception) {
548555
exitWithError('$exception');
549556
}
550557

558+
if (options.removeUndefined) {
559+
removeUndefinedLocalizations(materialLocaleToResources);
560+
removeUndefinedLocalizations(cupertinoLocaleToResources);
561+
}
562+
551563
final String? materialLocalizations = options.writeToFile || !options.cupertinoOnly
552564
? generateArbBasedLocalizationSubclasses(
553565
localeToResources: materialLocaleToResources,

dev/tools/localization/bin/gen_missing_localizations.dart

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,15 @@ import '../localizations_utils.dart';
2727
import '../localizations_validator.dart';
2828

2929
Future<void> main(List<String> rawArgs) async {
30+
bool removeUndefined = false;
31+
if (rawArgs.contains('--remove-undefined')) {
32+
removeUndefined = true;
33+
}
3034
checkCwdIsRepoRoot('gen_missing_localizations');
3135

3236
final String localizationPath = path.join('packages', 'flutter_localizations', 'lib', 'src', 'l10n');
33-
updateMissingResources(localizationPath, 'material');
34-
updateMissingResources(localizationPath, 'cupertino');
37+
updateMissingResources(localizationPath, 'material', removeUndefined: removeUndefined);
38+
updateMissingResources(localizationPath, 'cupertino', removeUndefined: removeUndefined);
3539
}
3640

3741
Map<String, dynamic> loadBundle(File file) {
@@ -73,7 +77,7 @@ bool isPluralVariation(String key, Map<String, dynamic> bundle) {
7377
return bundle.containsKey('${prefix}Other');
7478
}
7579

76-
void updateMissingResources(String localizationPath, String groupPrefix) {
80+
void updateMissingResources(String localizationPath, String groupPrefix, {bool removeUndefined = false}) {
7781
final Directory localizationDir = Directory(localizationPath);
7882
final RegExp filenamePattern = RegExp('${groupPrefix}_(\\w+)\\.arb');
7983

@@ -91,14 +95,52 @@ void updateMissingResources(String localizationPath, String groupPrefix) {
9195
final File arbFile = File(entityPath);
9296
final Map<String, dynamic> localeBundle = loadBundle(arbFile);
9397
final Set<String> localeResources = resourceKeys(localeBundle);
98+
// Whether or not the resources were modified and need to be updated.
99+
bool shouldWrite = false;
100+
101+
// Remove any localizations that are not defined in the canonical
102+
// locale. This allows unused localizations to be removed if
103+
// --remove-undefined is passed.
104+
if (removeUndefined) {
105+
bool isIncluded(String key) {
106+
return !isPluralVariation(key, localeBundle)
107+
&& !intentionallyOmitted(key, localeBundle);
108+
}
109+
110+
// Find any resources in this locale that don't appear in the
111+
// canonical locale, and skipping any which should not be included
112+
// (plurals and intentionally omitted).
113+
final Set<String> extraResources = localeResources
114+
.difference(requiredKeys)
115+
.where(isIncluded)
116+
.toSet();
117+
118+
// Remove them.
119+
localeBundle.removeWhere((String key, dynamic value) {
120+
final bool found = extraResources.contains(key);
121+
if (found) {
122+
shouldWrite = true;
123+
}
124+
return found;
125+
});
126+
if (shouldWrite) {
127+
print('Updating $entityPath by removing extra entries for $extraResources');
128+
}
129+
}
130+
131+
// Add in any resources that are in the canonical locale and not present
132+
// in this locale.
94133
final Set<String> missingResources = requiredKeys.difference(localeResources).where(
95134
(String key) => !isPluralVariation(key, localeBundle) && !intentionallyOmitted(key, localeBundle)
96135
).toSet();
97136
if (missingResources.isNotEmpty) {
98137
localeBundle.addEntries(missingResources.map((String k) =>
99138
MapEntry<String, String>(k, englishBundle[k].toString())));
139+
shouldWrite = true;
140+
print('Updating $entityPath with missing entries for $missingResources');
141+
}
142+
if (shouldWrite) {
100143
writeBundle(arbFile, localeBundle);
101-
print('Updated $entityPath with missing entries for $missingResources');
102144
}
103145
}
104146
}

dev/tools/localization/localizations_utils.dart

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,9 +229,19 @@ void checkCwdIsRepoRoot(String commandName) {
229229

230230
GeneratorOptions parseArgs(List<String> rawArgs) {
231231
final argslib.ArgParser argParser = argslib.ArgParser()
232+
..addFlag(
233+
'help',
234+
abbr: 'h',
235+
help: 'Print the usage message for this command',
236+
)
232237
..addFlag(
233238
'overwrite',
234239
abbr: 'w',
240+
help: 'Overwrite existing localizations',
241+
)
242+
..addFlag(
243+
'remove-undefined',
244+
help: 'Remove any localizations that are not defined in the canonical locale.',
235245
)
236246
..addFlag(
237247
'material',
@@ -242,21 +252,33 @@ GeneratorOptions parseArgs(List<String> rawArgs) {
242252
help: 'Whether to print the generated classes for the Cupertino package only. Ignored when --overwrite is passed.',
243253
);
244254
final argslib.ArgResults args = argParser.parse(rawArgs);
255+
if (args.wasParsed('help') && args['help'] == true) {
256+
stderr.writeln(argParser.usage);
257+
exit(0);
258+
}
245259
final bool writeToFile = args['overwrite'] as bool;
260+
final bool removeUndefined = args['remove-undefined'] as bool;
246261
final bool materialOnly = args['material'] as bool;
247262
final bool cupertinoOnly = args['cupertino'] as bool;
248263

249-
return GeneratorOptions(writeToFile: writeToFile, materialOnly: materialOnly, cupertinoOnly: cupertinoOnly);
264+
return GeneratorOptions(
265+
writeToFile: writeToFile,
266+
materialOnly: materialOnly,
267+
cupertinoOnly: cupertinoOnly,
268+
removeUndefined: removeUndefined,
269+
);
250270
}
251271

252272
class GeneratorOptions {
253273
GeneratorOptions({
254274
required this.writeToFile,
275+
required this.removeUndefined,
255276
required this.materialOnly,
256277
required this.cupertinoOnly,
257278
});
258279

259280
final bool writeToFile;
281+
final bool removeUndefined;
260282
final bool materialOnly;
261283
final bool cupertinoOnly;
262284
}

dev/tools/localization/localizations_validator.dart

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,41 @@ void validateEnglishLocalizations(File file) {
8888
throw ValidationError(errorMessages.toString());
8989
}
9090

91+
/// This removes undefined localizations (localizations that aren't present in
92+
/// the canonical locale anymore) by:
93+
///
94+
/// 1. Looking up the canonical (English, in this case) localizations.
95+
/// 2. For each locale, getting the resources.
96+
/// 3. Determining the set of keys that aren't plural variations (we're only
97+
/// interested in the base terms being translated and not their variants)
98+
/// 4. Determining the set of invalid keys; that is those that are (non-plural)
99+
/// keys in the resources for this locale, but which _aren't_ keys in the
100+
/// canonical list.
101+
/// 5. Removes the invalid mappings from this resource's locale.
102+
void removeUndefinedLocalizations(
103+
Map<LocaleInfo, Map<String, String>> localeToResources,
104+
) {
105+
final Map<String, String> canonicalLocalizations = localeToResources[LocaleInfo.fromString('en')]!;
106+
final Set<String> canonicalKeys = Set<String>.from(canonicalLocalizations.keys);
107+
108+
localeToResources.forEach((LocaleInfo locale, Map<String, String> resources) {
109+
bool isPluralVariation(String key) {
110+
final Match? pluralMatch = kPluralRegexp.firstMatch(key);
111+
if (pluralMatch == null)
112+
return false;
113+
final String? prefix = pluralMatch[1];
114+
return resources.containsKey('${prefix}Other');
115+
}
116+
117+
final Set<String> keys = Set<String>.from(
118+
resources.keys.where((String key) => !isPluralVariation(key))
119+
);
120+
121+
final Set<String> invalidKeys = keys.difference(canonicalKeys);
122+
resources.removeWhere((String key, String value) => invalidKeys.contains(key));
123+
});
124+
}
125+
91126
/// Enforces the following invariants in our localizations:
92127
///
93128
/// - Resource keys are valid, i.e. they appear in the canonical list.
@@ -99,8 +134,9 @@ void validateEnglishLocalizations(File file) {
99134
/// If validation fails, throws an exception.
100135
void validateLocalizations(
101136
Map<LocaleInfo, Map<String, String>> localeToResources,
102-
Map<LocaleInfo, Map<String, dynamic>> localeToAttributes,
103-
) {
137+
Map<LocaleInfo, Map<String, dynamic>> localeToAttributes, {
138+
bool removeUndefined = false,
139+
}) {
104140
final Map<String, String> canonicalLocalizations = localeToResources[LocaleInfo.fromString('en')]!;
105141
final Set<String> canonicalKeys = Set<String>.from(canonicalLocalizations.keys);
106142
final StringBuffer errorMessages = StringBuffer();
@@ -128,8 +164,10 @@ void validateLocalizations(
128164
// Make sure keys are valid (i.e. they also exist in the canonical
129165
// localizations)
130166
final Set<String> invalidKeys = keys.difference(canonicalKeys);
131-
if (invalidKeys.isNotEmpty)
167+
if (invalidKeys.isNotEmpty && !removeUndefined) {
132168
errorMessages.writeln('Locale "$locale" contains invalid resource keys: ${invalidKeys.join(', ')}');
169+
}
170+
133171
// For language-level locales only, check that they have a complete list of
134172
// keys, or opted out of using certain ones.
135173
if (locale.length == 1) {

0 commit comments

Comments
 (0)