mirror of
https://github.com/flutter/flutter
synced 2024-10-13 03:32:55 +00:00
Migrate gen_l10n to null safety (#80763)
This commit is contained in:
parent
4cceeaa075
commit
728a193383
|
@ -2,8 +2,6 @@
|
||||||
// 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.
|
||||||
|
|
||||||
// @dart = 2.8
|
|
||||||
|
|
||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
import '../base/common.dart';
|
import '../base/common.dart';
|
||||||
|
@ -18,20 +16,20 @@ import 'localizations_utils.dart';
|
||||||
|
|
||||||
/// Run the localizations generation script with the configuration [options].
|
/// Run the localizations generation script with the configuration [options].
|
||||||
LocalizationsGenerator generateLocalizations({
|
LocalizationsGenerator generateLocalizations({
|
||||||
@required Directory projectDir,
|
required Directory projectDir,
|
||||||
@required Directory dependenciesDir,
|
Directory? dependenciesDir,
|
||||||
@required LocalizationOptions options,
|
required LocalizationOptions options,
|
||||||
@required Logger logger,
|
required Logger logger,
|
||||||
@required FileSystem fileSystem,
|
required FileSystem fileSystem,
|
||||||
}) {
|
}) {
|
||||||
// If generating a synthetic package, generate a warning if
|
// If generating a synthetic package, generate a warning if
|
||||||
// flutter: generate is not set.
|
// flutter: generate is not set.
|
||||||
final FlutterManifest flutterManifest = FlutterManifest.createFromPath(
|
final FlutterManifest? flutterManifest = FlutterManifest.createFromPath(
|
||||||
projectDir.childFile('pubspec.yaml').path,
|
projectDir.childFile('pubspec.yaml').path,
|
||||||
fileSystem: projectDir.fileSystem,
|
fileSystem: projectDir.fileSystem,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
);
|
);
|
||||||
if (options.useSyntheticPackage && !flutterManifest.generateSyntheticPackage) {
|
if (options.useSyntheticPackage && (flutterManifest == null || !flutterManifest.generateSyntheticPackage)) {
|
||||||
throwToolExit(
|
throwToolExit(
|
||||||
'Attempted to generate localizations code without having '
|
'Attempted to generate localizations code without having '
|
||||||
'the flutter: generate flag turned on.'
|
'the flutter: generate flag turned on.'
|
||||||
|
@ -44,9 +42,9 @@ LocalizationsGenerator generateLocalizations({
|
||||||
|
|
||||||
precacheLanguageAndRegionTags();
|
precacheLanguageAndRegionTags();
|
||||||
|
|
||||||
final String inputPathString = options?.arbDirectory?.path ?? fileSystem.path.join('lib', 'l10n');
|
final String inputPathString = options.arbDirectory?.path ?? fileSystem.path.join('lib', 'l10n');
|
||||||
final String templateArbFileName = options?.templateArbFile?.toFilePath() ?? 'app_en.arb';
|
final String templateArbFileName = options.templateArbFile?.toFilePath() ?? 'app_en.arb';
|
||||||
final String outputFileString = options?.outputLocalizationsFile?.toFilePath() ?? 'app_localizations.dart';
|
final String outputFileString = options.outputLocalizationsFile?.toFilePath() ?? 'app_localizations.dart';
|
||||||
LocalizationsGenerator generator;
|
LocalizationsGenerator generator;
|
||||||
try {
|
try {
|
||||||
generator = LocalizationsGenerator(
|
generator = LocalizationsGenerator(
|
||||||
|
@ -56,16 +54,16 @@ LocalizationsGenerator generateLocalizations({
|
||||||
inputPathString: inputPathString,
|
inputPathString: inputPathString,
|
||||||
templateArbFileName: templateArbFileName,
|
templateArbFileName: templateArbFileName,
|
||||||
outputFileString: outputFileString,
|
outputFileString: outputFileString,
|
||||||
outputPathString: options?.outputDirectory?.path,
|
outputPathString: options.outputDirectory?.path,
|
||||||
classNameString: options.outputClass ?? 'AppLocalizations',
|
classNameString: options.outputClass ?? 'AppLocalizations',
|
||||||
preferredSupportedLocales: options.preferredSupportedLocales,
|
preferredSupportedLocales: options.preferredSupportedLocales,
|
||||||
headerString: options.header,
|
headerString: options.header,
|
||||||
headerFile: options?.headerFile?.toFilePath(),
|
headerFile: options.headerFile?.toFilePath(),
|
||||||
useDeferredLoading: options.deferredLoading ?? false,
|
useDeferredLoading: options.deferredLoading ?? false,
|
||||||
useSyntheticPackage: options.useSyntheticPackage ?? true,
|
useSyntheticPackage: options.useSyntheticPackage,
|
||||||
areResourceAttributesRequired: options.areResourceAttributesRequired ?? false,
|
areResourceAttributesRequired: options.areResourceAttributesRequired,
|
||||||
untranslatedMessagesFile: options?.untranslatedMessagesFile?.toFilePath(),
|
untranslatedMessagesFile: options.untranslatedMessagesFile?.toFilePath(),
|
||||||
usesNullableGetter: options?.usesNullableGetter ?? true,
|
usesNullableGetter: options.usesNullableGetter,
|
||||||
)
|
)
|
||||||
..loadResources()
|
..loadResources()
|
||||||
..writeOutputFiles(logger, isFromYaml: true);
|
..writeOutputFiles(logger, isFromYaml: true);
|
||||||
|
@ -87,9 +85,9 @@ String _syntheticL10nPackagePath(FileSystem fileSystem) => fileSystem.path.join(
|
||||||
|
|
||||||
List<String> generateMethodParameters(Message message) {
|
List<String> generateMethodParameters(Message message) {
|
||||||
assert(message.placeholders.isNotEmpty);
|
assert(message.placeholders.isNotEmpty);
|
||||||
final Placeholder countPlaceholder = message.isPlural ? message.getCountPlaceholder() : null;
|
final Placeholder? countPlaceholder = message.isPlural ? message.getCountPlaceholder() : null;
|
||||||
return message.placeholders.map((Placeholder placeholder) {
|
return message.placeholders.map((Placeholder placeholder) {
|
||||||
final String type = placeholder == countPlaceholder ? 'int' : placeholder.type;
|
final String? type = placeholder == countPlaceholder ? 'int' : placeholder.type;
|
||||||
return '$type ${placeholder.name}';
|
return '$type ${placeholder.name}';
|
||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
||||||
|
@ -102,7 +100,8 @@ String generateDateFormattingLogic(Message message) {
|
||||||
final Iterable<String> formatStatements = message.placeholders
|
final Iterable<String> formatStatements = message.placeholders
|
||||||
.where((Placeholder placeholder) => placeholder.isDate)
|
.where((Placeholder placeholder) => placeholder.isDate)
|
||||||
.map((Placeholder placeholder) {
|
.map((Placeholder placeholder) {
|
||||||
if (placeholder.format == null) {
|
final String? placeholderFormat = placeholder.format;
|
||||||
|
if (placeholderFormat == null) {
|
||||||
throw L10nException(
|
throw L10nException(
|
||||||
'The placeholder, ${placeholder.name}, has its "type" resource attribute set to '
|
'The placeholder, ${placeholder.name}, has its "type" resource attribute set to '
|
||||||
'the "${placeholder.type}" type. To properly resolve for the right '
|
'the "${placeholder.type}" type. To properly resolve for the right '
|
||||||
|
@ -114,7 +113,7 @@ String generateDateFormattingLogic(Message message) {
|
||||||
}
|
}
|
||||||
if (!placeholder.hasValidDateFormat) {
|
if (!placeholder.hasValidDateFormat) {
|
||||||
throw L10nException(
|
throw L10nException(
|
||||||
'Date format "${placeholder.format}" for placeholder '
|
'Date format "$placeholderFormat" for placeholder '
|
||||||
'${placeholder.name} does not have a corresponding DateFormat '
|
'${placeholder.name} does not have a corresponding DateFormat '
|
||||||
'constructor\n. Check the intl library\'s DateFormat class '
|
'constructor\n. Check the intl library\'s DateFormat class '
|
||||||
'constructors for allowed date formats.'
|
'constructors for allowed date formats.'
|
||||||
|
@ -122,7 +121,7 @@ String generateDateFormattingLogic(Message message) {
|
||||||
}
|
}
|
||||||
return dateFormatTemplate
|
return dateFormatTemplate
|
||||||
.replaceAll('@(placeholder)', placeholder.name)
|
.replaceAll('@(placeholder)', placeholder.name)
|
||||||
.replaceAll('@(format)', placeholder.format);
|
.replaceAll('@(format)', placeholderFormat);
|
||||||
});
|
});
|
||||||
|
|
||||||
return formatStatements.isEmpty ? '@(none)' : formatStatements.join('');
|
return formatStatements.isEmpty ? '@(none)' : formatStatements.join('');
|
||||||
|
@ -136,9 +135,10 @@ String generateNumberFormattingLogic(Message message) {
|
||||||
final Iterable<String> formatStatements = message.placeholders
|
final Iterable<String> formatStatements = message.placeholders
|
||||||
.where((Placeholder placeholder) => placeholder.isNumber)
|
.where((Placeholder placeholder) => placeholder.isNumber)
|
||||||
.map((Placeholder placeholder) {
|
.map((Placeholder placeholder) {
|
||||||
if (!placeholder.hasValidNumberFormat) {
|
final String? placeholderFormat = placeholder.format;
|
||||||
|
if (!placeholder.hasValidNumberFormat || placeholderFormat == null) {
|
||||||
throw L10nException(
|
throw L10nException(
|
||||||
'Number format ${placeholder.format} for the ${placeholder.name} '
|
'Number format $placeholderFormat for the ${placeholder.name} '
|
||||||
'placeholder does not have a corresponding NumberFormat constructor.\n'
|
'placeholder does not have a corresponding NumberFormat constructor.\n'
|
||||||
'Check the intl library\'s NumberFormat class constructors for allowed '
|
'Check the intl library\'s NumberFormat class constructors for allowed '
|
||||||
'number formats.'
|
'number formats.'
|
||||||
|
@ -157,19 +157,19 @@ String generateNumberFormattingLogic(Message message) {
|
||||||
if (placeholder.hasNumberFormatWithParameters) {
|
if (placeholder.hasNumberFormatWithParameters) {
|
||||||
return numberFormatNamedTemplate
|
return numberFormatNamedTemplate
|
||||||
.replaceAll('@(placeholder)', placeholder.name)
|
.replaceAll('@(placeholder)', placeholder.name)
|
||||||
.replaceAll('@(format)', placeholder.format)
|
.replaceAll('@(format)', placeholderFormat)
|
||||||
.replaceAll('@(parameters)', parameters.join(',\n '));
|
.replaceAll('@(parameters)', parameters.join(',\n '));
|
||||||
} else {
|
} else {
|
||||||
return numberFormatPositionalTemplate
|
return numberFormatPositionalTemplate
|
||||||
.replaceAll('@(placeholder)', placeholder.name)
|
.replaceAll('@(placeholder)', placeholder.name)
|
||||||
.replaceAll('@(format)', placeholder.format);
|
.replaceAll('@(format)', placeholderFormat);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return formatStatements.isEmpty ? '@(none)' : formatStatements.join('');
|
return formatStatements.isEmpty ? '@(none)' : formatStatements.join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
String generatePluralMethod(Message message, AppResourceBundle bundle) {
|
String _generatePluralMethod(Message message, String translationForMessage) {
|
||||||
if (message.placeholders.isEmpty) {
|
if (message.placeholders.isEmpty) {
|
||||||
throw L10nException(
|
throw L10nException(
|
||||||
'Unable to find placeholders for the plural message: ${message.resourceId}.\n'
|
'Unable to find placeholders for the plural message: ${message.resourceId}.\n'
|
||||||
|
@ -180,20 +180,12 @@ String generatePluralMethod(Message message, AppResourceBundle bundle) {
|
||||||
|
|
||||||
// To make it easier to parse the plurals message, temporarily replace each
|
// To make it easier to parse the plurals message, temporarily replace each
|
||||||
// "{placeholder}" parameter with "#placeholder#".
|
// "{placeholder}" parameter with "#placeholder#".
|
||||||
String easyMessage = bundle.translationFor(message);
|
String easyMessage = translationForMessage;
|
||||||
for (final Placeholder placeholder in message.placeholders) {
|
for (final Placeholder placeholder in message.placeholders) {
|
||||||
easyMessage = easyMessage.replaceAll('{${placeholder.name}}', '#${placeholder.name}#');
|
easyMessage = easyMessage.replaceAll('{${placeholder.name}}', '#${placeholder.name}#');
|
||||||
}
|
}
|
||||||
|
|
||||||
final Placeholder countPlaceholder = message.getCountPlaceholder();
|
final Placeholder countPlaceholder = message.getCountPlaceholder();
|
||||||
if (countPlaceholder == null) {
|
|
||||||
throw L10nException(
|
|
||||||
'Unable to find the count placeholder for the plural message: ${message.resourceId}.\n'
|
|
||||||
'Check to see if the plural message is in the proper ICU syntax format '
|
|
||||||
'and ensure that placeholders are properly specified.'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Map<String, String> pluralIds = <String, String>{
|
const Map<String, String> pluralIds = <String, String>{
|
||||||
'=0': 'zero',
|
'=0': 'zero',
|
||||||
'=1': 'one',
|
'=1': 'one',
|
||||||
|
@ -206,9 +198,9 @@ String generatePluralMethod(Message message, AppResourceBundle bundle) {
|
||||||
final List<String> pluralLogicArgs = <String>[];
|
final List<String> pluralLogicArgs = <String>[];
|
||||||
for (final String pluralKey in pluralIds.keys) {
|
for (final String pluralKey in pluralIds.keys) {
|
||||||
final RegExp expRE = RegExp('($pluralKey)\\s*{([^}]+)}');
|
final RegExp expRE = RegExp('($pluralKey)\\s*{([^}]+)}');
|
||||||
final RegExpMatch match = expRE.firstMatch(easyMessage);
|
final RegExpMatch? match = expRE.firstMatch(easyMessage);
|
||||||
if (match != null && match.groupCount == 2) {
|
if (match != null && match.groupCount == 2) {
|
||||||
String argValue = generateString(match.group(2));
|
String argValue = generateString(match.group(2)!);
|
||||||
for (final Placeholder placeholder in message.placeholders) {
|
for (final Placeholder placeholder in message.placeholders) {
|
||||||
if (placeholder != countPlaceholder && placeholder.requiresFormatting) {
|
if (placeholder != countPlaceholder && placeholder.requiresFormatting) {
|
||||||
argValue = argValue.replaceAll(
|
argValue = argValue.replaceAll(
|
||||||
|
@ -231,7 +223,7 @@ String generatePluralMethod(Message message, AppResourceBundle bundle) {
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<String> parameters = message.placeholders.map((Placeholder placeholder) {
|
final List<String> parameters = message.placeholders.map((Placeholder placeholder) {
|
||||||
final String placeholderType = placeholder == countPlaceholder ? 'int' : placeholder.type;
|
final String? placeholderType = placeholder == countPlaceholder ? 'int' : placeholder.type;
|
||||||
return '$placeholderType ${placeholder.name}';
|
return '$placeholderType ${placeholder.name}';
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
|
@ -285,9 +277,9 @@ bool _needsCurlyBracketStringInterpolation(String messageString, String placehol
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String generateMethod(Message message, AppResourceBundle bundle) {
|
String _generateMethod(Message message, String translationForMessage) {
|
||||||
String generateMessage() {
|
String generateMessage() {
|
||||||
String messageValue = generateString(bundle.translationFor(message));
|
String messageValue = generateString(translationForMessage);
|
||||||
for (final Placeholder placeholder in message.placeholders) {
|
for (final Placeholder placeholder in message.placeholders) {
|
||||||
if (placeholder.requiresFormatting) {
|
if (placeholder.requiresFormatting) {
|
||||||
messageValue = messageValue.replaceAll(
|
messageValue = messageValue.replaceAll(
|
||||||
|
@ -310,7 +302,7 @@ String generateMethod(Message message, AppResourceBundle bundle) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.isPlural) {
|
if (message.isPlural) {
|
||||||
return generatePluralMethod(message, bundle);
|
return _generatePluralMethod(message, translationForMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.placeholdersRequireFormatting) {
|
if (message.placeholdersRequireFormatting) {
|
||||||
|
@ -335,7 +327,7 @@ String generateMethod(Message message, AppResourceBundle bundle) {
|
||||||
.replaceAll('@(message)', generateMessage());
|
.replaceAll('@(message)', generateMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
String generateBaseClassMethod(Message message, LocaleInfo templateArbLocale) {
|
String generateBaseClassMethod(Message message, LocaleInfo? templateArbLocale) {
|
||||||
final String comment = message.description ?? 'No description provided for @${message.resourceId}.';
|
final String comment = message.description ?? 'No description provided for @${message.resourceId}.';
|
||||||
final String templateLocaleTranslationComment = '''
|
final String templateLocaleTranslationComment = '''
|
||||||
/// In $templateArbLocale, this message translates to:
|
/// In $templateArbLocale, this message translates to:
|
||||||
|
@ -396,9 +388,9 @@ String _generateLookupByScriptCode(
|
||||||
.replaceAll('@(code)', 'scriptCode')
|
.replaceAll('@(code)', 'scriptCode')
|
||||||
.replaceAll('@(switchClauses)', localesWithScriptCodes.map((LocaleInfo locale) {
|
.replaceAll('@(switchClauses)', localesWithScriptCodes.map((LocaleInfo locale) {
|
||||||
return generateSwitchClauseTemplate(locale)
|
return generateSwitchClauseTemplate(locale)
|
||||||
.replaceAll('@(case)', locale.scriptCode);
|
.replaceAll('@(case)', locale.scriptCode!);
|
||||||
}).join('\n '));
|
}).join('\n '));
|
||||||
}).where((String switchClause) => switchClause != null);
|
}).whereType<String>();
|
||||||
|
|
||||||
if (switchClauses.isEmpty) {
|
if (switchClauses.isEmpty) {
|
||||||
return '';
|
return '';
|
||||||
|
@ -429,9 +421,9 @@ String _generateLookupByCountryCode(
|
||||||
.replaceAll('@(code)', 'countryCode')
|
.replaceAll('@(code)', 'countryCode')
|
||||||
.replaceAll('@(switchClauses)', localesWithCountryCodes.map((LocaleInfo locale) {
|
.replaceAll('@(switchClauses)', localesWithCountryCodes.map((LocaleInfo locale) {
|
||||||
return generateSwitchClauseTemplate(locale)
|
return generateSwitchClauseTemplate(locale)
|
||||||
.replaceAll('@(case)', locale.countryCode);
|
.replaceAll('@(case)', locale.countryCode!);
|
||||||
}).join('\n '));
|
}).join('\n '));
|
||||||
}).where((String switchClause) => switchClause != null);
|
}).whereType<String>();
|
||||||
|
|
||||||
if (switchClauses.isEmpty) {
|
if (switchClauses.isEmpty) {
|
||||||
return '';
|
return '';
|
||||||
|
@ -460,7 +452,7 @@ String _generateLookupByLanguageCode(
|
||||||
return generateSwitchClauseTemplate(locale)
|
return generateSwitchClauseTemplate(locale)
|
||||||
.replaceAll('@(case)', locale.languageCode);
|
.replaceAll('@(case)', locale.languageCode);
|
||||||
}).join('\n ');
|
}).join('\n ');
|
||||||
}).where((String switchClause) => switchClause != null);
|
}).whereType<String>();
|
||||||
|
|
||||||
if (switchClauses.isEmpty) {
|
if (switchClauses.isEmpty) {
|
||||||
return '';
|
return '';
|
||||||
|
@ -504,11 +496,11 @@ String _generateLookupBody(
|
||||||
}
|
}
|
||||||
|
|
||||||
String _generateDelegateClass({
|
String _generateDelegateClass({
|
||||||
AppResourceBundleCollection allBundles,
|
required AppResourceBundleCollection allBundles,
|
||||||
String className,
|
required String className,
|
||||||
Set<String> supportedLanguageCodes,
|
required Set<String> supportedLanguageCodes,
|
||||||
bool useDeferredLoading,
|
required bool useDeferredLoading,
|
||||||
String fileName,
|
required String fileName,
|
||||||
}) {
|
}) {
|
||||||
|
|
||||||
final String lookupBody = _generateLookupBody(
|
final String lookupBody = _generateLookupBody(
|
||||||
|
@ -544,24 +536,24 @@ class LocalizationsGenerator {
|
||||||
/// Throws a [FileSystemException] when a file operation necessary for setting
|
/// Throws a [FileSystemException] when a file operation necessary for setting
|
||||||
/// up the [LocalizationsGenerator] cannot be completed.
|
/// up the [LocalizationsGenerator] cannot be completed.
|
||||||
factory LocalizationsGenerator({
|
factory LocalizationsGenerator({
|
||||||
@required FileSystem fileSystem,
|
required FileSystem fileSystem,
|
||||||
@required String inputPathString,
|
required String inputPathString,
|
||||||
String outputPathString,
|
String? outputPathString,
|
||||||
@required String templateArbFileName,
|
required String templateArbFileName,
|
||||||
String outputFileString,
|
required String outputFileString,
|
||||||
@required String classNameString,
|
required String classNameString,
|
||||||
List<String> preferredSupportedLocales,
|
List<String>? preferredSupportedLocales,
|
||||||
String headerString,
|
String? headerString,
|
||||||
String headerFile,
|
String? headerFile,
|
||||||
bool useDeferredLoading = false,
|
bool useDeferredLoading = false,
|
||||||
String inputsAndOutputsListPath,
|
String? inputsAndOutputsListPath,
|
||||||
bool useSyntheticPackage = true,
|
bool useSyntheticPackage = true,
|
||||||
String projectPathString,
|
String? projectPathString,
|
||||||
bool areResourceAttributesRequired = false,
|
bool areResourceAttributesRequired = false,
|
||||||
String untranslatedMessagesFile,
|
String? untranslatedMessagesFile,
|
||||||
bool usesNullableGetter = true,
|
bool usesNullableGetter = true,
|
||||||
}) {
|
}) {
|
||||||
final Directory projectDirectory = projectDirFromPath(fileSystem, projectPathString);
|
final Directory? projectDirectory = projectDirFromPath(fileSystem, projectPathString);
|
||||||
final Directory inputDirectory = inputDirectoryFromPath(fileSystem, inputPathString, projectDirectory);
|
final Directory inputDirectory = inputDirectoryFromPath(fileSystem, inputPathString, projectDirectory);
|
||||||
final Directory outputDirectory = outputDirectoryFromPath(fileSystem, outputPathString ?? inputPathString, useSyntheticPackage, projectDirectory);
|
final Directory outputDirectory = outputDirectoryFromPath(fileSystem, outputPathString ?? inputPathString, useSyntheticPackage, projectDirectory);
|
||||||
return LocalizationsGenerator._(
|
return LocalizationsGenerator._(
|
||||||
|
@ -576,7 +568,7 @@ class LocalizationsGenerator {
|
||||||
baseOutputFile: outputDirectory.childFile(outputFileString),
|
baseOutputFile: outputDirectory.childFile(outputFileString),
|
||||||
preferredSupportedLocales: preferredSupportedLocalesFromLocales(preferredSupportedLocales),
|
preferredSupportedLocales: preferredSupportedLocalesFromLocales(preferredSupportedLocales),
|
||||||
header: headerFromFile(headerString, headerFile, inputDirectory),
|
header: headerFromFile(headerString, headerFile, inputDirectory),
|
||||||
useDeferredLoading: useDeferredLoading ?? false,
|
useDeferredLoading: useDeferredLoading,
|
||||||
untranslatedMessagesFile: _untranslatedMessagesFileFromPath(fileSystem, untranslatedMessagesFile),
|
untranslatedMessagesFile: _untranslatedMessagesFileFromPath(fileSystem, untranslatedMessagesFile),
|
||||||
inputsAndOutputsListFile: _inputsAndOutputsListFileFromPath(fileSystem, inputsAndOutputsListPath),
|
inputsAndOutputsListFile: _inputsAndOutputsListFileFromPath(fileSystem, inputsAndOutputsListPath),
|
||||||
areResourceAttributesRequired: areResourceAttributesRequired,
|
areResourceAttributesRequired: areResourceAttributesRequired,
|
||||||
|
@ -586,17 +578,16 @@ class LocalizationsGenerator {
|
||||||
/// Creates an instance of the localizations generator class.
|
/// Creates an instance of the localizations generator class.
|
||||||
///
|
///
|
||||||
/// It takes in a [FileSystem] representation that the class will act upon.
|
/// It takes in a [FileSystem] representation that the class will act upon.
|
||||||
LocalizationsGenerator._(
|
LocalizationsGenerator._(this._fs, {
|
||||||
this._fs, {
|
required this.inputDirectory,
|
||||||
this.inputDirectory,
|
required this.outputDirectory,
|
||||||
@required this.outputDirectory,
|
required this.templateArbFile,
|
||||||
@required this.templateArbFile,
|
required this.baseOutputFile,
|
||||||
@required this.baseOutputFile,
|
required this.className,
|
||||||
@required this.className,
|
|
||||||
this.preferredSupportedLocales = const <LocaleInfo>[],
|
this.preferredSupportedLocales = const <LocaleInfo>[],
|
||||||
this.header = '',
|
this.header = '',
|
||||||
this.useDeferredLoading = false,
|
this.useDeferredLoading = false,
|
||||||
this.inputsAndOutputsListFile,
|
required this.inputsAndOutputsListFile,
|
||||||
this.useSyntheticPackage = true,
|
this.useSyntheticPackage = true,
|
||||||
this.projectDirectory,
|
this.projectDirectory,
|
||||||
this.areResourceAttributesRequired = false,
|
this.areResourceAttributesRequired = false,
|
||||||
|
@ -605,9 +596,11 @@ class LocalizationsGenerator {
|
||||||
});
|
});
|
||||||
|
|
||||||
final FileSystem _fs;
|
final FileSystem _fs;
|
||||||
Iterable<Message> _allMessages;
|
Iterable<Message> _allMessages = <Message>[];
|
||||||
AppResourceBundleCollection _allBundles;
|
late final AppResourceBundleCollection _allBundles = AppResourceBundleCollection(inputDirectory);
|
||||||
LocaleInfo _templateArbLocale;
|
|
||||||
|
late final AppResourceBundle _templateBundle = AppResourceBundle(templateArbFile);
|
||||||
|
late final LocaleInfo _templateArbLocale = _templateBundle.locale;
|
||||||
|
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
final bool useSyntheticPackage;
|
final bool useSyntheticPackage;
|
||||||
|
@ -623,44 +616,32 @@ class LocalizationsGenerator {
|
||||||
///
|
///
|
||||||
/// It is assumed that all input files (e.g. [templateArbFile], arb files
|
/// It is assumed that all input files (e.g. [templateArbFile], arb files
|
||||||
/// for translated messages, header file templates) will reside here.
|
/// for translated messages, header file templates) will reside here.
|
||||||
///
|
|
||||||
/// This directory is specified with the [initialize] method.
|
|
||||||
final Directory inputDirectory;
|
final Directory inputDirectory;
|
||||||
|
|
||||||
/// The Flutter project's root directory.
|
/// The Flutter project's root directory.
|
||||||
///
|
final Directory? projectDirectory;
|
||||||
/// This directory is specified with the [initialize] method.
|
|
||||||
final Directory projectDirectory;
|
|
||||||
|
|
||||||
/// The directory to generate the project's localizations files in.
|
/// The directory to generate the project's localizations files in.
|
||||||
///
|
///
|
||||||
/// It is assumed that all output files (e.g. The localizations
|
/// It is assumed that all output files (e.g. The localizations
|
||||||
/// [outputFile], `messages_<locale>.dart` and `messages_all.dart`)
|
/// [outputFile], `messages_<locale>.dart` and `messages_all.dart`)
|
||||||
/// will reside here.
|
/// will reside here.
|
||||||
///
|
|
||||||
/// This directory is specified with the [initialize] method.
|
|
||||||
final Directory outputDirectory;
|
final Directory outputDirectory;
|
||||||
|
|
||||||
/// The input arb file which defines all of the messages that will be
|
/// The input arb file which defines all of the messages that will be
|
||||||
/// exported by the generated class that's written to [outputFile].
|
/// exported by the generated class that's written to [outputFile].
|
||||||
///
|
|
||||||
/// This file is specified with the [initialize] method.
|
|
||||||
final File templateArbFile;
|
final File templateArbFile;
|
||||||
|
|
||||||
/// The file to write the generated abstract localizations and
|
/// The file to write the generated abstract localizations and
|
||||||
/// localizations delegate classes to. Separate localizations
|
/// localizations delegate classes to. Separate localizations
|
||||||
/// files will also be generated for each language using this
|
/// files will also be generated for each language using this
|
||||||
/// filename as a prefix and the locale as the suffix.
|
/// filename as a prefix and the locale as the suffix.
|
||||||
///
|
|
||||||
/// This file is specified with the [initialize] method.
|
|
||||||
final File baseOutputFile;
|
final File baseOutputFile;
|
||||||
|
|
||||||
/// The class name to be used for the localizations class in [outputFile].
|
/// The class name to be used for the localizations class in [outputFile].
|
||||||
///
|
///
|
||||||
/// For example, if 'AppLocalizations' is passed in, a class named
|
/// For example, if 'AppLocalizations' is passed in, a class named
|
||||||
/// AppLocalizations will be used for localized message lookups.
|
/// AppLocalizations will be used for localized message lookups.
|
||||||
///
|
|
||||||
/// The class name is specified with the [initialize] method.
|
|
||||||
final String className;
|
final String className;
|
||||||
|
|
||||||
/// The list of preferred supported locales.
|
/// The list of preferred supported locales.
|
||||||
|
@ -673,8 +654,6 @@ class LocalizationsGenerator {
|
||||||
/// The order of locales in this list will also be the order of locale
|
/// The order of locales in this list will also be the order of locale
|
||||||
/// priority. For example, if a device supports 'en' and 'es' and
|
/// priority. For example, if a device supports 'en' and 'es' and
|
||||||
/// ['es', 'en'] is passed in, the 'es' locale will take priority over 'en'.
|
/// ['es', 'en'] is passed in, the 'es' locale will take priority over 'en'.
|
||||||
///
|
|
||||||
/// The list of preferred locales is specified with the [initialize] method.
|
|
||||||
final List<LocaleInfo> preferredSupportedLocales;
|
final List<LocaleInfo> preferredSupportedLocales;
|
||||||
|
|
||||||
/// The list of all arb path strings in [inputDirectory].
|
/// The list of all arb path strings in [inputDirectory].
|
||||||
|
@ -715,19 +694,15 @@ class LocalizationsGenerator {
|
||||||
/// string format.
|
/// string format.
|
||||||
final Map<File, String> _languageFileMap = <File, String>{};
|
final Map<File, String> _languageFileMap = <File, String>{};
|
||||||
|
|
||||||
/// Contains the generated application's localizations and localizations delegate
|
|
||||||
/// classes.
|
|
||||||
String _generatedLocalizationsFile;
|
|
||||||
|
|
||||||
/// A generated file that will contain the list of messages for each locale
|
/// A generated file that will contain the list of messages for each locale
|
||||||
/// that do not have a translation yet.
|
/// that do not have a translation yet.
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
final File untranslatedMessagesFile;
|
final File? untranslatedMessagesFile;
|
||||||
|
|
||||||
/// The file that contains the list of inputs and outputs for generating
|
/// The file that contains the list of inputs and outputs for generating
|
||||||
/// localizations.
|
/// localizations.
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
final File inputsAndOutputsListFile;
|
final File? inputsAndOutputsListFile;
|
||||||
final List<String> _inputFileList = <String>[];
|
final List<String> _inputFileList = <String>[];
|
||||||
final List<String> _outputFileList = <String>[];
|
final List<String> _outputFileList = <String>[];
|
||||||
|
|
||||||
|
@ -753,7 +728,7 @@ class LocalizationsGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
static Directory projectDirFromPath(FileSystem fileSystem, String projectPathString) {
|
static Directory? projectDirFromPath(FileSystem fileSystem, String? projectPathString) {
|
||||||
if (projectPathString == null) {
|
if (projectPathString == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -771,10 +746,7 @@ class LocalizationsGenerator {
|
||||||
|
|
||||||
/// Sets the reference [Directory] for [inputDirectory].
|
/// Sets the reference [Directory] for [inputDirectory].
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
static Directory inputDirectoryFromPath(FileSystem fileSystem, String inputPathString, Directory projectDirectory) {
|
static Directory inputDirectoryFromPath(FileSystem fileSystem, String inputPathString, Directory? projectDirectory) {
|
||||||
if (inputPathString == null) {
|
|
||||||
throw L10nException('inputPathString argument cannot be null');
|
|
||||||
}
|
|
||||||
final Directory inputDirectory = fileSystem.directory(
|
final Directory inputDirectory = fileSystem.directory(
|
||||||
projectDirectory != null
|
projectDirectory != null
|
||||||
? _getAbsoluteProjectPath(inputPathString, projectDirectory)
|
? _getAbsoluteProjectPath(inputPathString, projectDirectory)
|
||||||
|
@ -800,7 +772,7 @@ class LocalizationsGenerator {
|
||||||
|
|
||||||
/// Sets the reference [Directory] for [outputDirectory].
|
/// Sets the reference [Directory] for [outputDirectory].
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
static Directory outputDirectoryFromPath(FileSystem fileSystem, String outputPathString, bool useSyntheticPackage, Directory projectDirectory) {
|
static Directory outputDirectoryFromPath(FileSystem fileSystem, String outputPathString, bool useSyntheticPackage, Directory? projectDirectory) {
|
||||||
Directory outputDirectory;
|
Directory outputDirectory;
|
||||||
if (useSyntheticPackage) {
|
if (useSyntheticPackage) {
|
||||||
outputDirectory = fileSystem.directory(
|
outputDirectory = fileSystem.directory(
|
||||||
|
@ -809,13 +781,6 @@ class LocalizationsGenerator {
|
||||||
: _syntheticL10nPackagePath(fileSystem)
|
: _syntheticL10nPackagePath(fileSystem)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
if (outputPathString == null) {
|
|
||||||
throw L10nException(
|
|
||||||
'outputPathString argument cannot be null if not using '
|
|
||||||
'synthetic package option.'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
outputDirectory = fileSystem.directory(
|
outputDirectory = fileSystem.directory(
|
||||||
projectDirectory != null
|
projectDirectory != null
|
||||||
? _getAbsoluteProjectPath(outputPathString, projectDirectory)
|
? _getAbsoluteProjectPath(outputPathString, projectDirectory)
|
||||||
|
@ -828,13 +793,6 @@ class LocalizationsGenerator {
|
||||||
/// Sets the reference [File] for [templateArbFile].
|
/// Sets the reference [File] for [templateArbFile].
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
static File templateArbFileFromFileName(String templateArbFileName, Directory inputDirectory) {
|
static File templateArbFileFromFileName(String templateArbFileName, Directory inputDirectory) {
|
||||||
if (templateArbFileName == null) {
|
|
||||||
throw L10nException('templateArbFileName argument cannot be null');
|
|
||||||
}
|
|
||||||
if (inputDirectory == null) {
|
|
||||||
throw L10nException('inputDirectory cannot be null when setting template arb file');
|
|
||||||
}
|
|
||||||
|
|
||||||
final File templateArbFile = inputDirectory.childFile(templateArbFileName);
|
final File templateArbFile = inputDirectory.childFile(templateArbFileName);
|
||||||
final String templateArbFileStatModeString = templateArbFile.statSync().modeString();
|
final String templateArbFileStatModeString = templateArbFile.statSync().modeString();
|
||||||
if (templateArbFileStatModeString[0] == '-' && templateArbFileStatModeString[3] == '-') {
|
if (templateArbFileStatModeString[0] == '-' && templateArbFileStatModeString[3] == '-') {
|
||||||
|
@ -846,15 +804,6 @@ class LocalizationsGenerator {
|
||||||
return templateArbFile;
|
return templateArbFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the reference [File] for the localizations delegate [outputFile].
|
|
||||||
@visibleForTesting
|
|
||||||
static File baseOutputFileFromOutputFile(FileSystem fileSystem, String outputFileString, Directory outputDirectory) {
|
|
||||||
if (outputDirectory == null) {
|
|
||||||
throw L10nException('outputFileString argument cannot be null');
|
|
||||||
}
|
|
||||||
return outputDirectory.childFile(outputFileString);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool _isValidClassName(String className) {
|
static bool _isValidClassName(String className) {
|
||||||
// Public Dart class name cannot begin with an underscore
|
// Public Dart class name cannot begin with an underscore
|
||||||
if (className[0] == '_') {
|
if (className[0] == '_') {
|
||||||
|
@ -879,8 +828,8 @@ class LocalizationsGenerator {
|
||||||
/// classes.
|
/// classes.
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
static String classNameFromString(String classNameString) {
|
static String classNameFromString(String classNameString) {
|
||||||
if (classNameString == null || classNameString.isEmpty) {
|
if (classNameString.isEmpty) {
|
||||||
throw L10nException('classNameString argument cannot be null or empty');
|
throw L10nException('classNameString argument cannot be empty');
|
||||||
}
|
}
|
||||||
if (!_isValidClassName(classNameString)) {
|
if (!_isValidClassName(classNameString)) {
|
||||||
throw L10nException(
|
throw L10nException(
|
||||||
|
@ -893,7 +842,7 @@ class LocalizationsGenerator {
|
||||||
/// Sets [preferredSupportedLocales] so that this particular list of locales
|
/// Sets [preferredSupportedLocales] so that this particular list of locales
|
||||||
/// will take priority over the other locales.
|
/// will take priority over the other locales.
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
static List<LocaleInfo> preferredSupportedLocalesFromLocales(List<String> inputLocales) {
|
static List<LocaleInfo> preferredSupportedLocalesFromLocales(List<String>? inputLocales) {
|
||||||
if (inputLocales == null || inputLocales.isEmpty) {
|
if (inputLocales == null || inputLocales.isEmpty) {
|
||||||
return const <LocaleInfo>[];
|
return const <LocaleInfo>[];
|
||||||
}
|
}
|
||||||
|
@ -902,7 +851,7 @@ class LocalizationsGenerator {
|
||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
static String headerFromFile(String headerString, String headerFile, Directory inputDirectory) {
|
static String headerFromFile(String? headerString, String? headerFile, Directory inputDirectory) {
|
||||||
if (headerString != null && headerFile != null) {
|
if (headerString != null && headerFile != null) {
|
||||||
throw L10nException(
|
throw L10nException(
|
||||||
'Cannot accept both header and header file arguments. \n'
|
'Cannot accept both header and header file arguments. \n'
|
||||||
|
@ -928,7 +877,7 @@ class LocalizationsGenerator {
|
||||||
static String _getAbsoluteProjectPath(String relativePath, Directory projectDirectory) =>
|
static String _getAbsoluteProjectPath(String relativePath, Directory projectDirectory) =>
|
||||||
projectDirectory.fileSystem.path.join(projectDirectory.path, relativePath);
|
projectDirectory.fileSystem.path.join(projectDirectory.path, relativePath);
|
||||||
|
|
||||||
static File _untranslatedMessagesFileFromPath(FileSystem fileSystem, String untranslatedMessagesFileString) {
|
static File? _untranslatedMessagesFileFromPath(FileSystem fileSystem, String? untranslatedMessagesFileString) {
|
||||||
if (untranslatedMessagesFileString == null || untranslatedMessagesFileString.isEmpty) {
|
if (untranslatedMessagesFileString == null || untranslatedMessagesFileString.isEmpty) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -936,7 +885,7 @@ class LocalizationsGenerator {
|
||||||
return fileSystem.file(untranslatedMessagesFileString);
|
return fileSystem.file(untranslatedMessagesFileString);
|
||||||
}
|
}
|
||||||
|
|
||||||
static File _inputsAndOutputsListFileFromPath(FileSystem fileSystem, String inputsAndOutputsListPath) {
|
static File? _inputsAndOutputsListFileFromPath(FileSystem fileSystem, String? inputsAndOutputsListPath) {
|
||||||
if (inputsAndOutputsListPath == null) {
|
if (inputsAndOutputsListPath == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -969,12 +918,10 @@ class LocalizationsGenerator {
|
||||||
// Load _allMessages from templateArbFile and _allBundles from all of the ARB
|
// Load _allMessages from templateArbFile and _allBundles from all of the ARB
|
||||||
// files in inputDirectory. Also initialized: supportedLocales.
|
// files in inputDirectory. Also initialized: supportedLocales.
|
||||||
void loadResources() {
|
void loadResources() {
|
||||||
final AppResourceBundle templateBundle = AppResourceBundle(templateArbFile);
|
_allMessages = _templateBundle.resourceIds.map((String id) => Message(
|
||||||
_templateArbLocale = templateBundle.locale;
|
_templateBundle.resources, id, areResourceAttributesRequired,
|
||||||
_allMessages = templateBundle.resourceIds.map((String id) => Message(
|
|
||||||
templateBundle.resources, id, areResourceAttributesRequired,
|
|
||||||
));
|
));
|
||||||
for (final String resourceId in templateBundle.resourceIds) {
|
for (final String resourceId in _templateBundle.resourceIds) {
|
||||||
if (!_isValidGetterAndMethodName(resourceId)) {
|
if (!_isValidGetterAndMethodName(resourceId)) {
|
||||||
throw L10nException(
|
throw L10nException(
|
||||||
'Invalid ARB resource name "$resourceId" in $templateArbFile.\n'
|
'Invalid ARB resource name "$resourceId" in $templateArbFile.\n'
|
||||||
|
@ -985,7 +932,6 @@ class LocalizationsGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_allBundles = AppResourceBundleCollection(inputDirectory);
|
|
||||||
if (inputsAndOutputsListFile != null) {
|
if (inputsAndOutputsListFile != null) {
|
||||||
_inputFileList.addAll(_allBundles.bundles.map((AppResourceBundle bundle) {
|
_inputFileList.addAll(_allBundles.bundles.map((AppResourceBundle bundle) {
|
||||||
return bundle.file.absolute.path;
|
return bundle.file.absolute.path;
|
||||||
|
@ -1011,7 +957,7 @@ class LocalizationsGenerator {
|
||||||
|
|
||||||
void _addUnimplementedMessage(LocaleInfo locale, String message) {
|
void _addUnimplementedMessage(LocaleInfo locale, String message) {
|
||||||
if (_unimplementedMessages.containsKey(locale)) {
|
if (_unimplementedMessages.containsKey(locale)) {
|
||||||
_unimplementedMessages[locale].add(message);
|
_unimplementedMessages[locale]!.add(message);
|
||||||
} else {
|
} else {
|
||||||
_unimplementedMessages.putIfAbsent(locale, () => <String>[message]);
|
_unimplementedMessages.putIfAbsent(locale, () => <String>[message]);
|
||||||
}
|
}
|
||||||
|
@ -1032,9 +978,9 @@ class LocalizationsGenerator {
|
||||||
_addUnimplementedMessage(locale, message.resourceId);
|
_addUnimplementedMessage(locale, message.resourceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return generateMethod(
|
return _generateMethod(
|
||||||
message,
|
message,
|
||||||
bundle.translationFor(message) == null ? templateBundle : bundle,
|
bundle.translationFor(message) ?? templateBundle.translationFor(message)!,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1065,7 +1011,7 @@ class LocalizationsGenerator {
|
||||||
|
|
||||||
final Iterable<String> methods = messages
|
final Iterable<String> methods = messages
|
||||||
.where((Message message) => bundle.translationFor(message) != null)
|
.where((Message message) => bundle.translationFor(message) != null)
|
||||||
.map((Message message) => generateMethod(message, bundle));
|
.map((Message message) => _generateMethod(message, bundle.translationFor(message)!));
|
||||||
|
|
||||||
return subclassTemplate
|
return subclassTemplate
|
||||||
.replaceAll('@(language)', describeLocale(locale.toString()))
|
.replaceAll('@(language)', describeLocale(locale.toString()))
|
||||||
|
@ -1078,7 +1024,7 @@ class LocalizationsGenerator {
|
||||||
// Generate the AppLocalizations class, its LocalizationsDelegate subclass,
|
// Generate the AppLocalizations class, its LocalizationsDelegate subclass,
|
||||||
// and all AppLocalizations subclasses for every locale. This method by
|
// and all AppLocalizations subclasses for every locale. This method by
|
||||||
// itself does not generate the output files.
|
// itself does not generate the output files.
|
||||||
void _generateCode() {
|
String _generateCode() {
|
||||||
bool isBaseClassLocale(LocaleInfo locale, String language) {
|
bool isBaseClassLocale(LocaleInfo locale, String language) {
|
||||||
return locale.languageCode == language
|
return locale.languageCode == language
|
||||||
&& locale.countryCode == null
|
&& locale.countryCode == null
|
||||||
|
@ -1100,8 +1046,8 @@ class LocalizationsGenerator {
|
||||||
|
|
||||||
final Iterable<String> supportedLocalesCode = supportedLocales.map((LocaleInfo locale) {
|
final Iterable<String> supportedLocalesCode = supportedLocales.map((LocaleInfo locale) {
|
||||||
final String languageCode = locale.languageCode;
|
final String languageCode = locale.languageCode;
|
||||||
final String countryCode = locale.countryCode;
|
final String? countryCode = locale.countryCode;
|
||||||
final String scriptCode = locale.scriptCode;
|
final String? scriptCode = locale.scriptCode;
|
||||||
|
|
||||||
if (countryCode == null && scriptCode == null) {
|
if (countryCode == null && scriptCode == null) {
|
||||||
return 'Locale(\'$languageCode\')';
|
return 'Locale(\'$languageCode\')';
|
||||||
|
@ -1131,8 +1077,8 @@ class LocalizationsGenerator {
|
||||||
className,
|
className,
|
||||||
outputFileName,
|
outputFileName,
|
||||||
header,
|
header,
|
||||||
_allBundles.bundleFor(locale),
|
_allBundles.bundleFor(locale)!,
|
||||||
_allBundles.bundleFor(_templateArbLocale),
|
_allBundles.bundleFor(_templateArbLocale)!,
|
||||||
_allMessages,
|
_allMessages,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1143,7 +1089,7 @@ class LocalizationsGenerator {
|
||||||
final Iterable<String> subclasses = localesForLanguage.map<String>((LocaleInfo locale) {
|
final Iterable<String> subclasses = localesForLanguage.map<String>((LocaleInfo locale) {
|
||||||
return _generateSubclass(
|
return _generateSubclass(
|
||||||
className,
|
className,
|
||||||
_allBundles.bundleFor(locale),
|
_allBundles.bundleFor(locale)!,
|
||||||
_allMessages,
|
_allMessages,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1175,7 +1121,7 @@ class LocalizationsGenerator {
|
||||||
fileName: fileName,
|
fileName: fileName,
|
||||||
);
|
);
|
||||||
|
|
||||||
_generatedLocalizationsFile = fileTemplate
|
return fileTemplate
|
||||||
.replaceAll('@(header)', header)
|
.replaceAll('@(header)', header)
|
||||||
.replaceAll('@(class)', className)
|
.replaceAll('@(class)', className)
|
||||||
.replaceAll('@(methods)', _allMessages.map((Message message) => generateBaseClassMethod(message, _templateArbLocale)).join('\n'))
|
.replaceAll('@(methods)', _allMessages.map((Message message) => generateBaseClassMethod(message, _templateArbLocale)).join('\n'))
|
||||||
|
@ -1194,7 +1140,7 @@ class LocalizationsGenerator {
|
||||||
|
|
||||||
void writeOutputFiles(Logger logger, { bool isFromYaml = false }) {
|
void writeOutputFiles(Logger logger, { bool isFromYaml = false }) {
|
||||||
// First, generate the string contents of all necessary files.
|
// First, generate the string contents of all necessary files.
|
||||||
_generateCode();
|
final String generatedLocalizationsFile = _generateCode();
|
||||||
|
|
||||||
// A pubspec.yaml file is required when using a synthetic package. If it does not
|
// A pubspec.yaml file is required when using a synthetic package. If it does not
|
||||||
// exist, create a blank one.
|
// exist, create a blank one.
|
||||||
|
@ -1228,10 +1174,10 @@ class LocalizationsGenerator {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
baseOutputFile.writeAsStringSync(_generatedLocalizationsFile);
|
baseOutputFile.writeAsStringSync(generatedLocalizationsFile);
|
||||||
|
final File? messagesFile = untranslatedMessagesFile;
|
||||||
if (untranslatedMessagesFile != null) {
|
if (messagesFile != null) {
|
||||||
_generateUntranslatedMessagesFile(logger);
|
_generateUntranslatedMessagesFile(logger, messagesFile);
|
||||||
} else if (_unimplementedMessages.isNotEmpty) {
|
} else if (_unimplementedMessages.isNotEmpty) {
|
||||||
_unimplementedMessages.forEach((LocaleInfo locale, List<String> messages) {
|
_unimplementedMessages.forEach((LocaleInfo locale, List<String> messages) {
|
||||||
logger.printStatus('"$locale": ${messages.length} untranslated message(s).');
|
logger.printStatus('"$locale": ${messages.length} untranslated message(s).');
|
||||||
|
@ -1257,16 +1203,16 @@ class LocalizationsGenerator {
|
||||||
'need to be translated.'
|
'need to be translated.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
final File? inputsAndOutputsListFileLocal = inputsAndOutputsListFile;
|
||||||
if (inputsAndOutputsListFile != null) {
|
if (inputsAndOutputsListFileLocal != null) {
|
||||||
_outputFileList.add(baseOutputFile.absolute.path);
|
_outputFileList.add(baseOutputFile.absolute.path);
|
||||||
|
|
||||||
// Generate a JSON file containing the inputs and outputs of the gen_l10n script.
|
// Generate a JSON file containing the inputs and outputs of the gen_l10n script.
|
||||||
if (!inputsAndOutputsListFile.existsSync()) {
|
if (!inputsAndOutputsListFileLocal.existsSync()) {
|
||||||
inputsAndOutputsListFile.createSync(recursive: true);
|
inputsAndOutputsListFileLocal.createSync(recursive: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
inputsAndOutputsListFile.writeAsStringSync(
|
inputsAndOutputsListFileLocal.writeAsStringSync(
|
||||||
json.encode(<String, Object> {
|
json.encode(<String, Object> {
|
||||||
'inputs': _inputFileList,
|
'inputs': _inputFileList,
|
||||||
'outputs': _outputFileList,
|
'outputs': _outputFileList,
|
||||||
|
@ -1275,13 +1221,7 @@ class LocalizationsGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _generateUntranslatedMessagesFile(Logger logger) {
|
void _generateUntranslatedMessagesFile(Logger logger, File untranslatedMessagesFile) {
|
||||||
if (logger == null) {
|
|
||||||
throw L10nException(
|
|
||||||
'Logger must be defined when generating untranslated messages file.'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_unimplementedMessages.isEmpty) {
|
if (_unimplementedMessages.isEmpty) {
|
||||||
untranslatedMessagesFile.writeAsStringSync('{}');
|
untranslatedMessagesFile.writeAsStringSync('{}');
|
||||||
if (inputsAndOutputsListFile != null) {
|
if (inputsAndOutputsListFile != null) {
|
||||||
|
|
|
@ -187,7 +187,7 @@ class OptionalParameter {
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
class Placeholder {
|
class Placeholder {
|
||||||
Placeholder(this.resourceId, this.name, Map<String, dynamic> attributes)
|
Placeholder(this.resourceId, this.name, Map<String, Object?> attributes)
|
||||||
: assert(resourceId != null),
|
: assert(resourceId != null),
|
||||||
assert(name != null),
|
assert(name != null),
|
||||||
example = _stringAttribute(resourceId, name, attributes, 'example'),
|
example = _stringAttribute(resourceId, name, attributes, 'example'),
|
||||||
|
@ -212,10 +212,10 @@ class Placeholder {
|
||||||
static String? _stringAttribute(
|
static String? _stringAttribute(
|
||||||
String resourceId,
|
String resourceId,
|
||||||
String name,
|
String name,
|
||||||
Map<String, dynamic> attributes,
|
Map<String, Object?> attributes,
|
||||||
String attributeName,
|
String attributeName,
|
||||||
) {
|
) {
|
||||||
final dynamic value = attributes[attributeName];
|
final Object? value = attributes[attributeName];
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -231,9 +231,9 @@ class Placeholder {
|
||||||
static List<OptionalParameter> _optionalParameters(
|
static List<OptionalParameter> _optionalParameters(
|
||||||
String resourceId,
|
String resourceId,
|
||||||
String name,
|
String name,
|
||||||
Map<String, dynamic> attributes
|
Map<String, Object?> attributes
|
||||||
) {
|
) {
|
||||||
final dynamic value = attributes['optionalParameters'];
|
final Object? value = attributes['optionalParameters'];
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return <OptionalParameter>[];
|
return <OptionalParameter>[];
|
||||||
}
|
}
|
||||||
|
@ -267,7 +267,7 @@ class Placeholder {
|
||||||
// localized string to be shown for the template ARB file's locale.
|
// localized string to be shown for the template ARB file's locale.
|
||||||
// The docs for the Placeholder explain how placeholder entries are defined.
|
// The docs for the Placeholder explain how placeholder entries are defined.
|
||||||
class Message {
|
class Message {
|
||||||
Message(Map<String, dynamic> bundle, this.resourceId, bool isResourceAttributeRequired)
|
Message(Map<String, Object?> bundle, this.resourceId, bool isResourceAttributeRequired)
|
||||||
: assert(bundle != null),
|
: assert(bundle != null),
|
||||||
assert(resourceId != null && resourceId.isNotEmpty),
|
assert(resourceId != null && resourceId.isNotEmpty),
|
||||||
value = _value(bundle, resourceId),
|
value = _value(bundle, resourceId),
|
||||||
|
@ -298,23 +298,23 @@ class Message {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static String _value(Map<String, dynamic> bundle, String resourceId) {
|
static String _value(Map<String, Object?> bundle, String resourceId) {
|
||||||
final dynamic value = bundle[resourceId];
|
final Object? value = bundle[resourceId];
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
throw L10nException('A value for resource "$resourceId" was not found.');
|
throw L10nException('A value for resource "$resourceId" was not found.');
|
||||||
}
|
}
|
||||||
if (value is! String) {
|
if (value is! String) {
|
||||||
throw L10nException('The value of "$resourceId" is not a string.');
|
throw L10nException('The value of "$resourceId" is not a string.');
|
||||||
}
|
}
|
||||||
return bundle[resourceId] as String;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Map<String, dynamic> _attributes(
|
static Map<String, Object?>? _attributes(
|
||||||
Map<String, dynamic> bundle,
|
Map<String, Object?> bundle,
|
||||||
String resourceId,
|
String resourceId,
|
||||||
bool isResourceAttributeRequired,
|
bool isResourceAttributeRequired,
|
||||||
) {
|
) {
|
||||||
final dynamic attributes = bundle['@$resourceId'];
|
final Object? attributes = bundle['@$resourceId'];
|
||||||
if (isResourceAttributeRequired) {
|
if (isResourceAttributeRequired) {
|
||||||
if (attributes == null) {
|
if (attributes == null) {
|
||||||
throw L10nException(
|
throw L10nException(
|
||||||
|
@ -324,7 +324,7 @@ class Message {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attributes != null && attributes is! Map<String, dynamic>) {
|
if (attributes != null && attributes is! Map<String, Object?>) {
|
||||||
throw L10nException(
|
throw L10nException(
|
||||||
'The resource attribute "@$resourceId" is not a properly formatted Map. '
|
'The resource attribute "@$resourceId" is not a properly formatted Map. '
|
||||||
'Ensure that it is a map with keys that are strings.'
|
'Ensure that it is a map with keys that are strings.'
|
||||||
|
@ -340,20 +340,20 @@ class Message {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return attributes as Map<String, dynamic>;
|
return attributes as Map<String, Object?>?;
|
||||||
}
|
}
|
||||||
|
|
||||||
static String? _description(
|
static String? _description(
|
||||||
Map<String, dynamic> bundle,
|
Map<String, Object?> bundle,
|
||||||
String resourceId,
|
String resourceId,
|
||||||
bool isResourceAttributeRequired,
|
bool isResourceAttributeRequired,
|
||||||
) {
|
) {
|
||||||
final Map<String, dynamic> resourceAttributes = _attributes(bundle, resourceId, isResourceAttributeRequired);
|
final Map<String, Object?>? resourceAttributes = _attributes(bundle, resourceId, isResourceAttributeRequired);
|
||||||
if (resourceAttributes == null) {
|
if (resourceAttributes == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final dynamic value = resourceAttributes['description'];
|
final Object? value = resourceAttributes['description'];
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -366,27 +366,27 @@ class Message {
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<Placeholder> _placeholders(
|
static List<Placeholder> _placeholders(
|
||||||
Map<String, dynamic> bundle,
|
Map<String, Object?> bundle,
|
||||||
String resourceId,
|
String resourceId,
|
||||||
bool isResourceAttributeRequired,
|
bool isResourceAttributeRequired,
|
||||||
) {
|
) {
|
||||||
final Map<String, dynamic> resourceAttributes = _attributes(bundle, resourceId, isResourceAttributeRequired);
|
final Map<String, Object?>? resourceAttributes = _attributes(bundle, resourceId, isResourceAttributeRequired);
|
||||||
if (resourceAttributes == null) {
|
if (resourceAttributes == null) {
|
||||||
return <Placeholder>[];
|
return <Placeholder>[];
|
||||||
}
|
}
|
||||||
final dynamic allPlaceholdersMap = resourceAttributes['placeholders'];
|
final Object? allPlaceholdersMap = resourceAttributes['placeholders'];
|
||||||
if (allPlaceholdersMap == null) {
|
if (allPlaceholdersMap == null) {
|
||||||
return <Placeholder>[];
|
return <Placeholder>[];
|
||||||
}
|
}
|
||||||
if (allPlaceholdersMap is! Map<String, dynamic>) {
|
if (allPlaceholdersMap is! Map<String, Object?>) {
|
||||||
throw L10nException(
|
throw L10nException(
|
||||||
'The "placeholders" attribute for message $resourceId, is not '
|
'The "placeholders" attribute for message $resourceId, is not '
|
||||||
'properly formatted. Ensure that it is a map with string valued keys.'
|
'properly formatted. Ensure that it is a map with string valued keys.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return allPlaceholdersMap.keys.map<Placeholder>((String placeholderName) {
|
return allPlaceholdersMap.keys.map<Placeholder>((String placeholderName) {
|
||||||
final dynamic value = allPlaceholdersMap[placeholderName];
|
final Object? value = allPlaceholdersMap[placeholderName];
|
||||||
if (value is! Map<String, dynamic>) {
|
if (value is! Map<String, Object?>) {
|
||||||
throw L10nException(
|
throw L10nException(
|
||||||
'The value of the "$placeholderName" placeholder attribute for message '
|
'The value of the "$placeholderName" placeholder attribute for message '
|
||||||
'"$resourceId", is not properly formatted. Ensure that it is a map '
|
'"$resourceId", is not properly formatted. Ensure that it is a map '
|
||||||
|
@ -403,9 +403,9 @@ class AppResourceBundle {
|
||||||
factory AppResourceBundle(File file) {
|
factory AppResourceBundle(File file) {
|
||||||
assert(file != null);
|
assert(file != null);
|
||||||
// Assuming that the caller has verified that the file exists and is readable.
|
// Assuming that the caller has verified that the file exists and is readable.
|
||||||
Map<String, dynamic> resources;
|
Map<String, Object?> resources;
|
||||||
try {
|
try {
|
||||||
resources = json.decode(file.readAsStringSync()) as Map<String, dynamic>;
|
resources = json.decode(file.readAsStringSync()) as Map<String, Object?>;
|
||||||
} on FormatException catch (e) {
|
} on FormatException catch (e) {
|
||||||
throw L10nException(
|
throw L10nException(
|
||||||
'The arb file ${file.path} has the following formatting issue: \n'
|
'The arb file ${file.path} has the following formatting issue: \n'
|
||||||
|
@ -413,7 +413,7 @@ class AppResourceBundle {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
String localeString = resources['@@locale'] as String;
|
String? localeString = resources['@@locale'] as String?;
|
||||||
|
|
||||||
// Look for the first instance of an ISO 639-1 language code, matching exactly.
|
// Look for the first instance of an ISO 639-1 language code, matching exactly.
|
||||||
final String fileName = file.fileSystem.path.basenameWithoutExtension(file.path);
|
final String fileName = file.fileSystem.path.basenameWithoutExtension(file.path);
|
||||||
|
@ -470,10 +470,10 @@ class AppResourceBundle {
|
||||||
|
|
||||||
final File file;
|
final File file;
|
||||||
final LocaleInfo locale;
|
final LocaleInfo locale;
|
||||||
final Map<String, dynamic> resources;
|
final Map<String, Object?> resources;
|
||||||
final Iterable<String> resourceIds;
|
final Iterable<String> resourceIds;
|
||||||
|
|
||||||
String translationFor(Message message) => resources[message.resourceId] as String;
|
String? translationFor(Message message) => resources[message.resourceId] as String?;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
|
|
|
@ -98,75 +98,12 @@ void main() {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('setInputDirectory fails if input string is null', () {
|
testWithoutContext('setting className fails if input string is empty', () {
|
||||||
_standardFlutterDirectoryL10nSetup(fs);
|
_standardFlutterDirectoryL10nSetup(fs);
|
||||||
try {
|
try {
|
||||||
LocalizationsGenerator.inputDirectoryFromPath(fs, null, fs.directory('bogus'));
|
LocalizationsGenerator.classNameFromString('');
|
||||||
} on L10nException catch (e) {
|
} on L10nException catch (e) {
|
||||||
expect(e.message, contains('cannot be null'));
|
expect(e.message, contains('cannot be empty'));
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fail(
|
|
||||||
'LocalizationsGenerator.setInputDirectory should fail if the '
|
|
||||||
'input string is null.'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWithoutContext(
|
|
||||||
'setOutputDirectory fails if output string is null while not using the '
|
|
||||||
'synthetic package option',
|
|
||||||
() {
|
|
||||||
_standardFlutterDirectoryL10nSetup(fs);
|
|
||||||
try {
|
|
||||||
LocalizationsGenerator.outputDirectoryFromPath(fs, null, false, null);
|
|
||||||
} on L10nException catch (e) {
|
|
||||||
expect(e.message, contains('cannot be null'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fail(
|
|
||||||
'LocalizationsGenerator.setOutputDirectory should fail if the '
|
|
||||||
'input string is null.'
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
testWithoutContext('setTemplateArbFile fails if inputDirectory is null', () {
|
|
||||||
try {
|
|
||||||
LocalizationsGenerator.templateArbFileFromFileName(defaultTemplateArbFileName, null);
|
|
||||||
} on L10nException catch (e) {
|
|
||||||
expect(e.message, contains('cannot be null'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fail(
|
|
||||||
'LocalizationsGenerator.setTemplateArbFile should fail if the '
|
|
||||||
'inputDirectory is not specified.'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWithoutContext('setTemplateArbFile fails if templateArbFileName is null', () {
|
|
||||||
_standardFlutterDirectoryL10nSetup(fs);
|
|
||||||
try {
|
|
||||||
LocalizationsGenerator.templateArbFileFromFileName(null, fs.directory('bogus'));
|
|
||||||
} on L10nException catch (e) {
|
|
||||||
expect(e.message, contains('cannot be null'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fail(
|
|
||||||
'LocalizationsGenerator.setTemplateArbFile should fail if the '
|
|
||||||
'templateArbFileName passed in is null.'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWithoutContext('setting className fails if input string is null', () {
|
|
||||||
_standardFlutterDirectoryL10nSetup(fs);
|
|
||||||
try {
|
|
||||||
LocalizationsGenerator.classNameFromString(null);
|
|
||||||
} on L10nException catch (e) {
|
|
||||||
expect(e.message, contains('cannot be null'));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue