Validate the @foo resources in material_en.arb (#12824)

This commit is contained in:
Hans Muller 2017-11-01 16:14:10 -07:00 committed by GitHub
parent e023e89b8e
commit 5c1320e5b9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 18 deletions

View file

@ -44,7 +44,7 @@ Future<Null> main(List<String> rawArgs) async {
final bool dotPackagesExists = dotPackagesFile.existsSync();
if (!dotPackagesExists) {
fatal(
exitWithError(
'File not found: ${dotPackagesFile.path}. $_kCommandName must be run '
'after a successful "flutter update-packages".'
);
@ -56,7 +56,7 @@ Future<Null> main(List<String> rawArgs) async {
.firstWhere(
(String line) => line.startsWith('intl:'),
orElse: () {
fatal('intl dependency not found in ${dotPackagesFile.path}');
exitWithError('intl dependency not found in ${dotPackagesFile.path}');
},
)
.split(':')

View file

@ -142,6 +142,10 @@ void main(List<String> rawArgs) {
final Directory directory = new Directory(pathlib.join('packages', 'flutter_localizations', 'lib', 'src', 'l10n'));
final RegExp filenameRE = new RegExp(r'material_(\w+)\.arb$');
exitWithError(
validateEnglishLocalizations(new File(pathlib.join(directory.path, 'material_en.arb')))
);
for (FileSystemEntity entity in directory.listSync()) {
final String path = entity.path;
if (FileSystemEntity.isFileSync(path) && filenameRE.hasMatch(path)) {
@ -149,7 +153,10 @@ void main(List<String> rawArgs) {
processBundle(new File(path), locale);
}
}
validateLocalizations(localeToResources, localeToResourceAttributes);
exitWithError(
validateLocalizations(localeToResources, localeToResourceAttributes)
);
final String regenerate = 'dart dev/tools/gen_localizations.dart --overwrite';
final StringBuffer buffer = new StringBuffer();

View file

@ -7,8 +7,10 @@ import 'dart:io';
import 'package:args/args.dart' as argslib;
import 'package:meta/meta.dart';
void fatal(String message) {
stderr.writeln(message);
void exitWithError(String errorMessage) {
if (errorMessage == null)
return;
stderr.writeln('Fatal Error: $errorMessage');
exit(1);
}
@ -16,7 +18,7 @@ void checkCwdIsRepoRoot(String commandName) {
final bool isRepoRoot = new Directory('.git').existsSync();
if (!isRepoRoot) {
fatal(
exitWithError(
'$commandName must be run from the root of the Flutter repository. The '
'current working directory is: ${Directory.current.path}'
);
@ -32,7 +34,7 @@ GeneratorOptions parseArgs(List<String> rawArgs) {
);
final argslib.ArgResults args = argParser.parse(rawArgs);
final bool writeToFile = args['overwrite'];
return new GeneratorOptions(writeToFile: writeToFile);
}

View file

@ -2,19 +2,67 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:convert' show JSON;
import 'dart:io';
/// Sanity checking of the @foo metadata in the English translations,
/// material_en.arb.
///
/// - For each @foo resource, there must be a corresponding foo, except
/// for plurals, for which there must be a fooOther.
/// - Each @foo resource must have a Map value with a String valued
/// description entry.
///
/// Returns an error message upon failure, null on success.
String validateEnglishLocalizations(File file) {
final StringBuffer errorMessages = new StringBuffer();
if (!file.existsSync()) {
errorMessages.writeln('English localizations do not exist: $file');
return errorMessages.toString();
}
final Map<String, dynamic> bundle = JSON.decode(file.readAsStringSync());
for (String atResourceId in bundle.keys) {
if (!atResourceId.startsWith('@'))
continue;
final dynamic atResourceValue = bundle[atResourceId];
final Map<String, String> atResource = atResourceValue is Map ? atResourceValue : null;
if (atResource == null) {
errorMessages.writeln('A map value was not specified for $atResourceId');
continue;
}
final String description = atResource['description'];
if (description == null)
errorMessages.writeln('No description specified for $atResourceId');
final String plural = atResource['plural'];
final String resourceId = atResourceId.substring(1);
if (plural != null) {
final String resourceIdOther = '${resourceId}Other';
if (!bundle.containsKey(resourceIdOther))
errorMessages.writeln('Default plural resource $resourceIdOther undefined');
} else {
if (!bundle.containsKey(resourceId))
errorMessages.writeln('No matching $resourceId defined for $atResourceId');
}
}
return errorMessages.isEmpty ? null : errorMessages.toString();
}
/// Enforces the following invariants in our localizations:
///
///
/// - Resource keys are valid, i.e. they appear in the canonical list.
/// - Resource keys are complete for language-level locales, e.g. "es", "he".
///
///
/// Uses "en" localizations as the canonical source of locale keys that other
/// locales are compared against.
///
/// If validation fails, print an error message to STDERR and quit with exit
/// code 1.
void validateLocalizations(
///
/// If validation fails, return an error message, otherwise return null.
String validateLocalizations(
Map<String, Map<String, String>> localeToResources,
Map<String, Map<String, dynamic>> localeToAttributes,
) {
@ -33,7 +81,7 @@ void validateLocalizations(
bool isPluralVariation(String key) {
final RegExp pluralRegexp = new RegExp(r'(\w*)(Zero|One|Two|Few|Many)$');
final Match pluralMatch = pluralRegexp.firstMatch(key);
if (pluralMatch == null)
return false;
@ -83,9 +131,7 @@ void validateLocalizations(
..writeln(' "notUsed": "Sindhi time format does not use a.m. indicator"')
..writeln('}');
}
stderr.writeln('ERROR:');
stderr.writeln(errorMessages);
exit(1);
return errorMessages.toString();
}
return null;
}