Unverified Commit 5c1320e5 authored by Hans Muller's avatar Hans Muller Committed by GitHub

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

parent e023e89b
...@@ -44,7 +44,7 @@ Future<Null> main(List<String> rawArgs) async { ...@@ -44,7 +44,7 @@ Future<Null> main(List<String> rawArgs) async {
final bool dotPackagesExists = dotPackagesFile.existsSync(); final bool dotPackagesExists = dotPackagesFile.existsSync();
if (!dotPackagesExists) { if (!dotPackagesExists) {
fatal( exitWithError(
'File not found: ${dotPackagesFile.path}. $_kCommandName must be run ' 'File not found: ${dotPackagesFile.path}. $_kCommandName must be run '
'after a successful "flutter update-packages".' 'after a successful "flutter update-packages".'
); );
...@@ -56,7 +56,7 @@ Future<Null> main(List<String> rawArgs) async { ...@@ -56,7 +56,7 @@ Future<Null> main(List<String> rawArgs) async {
.firstWhere( .firstWhere(
(String line) => line.startsWith('intl:'), (String line) => line.startsWith('intl:'),
orElse: () { orElse: () {
fatal('intl dependency not found in ${dotPackagesFile.path}'); exitWithError('intl dependency not found in ${dotPackagesFile.path}');
}, },
) )
.split(':') .split(':')
......
...@@ -142,6 +142,10 @@ void main(List<String> rawArgs) { ...@@ -142,6 +142,10 @@ void main(List<String> rawArgs) {
final Directory directory = new Directory(pathlib.join('packages', 'flutter_localizations', 'lib', 'src', 'l10n')); final Directory directory = new Directory(pathlib.join('packages', 'flutter_localizations', 'lib', 'src', 'l10n'));
final RegExp filenameRE = new RegExp(r'material_(\w+)\.arb$'); 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()) { for (FileSystemEntity entity in directory.listSync()) {
final String path = entity.path; final String path = entity.path;
if (FileSystemEntity.isFileSync(path) && filenameRE.hasMatch(path)) { if (FileSystemEntity.isFileSync(path) && filenameRE.hasMatch(path)) {
...@@ -149,7 +153,10 @@ void main(List<String> rawArgs) { ...@@ -149,7 +153,10 @@ void main(List<String> rawArgs) {
processBundle(new File(path), locale); processBundle(new File(path), locale);
} }
} }
validateLocalizations(localeToResources, localeToResourceAttributes);
exitWithError(
validateLocalizations(localeToResources, localeToResourceAttributes)
);
final String regenerate = 'dart dev/tools/gen_localizations.dart --overwrite'; final String regenerate = 'dart dev/tools/gen_localizations.dart --overwrite';
final StringBuffer buffer = new StringBuffer(); final StringBuffer buffer = new StringBuffer();
......
...@@ -7,8 +7,10 @@ import 'dart:io'; ...@@ -7,8 +7,10 @@ import 'dart:io';
import 'package:args/args.dart' as argslib; import 'package:args/args.dart' as argslib;
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
void fatal(String message) { void exitWithError(String errorMessage) {
stderr.writeln(message); if (errorMessage == null)
return;
stderr.writeln('Fatal Error: $errorMessage');
exit(1); exit(1);
} }
...@@ -16,7 +18,7 @@ void checkCwdIsRepoRoot(String commandName) { ...@@ -16,7 +18,7 @@ void checkCwdIsRepoRoot(String commandName) {
final bool isRepoRoot = new Directory('.git').existsSync(); final bool isRepoRoot = new Directory('.git').existsSync();
if (!isRepoRoot) { if (!isRepoRoot) {
fatal( exitWithError(
'$commandName must be run from the root of the Flutter repository. The ' '$commandName must be run from the root of the Flutter repository. The '
'current working directory is: ${Directory.current.path}' 'current working directory is: ${Directory.current.path}'
); );
...@@ -32,7 +34,7 @@ GeneratorOptions parseArgs(List<String> rawArgs) { ...@@ -32,7 +34,7 @@ GeneratorOptions parseArgs(List<String> rawArgs) {
); );
final argslib.ArgResults args = argParser.parse(rawArgs); final argslib.ArgResults args = argParser.parse(rawArgs);
final bool writeToFile = args['overwrite']; final bool writeToFile = args['overwrite'];
return new GeneratorOptions(writeToFile: writeToFile); return new GeneratorOptions(writeToFile: writeToFile);
} }
......
...@@ -2,19 +2,67 @@ ...@@ -2,19 +2,67 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:convert' show JSON;
import 'dart:io'; 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: /// Enforces the following invariants in our localizations:
/// ///
/// - Resource keys are valid, i.e. they appear in the canonical list. /// - Resource keys are valid, i.e. they appear in the canonical list.
/// - Resource keys are complete for language-level locales, e.g. "es", "he". /// - Resource keys are complete for language-level locales, e.g. "es", "he".
/// ///
/// Uses "en" localizations as the canonical source of locale keys that other /// Uses "en" localizations as the canonical source of locale keys that other
/// locales are compared against. /// locales are compared against.
/// ///
/// If validation fails, print an error message to STDERR and quit with exit /// If validation fails, return an error message, otherwise return null.
/// code 1. String validateLocalizations(
void validateLocalizations(
Map<String, Map<String, String>> localeToResources, Map<String, Map<String, String>> localeToResources,
Map<String, Map<String, dynamic>> localeToAttributes, Map<String, Map<String, dynamic>> localeToAttributes,
) { ) {
...@@ -33,7 +81,7 @@ void validateLocalizations( ...@@ -33,7 +81,7 @@ void validateLocalizations(
bool isPluralVariation(String key) { bool isPluralVariation(String key) {
final RegExp pluralRegexp = new RegExp(r'(\w*)(Zero|One|Two|Few|Many)$'); final RegExp pluralRegexp = new RegExp(r'(\w*)(Zero|One|Two|Few|Many)$');
final Match pluralMatch = pluralRegexp.firstMatch(key); final Match pluralMatch = pluralRegexp.firstMatch(key);
if (pluralMatch == null) if (pluralMatch == null)
return false; return false;
...@@ -83,9 +131,7 @@ void validateLocalizations( ...@@ -83,9 +131,7 @@ void validateLocalizations(
..writeln(' "notUsed": "Sindhi time format does not use a.m. indicator"') ..writeln(' "notUsed": "Sindhi time format does not use a.m. indicator"')
..writeln('}'); ..writeln('}');
} }
return errorMessages.toString();
stderr.writeln('ERROR:');
stderr.writeln(errorMessages);
exit(1);
} }
return null;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment