mirror of
https://github.com/flutter/flutter
synced 2024-10-14 04:02:56 +00:00
1615 lines
59 KiB
Dart
1615 lines
59 KiB
Dart
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'dart:io';
|
|
|
|
import 'package:file/file.dart';
|
|
import 'package:file/memory.dart';
|
|
import 'package:path/path.dart' as path;
|
|
|
|
import '../../localization/gen_l10n.dart';
|
|
import '../../localization/localizations_utils.dart';
|
|
|
|
import '../common.dart';
|
|
|
|
final String defaultArbPathString = path.join('lib', 'l10n');
|
|
const String defaultTemplateArbFileName = 'app_en_US.arb';
|
|
const String defaultOutputFileString = 'output-localization-file';
|
|
const String defaultClassNameString = 'AppLocalizations';
|
|
const String singleMessageArbFileString = '''{
|
|
"title": "Title",
|
|
"@title": {
|
|
"description": "Title for the application"
|
|
}
|
|
}''';
|
|
|
|
const String esArbFileName = 'app_es.arb';
|
|
const String singleEsMessageArbFileString = '''{
|
|
"title": "Título"
|
|
}''';
|
|
const String singleZhMessageArbFileString = '''{
|
|
"title": "标题"
|
|
}''';
|
|
|
|
void _standardFlutterDirectoryL10nSetup(FileSystem fs) {
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile(defaultTemplateArbFileName)
|
|
.writeAsStringSync(singleMessageArbFileString);
|
|
l10nDirectory.childFile(esArbFileName)
|
|
.writeAsStringSync(singleEsMessageArbFileString);
|
|
}
|
|
|
|
void main() {
|
|
MemoryFileSystem fs;
|
|
|
|
setUp(() {
|
|
fs = MemoryFileSystem(
|
|
style: Platform.isWindows ? FileSystemStyle.windows : FileSystemStyle.posix
|
|
);
|
|
});
|
|
|
|
group('Setters', () {
|
|
test('happy path', () {
|
|
_standardFlutterDirectoryL10nSetup(fs);
|
|
expect(() {
|
|
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
|
|
generator.initialize(
|
|
l10nDirectoryPath: defaultArbPathString,
|
|
templateArbFileName: defaultTemplateArbFileName,
|
|
outputFileString: defaultOutputFileString,
|
|
classNameString: defaultClassNameString,
|
|
);
|
|
}, returnsNormally);
|
|
});
|
|
|
|
test('setL10nDirectory fails if the directory does not exist', () {
|
|
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
|
|
try {
|
|
generator.setL10nDirectory('lib');
|
|
} on FileSystemException catch (e) {
|
|
expect(e.message, contains('Make sure that the correct path was provided'));
|
|
return;
|
|
}
|
|
|
|
fail(
|
|
'Attempting to set LocalizationsGenerator.setL10nDirectory should fail if the '
|
|
'directory does not exist.'
|
|
);
|
|
});
|
|
|
|
test('setL10nDirectory fails if input string is null', () {
|
|
_standardFlutterDirectoryL10nSetup(fs);
|
|
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
|
|
try {
|
|
generator.setL10nDirectory(null);
|
|
} on L10nException catch (e) {
|
|
expect(e.message, contains('cannot be null'));
|
|
return;
|
|
}
|
|
|
|
fail(
|
|
'Attempting to set LocalizationsGenerator.setL10nDirectory should fail if the '
|
|
'the input string is null.'
|
|
);
|
|
});
|
|
|
|
test('setTemplateArbFile fails if l10nDirectory is null', () {
|
|
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
|
|
try {
|
|
generator.setTemplateArbFile(defaultTemplateArbFileName);
|
|
} on L10nException catch (e) {
|
|
expect(e.message, contains('cannot be null'));
|
|
return;
|
|
}
|
|
|
|
fail(
|
|
'Attempting to set LocalizationsGenerator.setTemplateArbFile should fail if the '
|
|
'the l10nDirectory is null.'
|
|
);
|
|
});
|
|
|
|
test('setTemplateArbFile fails if templateArbFileName is null', () {
|
|
_standardFlutterDirectoryL10nSetup(fs);
|
|
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
|
|
try {
|
|
generator.setTemplateArbFile(null);
|
|
} on L10nException catch (e) {
|
|
expect(e.message, contains('cannot be null'));
|
|
return;
|
|
}
|
|
|
|
fail(
|
|
'Attempting to set LocalizationsGenerator.setTemplateArbFile should fail if the '
|
|
'the l10nDirectory is null.'
|
|
);
|
|
});
|
|
|
|
test('setTemplateArbFile fails if input string is null', () {
|
|
_standardFlutterDirectoryL10nSetup(fs);
|
|
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
|
|
try {
|
|
generator.setTemplateArbFile(null);
|
|
} on L10nException catch (e) {
|
|
expect(e.message, contains('cannot be null'));
|
|
return;
|
|
}
|
|
|
|
fail(
|
|
'Attempting to set LocalizationsGenerator.setTemplateArbFile should fail if the '
|
|
'the input string is null.'
|
|
);
|
|
});
|
|
|
|
test('setOutputFile fails if input string is null', () {
|
|
_standardFlutterDirectoryL10nSetup(fs);
|
|
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
|
|
try {
|
|
generator.setOutputFile(null);
|
|
} on L10nException catch (e) {
|
|
expect(e.message, contains('cannot be null'));
|
|
return;
|
|
}
|
|
|
|
fail(
|
|
'Attempting to set LocalizationsGenerator.setOutputFile should fail if the '
|
|
'the input string is null.'
|
|
);
|
|
});
|
|
|
|
test('setting className fails if input string is null', () {
|
|
_standardFlutterDirectoryL10nSetup(fs);
|
|
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
|
|
try {
|
|
generator.className = null;
|
|
} on L10nException catch (e) {
|
|
expect(e.message, contains('cannot be null'));
|
|
return;
|
|
}
|
|
|
|
fail(
|
|
'Attempting to set LocalizationsGenerator.className should fail if the '
|
|
'the input string is null.'
|
|
);
|
|
});
|
|
|
|
group('className should only take valid Dart class names', () {
|
|
LocalizationsGenerator generator;
|
|
setUp(() {
|
|
_standardFlutterDirectoryL10nSetup(fs);
|
|
generator = LocalizationsGenerator(fs);
|
|
try {
|
|
generator.setL10nDirectory(defaultArbPathString);
|
|
generator.setTemplateArbFile(defaultTemplateArbFileName);
|
|
generator.setOutputFile(defaultOutputFileString);
|
|
} on L10nException catch (e) {
|
|
throw TestFailure('Unexpected failure during test setup: ${e.message}');
|
|
}
|
|
});
|
|
|
|
test('fails on string with spaces', () {
|
|
try {
|
|
generator.className = 'String with spaces';
|
|
} on L10nException catch (e) {
|
|
expect(e.message, contains('is not a valid Dart class name'));
|
|
return;
|
|
}
|
|
fail(
|
|
'Attempting to set LocalizationsGenerator.className should fail if the '
|
|
'the input string is not a valid Dart class name.'
|
|
);
|
|
});
|
|
|
|
test('fails on non-alphanumeric symbols', () {
|
|
try {
|
|
generator.className = 'TestClass@123';
|
|
} on L10nException catch (e) {
|
|
expect(e.message, contains('is not a valid Dart class name'));
|
|
return;
|
|
}
|
|
fail(
|
|
'Attempting to set LocalizationsGenerator.className should fail if the '
|
|
'the input string is not a valid Dart class name.'
|
|
);
|
|
});
|
|
|
|
test('fails on camel-case', () {
|
|
try {
|
|
generator.className = 'camelCaseClassName';
|
|
} on L10nException catch (e) {
|
|
expect(e.message, contains('is not a valid Dart class name'));
|
|
return;
|
|
}
|
|
fail(
|
|
'Attempting to set LocalizationsGenerator.className should fail if the '
|
|
'the input string is not a valid Dart class name.'
|
|
);
|
|
});
|
|
|
|
test('fails when starting with a number', () {
|
|
try {
|
|
generator.className = '123ClassName';
|
|
} on L10nException catch (e) {
|
|
expect(e.message, contains('is not a valid Dart class name'));
|
|
return;
|
|
}
|
|
fail(
|
|
'Attempting to set LocalizationsGenerator.className should fail if the '
|
|
'the input string is not a valid Dart class name.'
|
|
);
|
|
});
|
|
});
|
|
});
|
|
|
|
group('parseArbFiles', () {
|
|
test('correctly initializes supportedLocales and supportedLanguageCodes properties', () {
|
|
_standardFlutterDirectoryL10nSetup(fs);
|
|
|
|
LocalizationsGenerator generator;
|
|
try {
|
|
generator = LocalizationsGenerator(fs);
|
|
generator.initialize(
|
|
l10nDirectoryPath: defaultArbPathString,
|
|
templateArbFileName: defaultTemplateArbFileName,
|
|
outputFileString: defaultOutputFileString,
|
|
classNameString: defaultClassNameString,
|
|
);
|
|
generator.parseArbFiles();
|
|
} on L10nException catch (e) {
|
|
fail('Setting language and locales should not fail: \n$e');
|
|
}
|
|
|
|
expect(generator.supportedLocales.contains(LocaleInfo.fromString('en_US')), true);
|
|
expect(generator.supportedLocales.contains(LocaleInfo.fromString('es')), true);
|
|
});
|
|
|
|
test('correctly sorts supportedLocales and supportedLanguageCodes alphabetically', () {
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
// Write files in non-alphabetical order so that read performs in that order
|
|
l10nDirectory.childFile('app_zh.arb')
|
|
.writeAsStringSync(singleZhMessageArbFileString);
|
|
l10nDirectory.childFile('app_es.arb')
|
|
.writeAsStringSync(singleEsMessageArbFileString);
|
|
l10nDirectory.childFile('app_en_US.arb')
|
|
.writeAsStringSync(singleMessageArbFileString);
|
|
|
|
LocalizationsGenerator generator;
|
|
try {
|
|
generator = LocalizationsGenerator(fs);
|
|
generator.initialize(
|
|
l10nDirectoryPath: defaultArbPathString,
|
|
templateArbFileName: defaultTemplateArbFileName,
|
|
outputFileString: defaultOutputFileString,
|
|
classNameString: defaultClassNameString,
|
|
);
|
|
generator.parseArbFiles();
|
|
} on L10nException catch (e) {
|
|
fail('Setting language and locales should not fail: \n$e');
|
|
}
|
|
|
|
expect(generator.supportedLocales.first, LocaleInfo.fromString('en_US'));
|
|
expect(generator.supportedLocales.elementAt(1), LocaleInfo.fromString('es'));
|
|
expect(generator.supportedLocales.elementAt(2), LocaleInfo.fromString('zh'));
|
|
});
|
|
|
|
test('adds preferred locales to the top of supportedLocales and supportedLanguageCodes', () {
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile('app_en_US.arb')
|
|
.writeAsStringSync(singleMessageArbFileString);
|
|
l10nDirectory.childFile('app_es.arb')
|
|
.writeAsStringSync(singleEsMessageArbFileString);
|
|
l10nDirectory.childFile('app_zh.arb')
|
|
.writeAsStringSync(singleZhMessageArbFileString);
|
|
|
|
const String preferredSupportedLocaleString = '["zh", "es"]';
|
|
LocalizationsGenerator generator;
|
|
try {
|
|
generator = LocalizationsGenerator(fs);
|
|
generator.initialize(
|
|
l10nDirectoryPath: defaultArbPathString,
|
|
templateArbFileName: defaultTemplateArbFileName,
|
|
outputFileString: defaultOutputFileString,
|
|
classNameString: defaultClassNameString,
|
|
preferredSupportedLocaleString: preferredSupportedLocaleString,
|
|
);
|
|
generator.parseArbFiles();
|
|
} on L10nException catch (e) {
|
|
fail('Setting language and locales should not fail: \n$e');
|
|
}
|
|
|
|
expect(generator.supportedLocales.first, LocaleInfo.fromString('zh'));
|
|
expect(generator.supportedLocales.elementAt(1), LocaleInfo.fromString('es'));
|
|
expect(generator.supportedLocales.elementAt(2), LocaleInfo.fromString('en_US'));
|
|
});
|
|
|
|
test(
|
|
'throws an error attempting to add preferred locales '
|
|
'with incorrect runtime type',
|
|
() {
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile('app_en_US.arb')
|
|
.writeAsStringSync(singleMessageArbFileString);
|
|
l10nDirectory.childFile('app_es.arb')
|
|
.writeAsStringSync(singleEsMessageArbFileString);
|
|
l10nDirectory.childFile('app_zh.arb')
|
|
.writeAsStringSync(singleZhMessageArbFileString);
|
|
|
|
const String preferredSupportedLocaleString = '[44, "en_US"]';
|
|
LocalizationsGenerator generator;
|
|
try {
|
|
generator = LocalizationsGenerator(fs);
|
|
generator.initialize(
|
|
l10nDirectoryPath: defaultArbPathString,
|
|
templateArbFileName: defaultTemplateArbFileName,
|
|
outputFileString: defaultOutputFileString,
|
|
classNameString: defaultClassNameString,
|
|
preferredSupportedLocaleString: preferredSupportedLocaleString,
|
|
);
|
|
generator.parseArbFiles();
|
|
} on L10nException catch (e) {
|
|
expect(
|
|
e.message,
|
|
contains('Incorrect runtime type'),
|
|
);
|
|
return;
|
|
}
|
|
|
|
fail(
|
|
'Should fail since an incorrect runtime type was used '
|
|
'in the preferredSupportedLocales list.'
|
|
);
|
|
},
|
|
);
|
|
|
|
test(
|
|
'throws an error attempting to add preferred locales '
|
|
'when there is no corresponding arb file for that '
|
|
'locale',
|
|
() {
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile('app_en_US.arb')
|
|
.writeAsStringSync(singleMessageArbFileString);
|
|
l10nDirectory.childFile('app_es.arb')
|
|
.writeAsStringSync(singleEsMessageArbFileString);
|
|
l10nDirectory.childFile('app_zh.arb')
|
|
.writeAsStringSync(singleZhMessageArbFileString);
|
|
|
|
const String preferredSupportedLocaleString = '["am", "es"]';
|
|
LocalizationsGenerator generator;
|
|
try {
|
|
generator = LocalizationsGenerator(fs);
|
|
generator.initialize(
|
|
l10nDirectoryPath: defaultArbPathString,
|
|
templateArbFileName: defaultTemplateArbFileName,
|
|
outputFileString: defaultOutputFileString,
|
|
classNameString: defaultClassNameString,
|
|
preferredSupportedLocaleString: preferredSupportedLocaleString,
|
|
);
|
|
generator.parseArbFiles();
|
|
} on L10nException catch (e) {
|
|
expect(
|
|
e.message,
|
|
contains("The preferred supported locale, 'am', cannot be added."),
|
|
);
|
|
return;
|
|
}
|
|
|
|
fail(
|
|
'Should fail since an unsupported locale was added '
|
|
'to the preferredSupportedLocales list.'
|
|
);
|
|
},
|
|
);
|
|
|
|
test('correctly sorts arbPathString alphabetically', () {
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
// Write files in non-alphabetical order so that read performs in that order
|
|
l10nDirectory.childFile('app_zh.arb')
|
|
.writeAsStringSync(singleZhMessageArbFileString);
|
|
l10nDirectory.childFile('app_es.arb')
|
|
.writeAsStringSync(singleEsMessageArbFileString);
|
|
l10nDirectory.childFile('app_en_US.arb')
|
|
.writeAsStringSync(singleMessageArbFileString);
|
|
|
|
LocalizationsGenerator generator;
|
|
try {
|
|
generator = LocalizationsGenerator(fs);
|
|
generator.initialize(
|
|
l10nDirectoryPath: defaultArbPathString,
|
|
templateArbFileName: defaultTemplateArbFileName,
|
|
outputFileString: defaultOutputFileString,
|
|
classNameString: defaultClassNameString,
|
|
);
|
|
generator.parseArbFiles();
|
|
} on L10nException catch (e) {
|
|
fail('Setting language and locales should not fail: \n$e');
|
|
}
|
|
|
|
if (Platform.isWindows) {
|
|
expect(generator.arbPathStrings.first, 'lib\\l10n\\app_en_US.arb');
|
|
expect(generator.arbPathStrings.elementAt(1), 'lib\\l10n\\app_es.arb');
|
|
expect(generator.arbPathStrings.elementAt(2), 'lib\\l10n\\app_zh.arb');
|
|
} else {
|
|
expect(generator.arbPathStrings.first, 'lib/l10n/app_en_US.arb');
|
|
expect(generator.arbPathStrings.elementAt(1), 'lib/l10n/app_es.arb');
|
|
expect(generator.arbPathStrings.elementAt(2), 'lib/l10n/app_zh.arb');
|
|
}
|
|
});
|
|
|
|
test('correctly parses @@locale property in arb file', () {
|
|
const String arbFileWithEnLocale = '''{
|
|
"@@locale": "en",
|
|
"title": "Title",
|
|
"@title": {
|
|
"description": "Title for the application"
|
|
}
|
|
}''';
|
|
|
|
const String arbFileWithZhLocale = '''{
|
|
"@@locale": "zh",
|
|
"title": "标题",
|
|
"@title": {
|
|
"description": "Title for the application"
|
|
}
|
|
}''';
|
|
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile('first_file.arb')
|
|
.writeAsStringSync(arbFileWithEnLocale);
|
|
l10nDirectory.childFile('second_file.arb')
|
|
.writeAsStringSync(arbFileWithZhLocale);
|
|
|
|
LocalizationsGenerator generator;
|
|
try {
|
|
generator = LocalizationsGenerator(fs);
|
|
generator.initialize(
|
|
l10nDirectoryPath: defaultArbPathString,
|
|
templateArbFileName: 'first_file.arb',
|
|
outputFileString: defaultOutputFileString,
|
|
classNameString: defaultClassNameString,
|
|
);
|
|
generator.parseArbFiles();
|
|
} on L10nException catch (e) {
|
|
fail('Setting language and locales should not fail: \n$e');
|
|
}
|
|
|
|
expect(generator.supportedLocales.contains(LocaleInfo.fromString('en')), true);
|
|
expect(generator.supportedLocales.contains(LocaleInfo.fromString('zh')), true);
|
|
});
|
|
|
|
test('correctly prioritizes @@locale property in arb file over filename', () {
|
|
const String arbFileWithEnLocale = '''{
|
|
"@@locale": "en",
|
|
"title": "Stocks",
|
|
"@title": {
|
|
"description": "Title for the Stocks application"
|
|
}
|
|
}''';
|
|
|
|
const String arbFileWithZhLocale = '''{
|
|
"@@locale": "zh",
|
|
"title": "标题",
|
|
"@title": {
|
|
"description": "Title for the Stocks application"
|
|
}
|
|
}''';
|
|
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile('app_es.arb')
|
|
.writeAsStringSync(arbFileWithEnLocale);
|
|
l10nDirectory.childFile('app_am.arb')
|
|
.writeAsStringSync(arbFileWithZhLocale);
|
|
|
|
LocalizationsGenerator generator;
|
|
try {
|
|
generator = LocalizationsGenerator(fs);
|
|
generator.initialize(
|
|
l10nDirectoryPath: defaultArbPathString,
|
|
templateArbFileName: 'app_es.arb',
|
|
outputFileString: defaultOutputFileString,
|
|
classNameString: defaultClassNameString,
|
|
);
|
|
generator.parseArbFiles();
|
|
} on L10nException catch (e) {
|
|
fail('Setting language and locales should not fail: \n$e');
|
|
}
|
|
|
|
// @@locale property should hold higher priority
|
|
expect(generator.supportedLocales.contains(LocaleInfo.fromString('en')), true);
|
|
expect(generator.supportedLocales.contains(LocaleInfo.fromString('zh')), true);
|
|
// filename should not be used since @@locale is specified
|
|
expect(generator.supportedLocales.contains(LocaleInfo.fromString('es')), false);
|
|
expect(generator.supportedLocales.contains(LocaleInfo.fromString('am')), false);
|
|
});
|
|
|
|
test('throws when arb file\'s locale could not be determined', () {
|
|
fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true)
|
|
..childFile('app.arb')
|
|
.writeAsStringSync(singleMessageArbFileString);
|
|
try {
|
|
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
|
|
generator.initialize(
|
|
l10nDirectoryPath: defaultArbPathString,
|
|
templateArbFileName: 'app.arb',
|
|
outputFileString: defaultOutputFileString,
|
|
classNameString: defaultClassNameString,
|
|
);
|
|
generator.parseArbFiles();
|
|
} on L10nException catch (e) {
|
|
expect(e.message, contains('locale could not be determined'));
|
|
return;
|
|
}
|
|
fail(
|
|
'Since locale is not specified, setting languages and locales '
|
|
'should fail'
|
|
);
|
|
});
|
|
test('throws when the same locale is detected more than once', () {
|
|
const String secondMessageArbFileString = '''{
|
|
"market": "MARKET",
|
|
"@market": {
|
|
"description": "Label for the Market tab"
|
|
}
|
|
}''';
|
|
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile('app_en.arb')
|
|
.writeAsStringSync(singleMessageArbFileString);
|
|
l10nDirectory.childFile('app2_en.arb')
|
|
.writeAsStringSync(secondMessageArbFileString);
|
|
|
|
try {
|
|
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
|
|
generator.initialize(
|
|
l10nDirectoryPath: defaultArbPathString,
|
|
templateArbFileName: 'app_en.arb',
|
|
outputFileString: defaultOutputFileString,
|
|
classNameString: defaultClassNameString,
|
|
);
|
|
generator.parseArbFiles();
|
|
} on L10nException catch (e) {
|
|
expect(e.message, contains('Multiple arb files with the same locale detected'));
|
|
return;
|
|
}
|
|
|
|
fail(
|
|
'Since en locale is specified twice, setting languages and locales '
|
|
'should fail'
|
|
);
|
|
});
|
|
});
|
|
|
|
group('generateClassMethods', () {
|
|
test('correctly generates a simple message with getter', () {
|
|
_standardFlutterDirectoryL10nSetup(fs);
|
|
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 get title {
|
|
return Intl.message(
|
|
r'Title',
|
|
locale: _localeName,
|
|
name: 'title',
|
|
desc: r'Title for the application'
|
|
);
|
|
}
|
|
''');
|
|
});
|
|
|
|
test('correctly generates simple message method with parameters', () {
|
|
const String singleSimpleMessageWithPlaceholderArbFileString = '''{
|
|
"itemNumber": "Item {value}",
|
|
"@itemNumber": {
|
|
"description": "Item placement in list.",
|
|
"placeholders": {
|
|
"value": {
|
|
"example": "1"
|
|
}
|
|
}
|
|
}
|
|
}''';
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile(defaultTemplateArbFileName)
|
|
.writeAsStringSync(singleSimpleMessageWithPlaceholderArbFileString);
|
|
|
|
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 itemNumber(Object value) {
|
|
return Intl.message(
|
|
r\'Item \$value\',
|
|
locale: _localeName,
|
|
name: 'itemNumber',
|
|
desc: r\'Item placement in list.\',
|
|
args: <Object>[value]
|
|
);
|
|
}
|
|
''');
|
|
});
|
|
|
|
group('DateTime tests', () {
|
|
test('correctly generates simple message with dates', () {
|
|
const String singleDateMessageArbFileString = '''{
|
|
"springBegins": "Spring begins on {springStartDate}",
|
|
"@springBegins": {
|
|
"description": "The first day of spring",
|
|
"placeholders": {
|
|
"springStartDate": {
|
|
"type": "DateTime",
|
|
"format": "yMMMMEEEEd"
|
|
}
|
|
}
|
|
}
|
|
}''';
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile(defaultTemplateArbFileName)
|
|
.writeAsStringSync(singleDateMessageArbFileString);
|
|
|
|
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 springBegins(Object springStartDate) {
|
|
final DateFormat springStartDateDateFormat = DateFormat.yMMMMEEEEd(_localeName);
|
|
final String springStartDateString = springStartDateDateFormat.format(springStartDate);
|
|
|
|
return Intl.message(
|
|
r'Spring begins on \$springStartDateString',
|
|
locale: _localeName,
|
|
name: 'springBegins',
|
|
desc: r'The first day of spring',
|
|
args: <Object>[springStartDateString]
|
|
);
|
|
}
|
|
''');
|
|
});
|
|
|
|
test('throws an exception when improperly formatted date is passed in', () {
|
|
const String singleDateMessageArbFileString = '''{
|
|
"springBegins": "Spring begins on {springStartDate}",
|
|
"@springBegins": {
|
|
"description": "The first day of spring",
|
|
"placeholders": {
|
|
"springStartDate": {
|
|
"type": "DateTime",
|
|
"format": "asdf"
|
|
}
|
|
}
|
|
}
|
|
}''';
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile(defaultTemplateArbFileName)
|
|
.writeAsStringSync(singleDateMessageArbFileString);
|
|
|
|
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
|
|
try {
|
|
generator.initialize(
|
|
l10nDirectoryPath: defaultArbPathString,
|
|
templateArbFileName: defaultTemplateArbFileName,
|
|
outputFileString: defaultOutputFileString,
|
|
classNameString: defaultClassNameString,
|
|
);
|
|
generator.parseArbFiles();
|
|
generator.generateClassMethods();
|
|
} on L10nException catch (e) {
|
|
expect(e.message, contains('asdf'));
|
|
expect(e.message, contains('springStartDate'));
|
|
expect(e.message, contains('does not have a corresponding DateFormat'));
|
|
return;
|
|
}
|
|
|
|
fail('Improper date formatting should throw an exception');
|
|
});
|
|
|
|
test('throws an exception when no format attribute is passed in', () {
|
|
const String singleDateMessageArbFileString = '''{
|
|
"springBegins": "Spring begins on {springStartDate}",
|
|
"@springBegins": {
|
|
"description": "The first day of spring",
|
|
"placeholders": {
|
|
"springStartDate": {
|
|
"type": "DateTime"
|
|
}
|
|
}
|
|
}
|
|
}''';
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile(defaultTemplateArbFileName)
|
|
.writeAsStringSync(singleDateMessageArbFileString);
|
|
|
|
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
|
|
try {
|
|
generator.initialize(
|
|
l10nDirectoryPath: defaultArbPathString,
|
|
templateArbFileName: defaultTemplateArbFileName,
|
|
outputFileString: defaultOutputFileString,
|
|
classNameString: defaultClassNameString,
|
|
);
|
|
generator.parseArbFiles();
|
|
generator.generateClassMethods();
|
|
} on L10nException catch (e) {
|
|
expect(e.message, contains('the "format" attribute needs to be set'));
|
|
return;
|
|
}
|
|
|
|
fail('Improper date formatting should throw an exception');
|
|
});
|
|
|
|
test('correctly generates simple message with date along with other placeholders', () {
|
|
const String singleDateMessageArbFileString = '''{
|
|
"springGreetings": "Since it's {springStartDate}, it's finally spring! {helloWorld}!",
|
|
"@springGreetings": {
|
|
"description": "A realization that it's finally the spring season, followed by a greeting.",
|
|
"placeholders": {
|
|
"springStartDate": {
|
|
"type": "DateTime",
|
|
"format": "yMMMMEEEEd"
|
|
},
|
|
"helloWorld": {}
|
|
}
|
|
}
|
|
}''';
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile(defaultTemplateArbFileName)
|
|
.writeAsStringSync(singleDateMessageArbFileString);
|
|
|
|
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 springGreetings(Object springStartDate, Object helloWorld) {
|
|
final DateFormat springStartDateDateFormat = DateFormat.yMMMMEEEEd(_localeName);
|
|
final String springStartDateString = springStartDateDateFormat.format(springStartDate);
|
|
|
|
return Intl.message(
|
|
r\'Since it\' "\'" r\'s \$springStartDateString, it\' "\'" r\'s finally spring! \$helloWorld!\',
|
|
locale: _localeName,
|
|
name: 'springGreetings',
|
|
desc: r\'A realization that it\' "\'" r\'s finally the spring season, followed by a greeting.\',
|
|
args: <Object>[springStartDateString, helloWorld]
|
|
);
|
|
}
|
|
''');
|
|
});
|
|
|
|
test('correctly generates simple message with multiple dates', () {
|
|
const String singleDateMessageArbFileString = '''{
|
|
"springRange": "Spring begins on {springStartDate} and ends on {springEndDate}",
|
|
"@springRange": {
|
|
"description": "The range of dates for spring in the year",
|
|
"placeholders": {
|
|
"springStartDate": {
|
|
"type": "DateTime",
|
|
"format": "yMMMMEEEEd"
|
|
},
|
|
"springEndDate": {
|
|
"type": "DateTime",
|
|
"format": "yMMMMEEEEd"
|
|
}
|
|
}
|
|
}
|
|
}''';
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile(defaultTemplateArbFileName)
|
|
.writeAsStringSync(singleDateMessageArbFileString);
|
|
|
|
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 springRange(Object springStartDate, Object springEndDate) {
|
|
final DateFormat springStartDateDateFormat = DateFormat.yMMMMEEEEd(_localeName);
|
|
final String springStartDateString = springStartDateDateFormat.format(springStartDate);
|
|
|
|
final DateFormat springEndDateDateFormat = DateFormat.yMMMMEEEEd(_localeName);
|
|
final String springEndDateString = springEndDateDateFormat.format(springEndDate);
|
|
|
|
return Intl.message(
|
|
r\'Spring begins on \$springStartDateString and ends on \$springEndDateString\',
|
|
locale: _localeName,
|
|
name: 'springRange',
|
|
desc: r\'The range of dates for spring in the year\',
|
|
args: <Object>[springStartDateString, springEndDateString]
|
|
);
|
|
}
|
|
''');
|
|
});
|
|
|
|
test('correctly generates a plural message with DateTime placeholders', () {
|
|
const String pluralMessageWithDateTimePlaceholder = '''{
|
|
"helloWorlds": "{count,plural, =1{Hello World, today is {currentDate}}=2{Hello two worlds, today is {currentDate}}many{Hello all {count} worlds, today is {currentDate}}other{Hello other {count} worlds, today is {currentDate}}}",
|
|
"@helloWorlds": {
|
|
"placeholders": {
|
|
"count": {},
|
|
"currentDate": {
|
|
"type": "DateTime",
|
|
"format": "yMMMMEEEEd"
|
|
}
|
|
}
|
|
}
|
|
}''';
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile(defaultTemplateArbFileName)
|
|
.writeAsStringSync(pluralMessageWithDateTimePlaceholder);
|
|
|
|
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 helloWorlds(int count, Object currentDate) {
|
|
final DateFormat currentDateDateFormat = DateFormat.yMMMMEEEEd(_localeName);
|
|
final String currentDateString = currentDateDateFormat.format(currentDate);
|
|
|
|
return Intl.plural(
|
|
count,
|
|
locale: _localeName,
|
|
name: 'helloWorlds',
|
|
args: <Object>[count, currentDateString],
|
|
one: 'Hello World, today is \$currentDateString',
|
|
two: 'Hello two worlds, today is \$currentDateString',
|
|
many: 'Hello all \$count worlds, today is \$currentDateString',
|
|
other: 'Hello other \$count worlds, today is \$currentDateString'
|
|
);
|
|
}
|
|
'''
|
|
);
|
|
});
|
|
});
|
|
|
|
group('Number tests', () {
|
|
test('correctly generates simple message with numbers', () {
|
|
const 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": "percentPattern"
|
|
}
|
|
}
|
|
}
|
|
}''';
|
|
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.percentPattern(
|
|
locale: _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('correctly adds optional parameters to numbers', () {
|
|
const 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",
|
|
"optionalParameters": {
|
|
"decimalDigits": 2
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}''';
|
|
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(
|
|
locale: _localeName,
|
|
decimalDigits: 2,
|
|
);
|
|
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', () {
|
|
const String singleDateMessageArbFileString = '''{
|
|
"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": "asdf"
|
|
}
|
|
}
|
|
}
|
|
}''';
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile(defaultTemplateArbFileName)
|
|
.writeAsStringSync(singleDateMessageArbFileString);
|
|
|
|
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
|
|
try {
|
|
generator.initialize(
|
|
l10nDirectoryPath: defaultArbPathString,
|
|
templateArbFileName: defaultTemplateArbFileName,
|
|
outputFileString: defaultOutputFileString,
|
|
classNameString: defaultClassNameString,
|
|
);
|
|
generator.parseArbFiles();
|
|
generator.generateClassMethods();
|
|
} on L10nException catch (e) {
|
|
expect(e.message, contains('asdf'));
|
|
expect(e.message, contains('progress'));
|
|
expect(e.message, contains('does not have a corresponding NumberFormat'));
|
|
return;
|
|
}
|
|
|
|
fail('Improper date formatting should throw an exception');
|
|
});
|
|
});
|
|
|
|
group('plural messages', () {
|
|
test('correctly generates a plural message', () {
|
|
const String singlePluralMessageArbFileString = '''{
|
|
"helloWorlds": "{count,plural, =0{Hello}=1{Hello World}=2{Hello two worlds}few{Hello {count} worlds}many{Hello all {count} worlds}other{Hello other {count} worlds}}",
|
|
"@helloWorlds": {
|
|
"placeholders": {
|
|
"count": {}
|
|
}
|
|
}
|
|
}''';
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile(defaultTemplateArbFileName)
|
|
.writeAsStringSync(singlePluralMessageArbFileString);
|
|
|
|
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 helloWorlds(int count) {
|
|
return Intl.plural(
|
|
count,
|
|
locale: _localeName,
|
|
name: 'helloWorlds',
|
|
args: <Object>[count],
|
|
zero: 'Hello',
|
|
one: 'Hello World',
|
|
two: 'Hello two worlds',
|
|
few: 'Hello \$count worlds',
|
|
many: 'Hello all \$count worlds',
|
|
other: 'Hello other \$count worlds'
|
|
);
|
|
}
|
|
'''
|
|
);
|
|
});
|
|
|
|
test('correctly generates a plural message with placeholders', () {
|
|
const String pluralMessageWithMultiplePlaceholders = '''{
|
|
"helloWorlds": "{count,plural, =0{Hello}=1{Hello {adjective} World}=2{Hello two {adjective} worlds}few{Hello {count} {adjective} worlds}many{Hello all {count} {adjective} worlds}other{Hello other {count} {adjective} worlds}}",
|
|
"@helloWorlds": {
|
|
"placeholders": {
|
|
"count": {},
|
|
"adjective": {}
|
|
}
|
|
}
|
|
}''';
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile(defaultTemplateArbFileName)
|
|
.writeAsStringSync(pluralMessageWithMultiplePlaceholders);
|
|
|
|
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 helloWorlds(int count, Object adjective) {
|
|
return Intl.plural(
|
|
count,
|
|
locale: _localeName,
|
|
name: 'helloWorlds',
|
|
args: <Object>[count, adjective],
|
|
zero: 'Hello',
|
|
one: 'Hello \$adjective World',
|
|
two: 'Hello two \$adjective worlds',
|
|
few: 'Hello \$count \$adjective worlds',
|
|
many: 'Hello all \$count \$adjective worlds',
|
|
other: 'Hello other \$count \$adjective worlds'
|
|
);
|
|
}
|
|
'''
|
|
);
|
|
});
|
|
|
|
test('correctly generates a plural message with DateTime placeholders', () {
|
|
const String pluralMessageWithDateTimePlaceholder = '''{
|
|
"helloWorlds": "{count,plural, =1{Hello World, today is {currentDate}}=2{Hello two worlds, today is {currentDate}}many{Hello all {count} worlds, today is {currentDate}}other{Hello other {count} worlds, today is {currentDate}}}",
|
|
"@helloWorlds": {
|
|
"placeholders": {
|
|
"count": {},
|
|
"currentDate": {
|
|
"type": "DateTime",
|
|
"format": "yMMMMEEEEd"
|
|
}
|
|
}
|
|
}
|
|
}''';
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile(defaultTemplateArbFileName)
|
|
.writeAsStringSync(pluralMessageWithDateTimePlaceholder);
|
|
|
|
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 helloWorlds(int count, Object currentDate) {
|
|
final DateFormat currentDateDateFormat = DateFormat.yMMMMEEEEd(_localeName);
|
|
final String currentDateString = currentDateDateFormat.format(currentDate);
|
|
|
|
return Intl.plural(
|
|
count,
|
|
locale: _localeName,
|
|
name: 'helloWorlds',
|
|
args: <Object>[count, currentDateString],
|
|
one: 'Hello World, today is \$currentDateString',
|
|
two: 'Hello two worlds, today is \$currentDateString',
|
|
many: 'Hello all \$count worlds, today is \$currentDateString',
|
|
other: 'Hello other \$count worlds, today is \$currentDateString'
|
|
);
|
|
}
|
|
'''
|
|
);
|
|
});
|
|
|
|
test('correctly generates a plural message with number placeholders', () {
|
|
const String pluralMessageWithDateTimePlaceholder = '''{
|
|
"helloWorlds": "{count,plural, =1{Hello World of {population} citizens}=2{Hello two worlds with {population} total citizens}many{Hello all {count} worlds, with a total of {population} citizens}other{Hello other {count} worlds, with a total of {population} citizens}}",
|
|
"@helloWorlds": {
|
|
"placeholders": {
|
|
"count": {},
|
|
"population": {
|
|
"type": "Number",
|
|
"format": "compactLong"
|
|
}
|
|
}
|
|
}
|
|
}''';
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile(defaultTemplateArbFileName)
|
|
.writeAsStringSync(pluralMessageWithDateTimePlaceholder);
|
|
|
|
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 helloWorlds(int count, Object population) {
|
|
final NumberFormat populationNumberFormat = NumberFormat.compactLong(
|
|
locale: _localeName,
|
|
);
|
|
final String populationString = populationNumberFormat.format(population);
|
|
|
|
return Intl.plural(
|
|
count,
|
|
locale: _localeName,
|
|
name: 'helloWorlds',
|
|
args: <Object>[count, populationString],
|
|
one: 'Hello World of \$populationString citizens',
|
|
two: 'Hello two worlds with \$populationString total citizens',
|
|
many: 'Hello all \$count worlds, with a total of \$populationString citizens',
|
|
other: 'Hello other \$count worlds, with a total of \$populationString citizens'
|
|
);
|
|
}
|
|
'''
|
|
);
|
|
});
|
|
|
|
test('should throw attempting to generate a plural message without placeholders', () {
|
|
const String pluralMessageWithoutPlaceholdersAttribute = '''{
|
|
"helloWorlds": "{count,plural, =0{Hello}=1{Hello World}=2{Hello two worlds}few{Hello {count} worlds}many{Hello all {count} worlds}other{Hello other {count} worlds}}",
|
|
"@helloWorlds": {
|
|
"description": "Improperly formatted since it has no placeholder attribute."
|
|
}
|
|
}''';
|
|
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile(defaultTemplateArbFileName)
|
|
.writeAsStringSync(pluralMessageWithoutPlaceholdersAttribute);
|
|
|
|
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
|
|
try {
|
|
generator.initialize(
|
|
l10nDirectoryPath: defaultArbPathString,
|
|
templateArbFileName: defaultTemplateArbFileName,
|
|
outputFileString: defaultOutputFileString,
|
|
classNameString: defaultClassNameString,
|
|
);
|
|
generator.parseArbFiles();
|
|
generator.generateClassMethods();
|
|
} on L10nException catch (e) {
|
|
expect(e.message, contains('Check to see if the plural message is in the proper ICU syntax format'));
|
|
return;
|
|
}
|
|
fail('Generating class methods without placeholders should not succeed');
|
|
});
|
|
|
|
test('should throw attempting to generate a plural message with an empty placeholders map', () {
|
|
const String pluralMessageWithEmptyPlaceholdersMap = '''{
|
|
"helloWorlds": "{count,plural, =0{Hello}=1{Hello World}=2{Hello two worlds}few{Hello {count} worlds}many{Hello all {count} worlds}other{Hello other {count} worlds}}",
|
|
"@helloWorlds": {
|
|
"description": "Improperly formatted since it has no placeholder attribute.",
|
|
"placeholders": {}
|
|
}
|
|
}''';
|
|
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile(defaultTemplateArbFileName)
|
|
.writeAsStringSync(pluralMessageWithEmptyPlaceholdersMap);
|
|
|
|
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
|
|
try {
|
|
generator.initialize(
|
|
l10nDirectoryPath: defaultArbPathString,
|
|
templateArbFileName: defaultTemplateArbFileName,
|
|
outputFileString: defaultOutputFileString,
|
|
classNameString: defaultClassNameString,
|
|
);
|
|
generator.parseArbFiles();
|
|
generator.generateClassMethods();
|
|
} on L10nException catch (e) {
|
|
expect(e.message, contains('Check to see if the plural message is in the proper ICU syntax format'));
|
|
return;
|
|
}
|
|
fail('Generating class methods without placeholders should not succeed');
|
|
});
|
|
|
|
test('should throw attempting to generate a plural message with no resource attributes', () {
|
|
const String pluralMessageWithoutResourceAttributes = '''{
|
|
"helloWorlds": "{count,plural, =0{Hello}=1{Hello World}=2{Hello two worlds}few{Hello {count} worlds}many{Hello all {count} worlds}other{Hello other {count} worlds}}"
|
|
}''';
|
|
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile(defaultTemplateArbFileName)
|
|
.writeAsStringSync(pluralMessageWithoutResourceAttributes);
|
|
|
|
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
|
|
try {
|
|
generator.initialize(
|
|
l10nDirectoryPath: defaultArbPathString,
|
|
templateArbFileName: defaultTemplateArbFileName,
|
|
outputFileString: defaultOutputFileString,
|
|
classNameString: defaultClassNameString,
|
|
);
|
|
generator.parseArbFiles();
|
|
generator.generateClassMethods();
|
|
} on L10nException catch (e) {
|
|
expect(e.message, contains('Resource attribute'));
|
|
expect(e.message, contains('does not exist'));
|
|
return;
|
|
}
|
|
fail('Generating plural class method without resource attributes should not succeed');
|
|
});
|
|
|
|
test('should throw attempting to generate a plural message with incorrect format for placeholders', () {
|
|
const String pluralMessageWithIncorrectPlaceholderFormat = '''{
|
|
"helloWorlds": "{count,plural, =0{Hello}=1{Hello World}=2{Hello two worlds}few{Hello {count} worlds}many{Hello all {count} worlds}other{Hello other {count} worlds}}",
|
|
"@helloWorlds": {
|
|
"placeholders": "Incorrectly a string, should be a map."
|
|
}
|
|
}''';
|
|
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile(defaultTemplateArbFileName)
|
|
.writeAsStringSync(pluralMessageWithIncorrectPlaceholderFormat);
|
|
|
|
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
|
|
try {
|
|
generator.initialize(
|
|
l10nDirectoryPath: defaultArbPathString,
|
|
templateArbFileName: defaultTemplateArbFileName,
|
|
outputFileString: defaultOutputFileString,
|
|
classNameString: defaultClassNameString,
|
|
);
|
|
generator.parseArbFiles();
|
|
generator.generateClassMethods();
|
|
} on L10nException catch (e) {
|
|
expect(e.message, contains('is not properly formatted'));
|
|
expect(e.message, contains('Ensure that it is a map with keys that are strings'));
|
|
return;
|
|
}
|
|
fail('Generating class methods with incorrect placeholder format should not succeed');
|
|
});
|
|
});
|
|
|
|
test('should throw when failing to parse the arb file', () {
|
|
const String arbFileWithTrailingComma = '''{
|
|
"title": "Stocks",
|
|
"@title": {
|
|
"description": "Title for the Stocks application"
|
|
},
|
|
}''';
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile(defaultTemplateArbFileName)
|
|
.writeAsStringSync(arbFileWithTrailingComma);
|
|
|
|
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
|
|
try {
|
|
generator.initialize(
|
|
l10nDirectoryPath: defaultArbPathString,
|
|
templateArbFileName: defaultTemplateArbFileName,
|
|
outputFileString: defaultOutputFileString,
|
|
classNameString: defaultClassNameString,
|
|
);
|
|
generator.parseArbFiles();
|
|
generator.generateClassMethods();
|
|
} on FormatException catch (e) {
|
|
expect(e.message, contains('Unexpected character'));
|
|
return;
|
|
}
|
|
|
|
fail(
|
|
'should fail with a FormatException due to a trailing comma in the '
|
|
'arb file.'
|
|
);
|
|
});
|
|
|
|
test('should throw when resource is missing resource attribute', () {
|
|
const String arbFileWithMissingResourceAttribute = '''{
|
|
"title": "Stocks"
|
|
}''';
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile(defaultTemplateArbFileName)
|
|
.writeAsStringSync(arbFileWithMissingResourceAttribute);
|
|
|
|
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
|
|
try {
|
|
generator.initialize(
|
|
l10nDirectoryPath: defaultArbPathString,
|
|
templateArbFileName: defaultTemplateArbFileName,
|
|
outputFileString: defaultOutputFileString,
|
|
classNameString: defaultClassNameString,
|
|
);
|
|
generator.parseArbFiles();
|
|
generator.generateClassMethods();
|
|
} on L10nException catch (e) {
|
|
expect(e.message, contains('Resource attribute "@title" was not found'));
|
|
return;
|
|
}
|
|
|
|
fail(
|
|
'should fail with a FormatException due to a trailing comma in the '
|
|
'arb file.'
|
|
);
|
|
});
|
|
|
|
group('checks for method/getter formatting', () {
|
|
test('cannot contain non-alphanumeric symbols', () {
|
|
const String nonAlphaNumericArbFile = '''{
|
|
"title!!": "Stocks",
|
|
"@title!!": {
|
|
"description": "Title for the Stocks application"
|
|
}
|
|
}''';
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile(defaultTemplateArbFileName)
|
|
.writeAsStringSync(nonAlphaNumericArbFile);
|
|
|
|
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
|
|
try {
|
|
generator.initialize(
|
|
l10nDirectoryPath: defaultArbPathString,
|
|
templateArbFileName: defaultTemplateArbFileName,
|
|
outputFileString: defaultOutputFileString,
|
|
classNameString: defaultClassNameString,
|
|
);
|
|
generator.parseArbFiles();
|
|
generator.generateClassMethods();
|
|
} on L10nException catch (e) {
|
|
expect(e.message, contains('Invalid key format'));
|
|
return;
|
|
}
|
|
|
|
fail('should fail due to non-alphanumeric character.');
|
|
});
|
|
|
|
test('must start with lowercase character', () {
|
|
const String nonAlphaNumericArbFile = '''{
|
|
"Title": "Stocks",
|
|
"@Title": {
|
|
"description": "Title for the Stocks application"
|
|
}
|
|
}''';
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile(defaultTemplateArbFileName)
|
|
.writeAsStringSync(nonAlphaNumericArbFile);
|
|
|
|
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
|
|
try {
|
|
generator.initialize(
|
|
l10nDirectoryPath: defaultArbPathString,
|
|
templateArbFileName: defaultTemplateArbFileName,
|
|
outputFileString: defaultOutputFileString,
|
|
classNameString: defaultClassNameString,
|
|
);
|
|
generator.parseArbFiles();
|
|
generator.generateClassMethods();
|
|
} on L10nException catch (e) {
|
|
expect(e.message, contains('Invalid key format'));
|
|
return;
|
|
}
|
|
|
|
fail('should fail since key starts with a non-lowercase.');
|
|
});
|
|
|
|
test('cannot start with a number', () {
|
|
const String nonAlphaNumericArbFile = '''{
|
|
"123title": "Stocks",
|
|
"@123title": {
|
|
"description": "Title for the Stocks application"
|
|
}
|
|
}''';
|
|
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
|
..createSync(recursive: true);
|
|
l10nDirectory.childFile(defaultTemplateArbFileName)
|
|
.writeAsStringSync(nonAlphaNumericArbFile);
|
|
|
|
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
|
|
try {
|
|
generator.initialize(
|
|
l10nDirectoryPath: defaultArbPathString,
|
|
templateArbFileName: defaultTemplateArbFileName,
|
|
outputFileString: defaultOutputFileString,
|
|
classNameString: defaultClassNameString,
|
|
);
|
|
generator.parseArbFiles();
|
|
generator.generateClassMethods();
|
|
} on L10nException catch (e) {
|
|
expect(e.message, contains('Invalid key format'));
|
|
return;
|
|
}
|
|
|
|
fail('should fail since key starts with a number.');
|
|
});
|
|
});
|
|
});
|
|
|
|
group('generateOutputFile', () {
|
|
test('correctly generates the localizations classes', () {
|
|
_standardFlutterDirectoryL10nSetup(fs);
|
|
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
|
|
try {
|
|
generator.initialize(
|
|
l10nDirectoryPath: defaultArbPathString,
|
|
templateArbFileName: defaultTemplateArbFileName,
|
|
outputFileString: defaultOutputFileString,
|
|
classNameString: defaultClassNameString,
|
|
);
|
|
generator.parseArbFiles();
|
|
generator.generateClassMethods();
|
|
generator.generateOutputFile();
|
|
} on Exception catch (e) {
|
|
fail('Generating output localization file should succeed: \n$e');
|
|
}
|
|
|
|
final String outputFileString = generator.outputFile.readAsStringSync();
|
|
expect(outputFileString, contains('class AppLocalizations'));
|
|
expect(outputFileString, contains('class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations>'));
|
|
});
|
|
});
|
|
}
|