Unverified Commit 47bba449 authored by Shi-Hao Hong's avatar Shi-Hao Hong Committed by GitHub

L10n Currency Formatting, Fixes to Named vs Positional Parameters (#48445)

* Add currency formatting for l10n tool, fix positional vs named params
parent ec2d5833
......@@ -232,11 +232,37 @@ const Set<String> allowableDateFormats = <String>{
// * <https://pub.dev/documentation/intl/latest/intl/NumberFormat-class.html>
const Set<String> allowableNumberFormats = <String>{
'compact',
'compactCurrency',
'compactSimpleCurrency',
'compactLong',
'currency',
'decimalPattern',
'decimalPercentPattern',
'percentPattern',
'scientificPattern',
'simpleCurrency',
};
// The names of the NumberFormat factory constructors which have named
// parameters rather than positional parameters.
//
// This helps the tool correctly generate number formmatting code correctly.
//
// Example of code that uses named parameters:
// final NumberFormat format = NumberFormat.compact(
// locale: _localeName,
// );
//
// Example of code that uses positional parameters:
// final NumberFormat format = NumberFormat.scientificPattern(_localeName);
const Set<String> numberFormatsWithNamedParameters = <String>{
'compact',
'compactCurrency',
'compactSimpleCurrency',
'compactLong',
'currency',
'decimalPercentPattern',
'simpleCurrency',
};
bool _isDateParameter(Map<String, dynamic> placeholderValue) => placeholderValue['type'] == 'DateTime';
......@@ -330,19 +356,27 @@ String generateNumberFormattingLogic(Map<String, dynamic> arbBundle, String reso
for (final String placeholder in placeholders.keys) {
final dynamic value = placeholders[placeholder];
if (value is Map<String, dynamic> && _isValidNumberFormat(value, placeholder)) {
if (value.containsKey('optionalParameters')) {
final Map<String, dynamic> optionalParameters = value['optionalParameters'] as Map<String, dynamic>;
for (final String parameter in optionalParameters.keys)
optionalParametersString.write('\n $parameter: ${optionalParameters[parameter]},');
}
if (numberFormatsWithNamedParameters.contains(value['format'])) {
if (value.containsKey('optionalParameters')) {
final Map<String, dynamic> optionalParameters = value['optionalParameters'] as Map<String, dynamic>;
for (final String parameter in optionalParameters.keys)
optionalParametersString.write('\n $parameter: ${optionalParameters[parameter]},');
}
result.write('''
result.write('''
final NumberFormat ${placeholder}NumberFormat = NumberFormat.${value['format']}(
locale: _localeName,@optionalParameters
);
final String ${placeholder}String = ${placeholder}NumberFormat.format($placeholder);
''');
} else {
result.write('''
final NumberFormat ${placeholder}NumberFormat = NumberFormat.${value['format']}(_localeName);
final String ${placeholder}String = ${placeholder}NumberFormat.format($placeholder);
''');
}
}
}
......
......@@ -962,7 +962,7 @@ void main() {
"placeholders": {
"progress": {
"type": "Number",
"format": "percentPattern"
"format": "compact"
}
}
}
......@@ -990,7 +990,7 @@ void main() {
expect(
generator.classMethods.first,
''' String courseCompletion(Object progress) {
final NumberFormat progressNumberFormat = NumberFormat.percentPattern(
final NumberFormat progressNumberFormat = NumberFormat.compact(
locale: _localeName,
);
final String progressString = progressNumberFormat.format(progress);
......@@ -1006,15 +1006,26 @@ void main() {
''');
});
test('correctly adds optional parameters to numbers', () {
const String singleNumberMessage = '''{
test('correctly adds optional named parameters to numbers', () {
const Set<String> numberFormatsWithNamedParameters = <String>{
'compact',
'compactCurrency',
'compactSimpleCurrency',
'compactLong',
'currency',
'decimalPercentPattern',
'simpleCurrency',
};
for (final String numberFormat in numberFormatsWithNamedParameters) {
final String singleNumberMessage = '''{
"courseCompletion": "You have completed {progress} of the course.",
"@courseCompletion": {
"description": "The amount of progress the student has made in their class.",
"placeholders": {
"progress": {
"type": "Number",
"format": "decimalPercentPattern",
"format": "$numberFormat",
"optionalParameters": {
"decimalDigits": 2
}
......@@ -1022,30 +1033,30 @@ void main() {
}
}
}''';
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
..createSync(recursive: true);
l10nDirectory.childFile(defaultTemplateArbFileName)
.writeAsStringSync(singleNumberMessage);
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
try {
generator.initialize(
l10nDirectoryPath: defaultArbPathString,
templateArbFileName: defaultTemplateArbFileName,
outputFileString: defaultOutputFileString,
classNameString: defaultClassNameString,
);
generator.parseArbFiles();
generator.generateClassMethods();
} on Exception catch (e) {
fail('Parsing template arb file should succeed: \n$e');
}
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
..createSync(recursive: true);
l10nDirectory.childFile(defaultTemplateArbFileName)
.writeAsStringSync(singleNumberMessage);
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
try {
generator.initialize(
l10nDirectoryPath: defaultArbPathString,
templateArbFileName: defaultTemplateArbFileName,
outputFileString: defaultOutputFileString,
classNameString: defaultClassNameString,
);
generator.parseArbFiles();
generator.generateClassMethods();
} on Exception catch (e) {
fail('Parsing template arb file should succeed: \n$e');
}
expect(generator.classMethods, isNotEmpty);
expect(
generator.classMethods.first,
''' String courseCompletion(Object progress) {
final NumberFormat progressNumberFormat = NumberFormat.decimalPercentPattern(
expect(generator.classMethods, isNotEmpty);
expect(
generator.classMethods.first,
''' String courseCompletion(Object progress) {
final NumberFormat progressNumberFormat = NumberFormat.$numberFormat(
locale: _localeName,
decimalDigits: 2,
);
......@@ -1060,6 +1071,65 @@ void main() {
);
}
''');
}
});
test('correctly adds optional positional parameters to numbers', () {
const Set<String> numberFormatsWithPositionalParameters = <String>{
'decimalPattern',
'percentPattern',
'scientificPattern',
};
for (final String numberFormat in numberFormatsWithPositionalParameters) {
final String singleNumberMessage = '''{
"courseCompletion": "You have completed {progress} of the course.",
"@courseCompletion": {
"description": "The amount of progress the student has made in their class.",
"placeholders": {
"progress": {
"type": "Number",
"format": "$numberFormat"
}
}
}
}''';
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
..createSync(recursive: true);
l10nDirectory.childFile(defaultTemplateArbFileName)
.writeAsStringSync(singleNumberMessage);
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
try {
generator.initialize(
l10nDirectoryPath: defaultArbPathString,
templateArbFileName: defaultTemplateArbFileName,
outputFileString: defaultOutputFileString,
classNameString: defaultClassNameString,
);
generator.parseArbFiles();
generator.generateClassMethods();
} on Exception catch (e) {
fail('Parsing template arb file should succeed: \n$e');
}
expect(generator.classMethods, isNotEmpty);
expect(
generator.classMethods.first,
''' String courseCompletion(Object progress) {
final NumberFormat progressNumberFormat = NumberFormat.$numberFormat(_localeName);
final String progressString = progressNumberFormat.format(progress);
return Intl.message(
r'You have completed \$progressString of the course.',
locale: _localeName,
name: 'courseCompletion',
desc: r'The amount of progress the student has made in their class.',
args: <Object>[progressString]
);
}
''');
}
});
test('throws an exception when improperly formatted number is passed in', () {
......
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