Unverified Commit 96fd143c authored by Shi-Hao Hong's avatar Shi-Hao Hong Committed by GitHub

[gen_l10n] Optional Headers (#52125)

* Expose --header and --header-file arguments for gen_l10n
parent d5626637
// 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.
......@@ -18,7 +18,7 @@ for more info.
```dart
dart ${FLUTTER_PATH}/dev/tools/localization/bin/gen_l10n.dart --arb-dir=lib/i18n \
--template-arb-file=stocks_en.arb --output-localization-file=stock_strings.dart \
--output-class=StockStrings
--output-class=StockStrings --header-file=header.txt
```
The `StockStrings` class creates a delegate that performs message lookups
......
......@@ -56,6 +56,23 @@ Future<void> main(List<String> arguments) async {
"For example, pass in ['en_US'] if you would like your app to "
'default to American English if a device supports it.',
);
parser.addOption(
'header',
help: 'The header to prepend to the generated Dart localizations '
'files. This option takes in a string. \n\n'
'For example, pass in "/// All localized files." if you would '
'like this string prepended to the generated Dart file. \n\n'
'Alternatively, see the `header-file` option to pass in a text '
'file for longer headers.'
);
parser.addOption(
'header-file',
help: 'The header to prepend to the generated Dart localizations '
'files. The value of this option is the name of the file that '
'contains the header text. \n\n'
'Alternatively, see the `header` option to pass in a string '
'for a simpler header.'
);
final argslib.ArgResults results = parser.parse(arguments);
if (results['help'] == true) {
......@@ -70,6 +87,8 @@ Future<void> main(List<String> arguments) async {
final String templateArbFileName = results['template-arb-file'] as String;
final String classNameString = results['output-class'] as String;
final String preferredSupportedLocaleString = results['preferred-supported-locales'] as String;
final String headerString = results['header'] as String;
final String headerFile = results['header-file'] as String;
const local.LocalFileSystem fs = local.LocalFileSystem();
final LocalizationsGenerator localizationsGenerator = LocalizationsGenerator(fs);
......@@ -82,6 +101,8 @@ Future<void> main(List<String> arguments) async {
outputFileString: outputFileString,
classNameString: classNameString,
preferredSupportedLocaleString: preferredSupportedLocaleString,
headerString: headerString,
headerFile: headerFile,
)
..loadResources()
..writeOutputFile();
......
......@@ -262,7 +262,6 @@ class LocalizationsGenerator {
Iterable<Message> _allMessages;
AppResourceBundleCollection _allBundles;
/// The reference to the project's l10n directory.
///
/// It is assumed that all input files (e.g. [templateArbFile], arb files
......@@ -322,6 +321,9 @@ class LocalizationsGenerator {
/// [l10nDirectory].
final Set<LocaleInfo> supportedLocales = <LocaleInfo>{};
/// The header to be prepended to the generated Dart localization file.
String header = '';
/// Initializes [l10nDirectory], [templateArbFile], [outputFile] and [className].
///
/// Throws an [L10nException] when a provided configuration is not allowed
......@@ -335,11 +337,14 @@ class LocalizationsGenerator {
String outputFileString,
String classNameString,
String preferredSupportedLocaleString,
String headerString,
String headerFile,
}) {
setL10nDirectory(l10nDirectoryPath);
setTemplateArbFile(templateArbFileName);
setOutputFile(outputFileString);
setPreferredSupportedLocales(preferredSupportedLocaleString);
_setHeader(headerString, headerFile);
className = classNameString;
}
......@@ -448,6 +453,28 @@ class LocalizationsGenerator {
}
}
void _setHeader(String headerString, String headerFile) {
if (headerString != null && headerFile != null) {
throw L10nException(
'Cannot accept both header and header file arguments. \n'
'Please make sure to define only one or the other. '
);
}
if (headerString != null) {
header = headerString;
} else if (headerFile != null) {
try {
header = _fs.file(path.join(l10nDirectory.path, headerFile)).readAsStringSync();
} on FileSystemException catch (error) {
throw L10nException (
'Failed to read header file: "$headerFile". \n'
'FileSystemException: ${error.message}'
);
}
}
}
static bool _isValidGetterAndMethodName(String name) {
// Public Dart method name must not start with an underscore
if (name[0] == '_')
......@@ -525,6 +552,7 @@ class LocalizationsGenerator {
final String lookupBody = generateLookupBody(_allBundles, className);
return fileTemplate
.replaceAll('@(header)', header)
.replaceAll('@(class)', className)
.replaceAll('@(methods)', _allMessages.map(generateBaseClassMethod).join('\n'))
.replaceAll('@(importFile)', '$directory/$outputFileName')
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
const String fileTemplate = '''
@(header)
import 'dart:async';
import 'package:flutter/foundation.dart';
......
......@@ -233,6 +233,104 @@ void main() {
});
});
test('correctly adds a headerString when it is set', () {
_standardFlutterDirectoryL10nSetup(fs);
LocalizationsGenerator generator;
try {
generator = LocalizationsGenerator(fs);
generator.initialize(
l10nDirectoryPath: defaultArbPathString,
templateArbFileName: defaultTemplateArbFileName,
outputFileString: defaultOutputFileString,
classNameString: defaultClassNameString,
headerString: '/// Sample header',
);
} on L10nException catch (e) {
fail('Setting a header through a String should not fail: \n${e.message}');
}
expect(generator.header, '/// Sample header');
});
test('correctly adds a headerFile when it is set', () {
fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
..createSync(recursive: true)
..childFile(defaultTemplateArbFileName).writeAsStringSync(singleMessageArbFileString)
..childFile(esArbFileName).writeAsStringSync(singleEsMessageArbFileString)
..childFile('header.txt').writeAsStringSync('/// Sample header in a text file');
LocalizationsGenerator generator;
try {
generator = LocalizationsGenerator(fs);
generator.initialize(
l10nDirectoryPath: defaultArbPathString,
templateArbFileName: defaultTemplateArbFileName,
outputFileString: defaultOutputFileString,
classNameString: defaultClassNameString,
headerFile: 'header.txt',
);
} on L10nException catch (e) {
fail('Setting a header through a file should not fail: \n${e.message}');
}
expect(generator.header, '/// Sample header in a text file');
});
test('setting both a headerString and a headerFile should fail', () {
fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
..createSync(recursive: true)
..childFile(defaultTemplateArbFileName).writeAsStringSync(singleMessageArbFileString)
..childFile(esArbFileName).writeAsStringSync(singleEsMessageArbFileString)
..childFile('header.txt').writeAsStringSync('/// Sample header in a text file');
LocalizationsGenerator generator;
try {
generator = LocalizationsGenerator(fs);
generator.initialize(
l10nDirectoryPath: defaultArbPathString,
templateArbFileName: defaultTemplateArbFileName,
outputFileString: defaultOutputFileString,
classNameString: defaultClassNameString,
headerString: '/// Sample header for localizations file.',
headerFile: 'header.txt',
);
} on L10nException catch (e) {
expect(e.message, contains('Cannot accept both header and header file arguments'));
return;
}
fail('Setting both headerFile and headerString should fail');
});
test('setting a headerFile that does not exist should fail', () {
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
..createSync(recursive: true);
l10nDirectory.childFile(defaultTemplateArbFileName)
.writeAsStringSync(singleMessageArbFileString);
l10nDirectory.childFile(esArbFileName)
.writeAsStringSync(singleEsMessageArbFileString);
l10nDirectory.childFile('header.txt')
.writeAsStringSync('/// Sample header in a text file');
LocalizationsGenerator generator;
try {
generator = LocalizationsGenerator(fs);
generator.initialize(
l10nDirectoryPath: defaultArbPathString,
templateArbFileName: defaultTemplateArbFileName,
outputFileString: defaultOutputFileString,
classNameString: defaultClassNameString,
headerFile: 'header.tx', // Intentionally spelled incorrectly
);
} on L10nException catch (e) {
expect(e.message, contains('Failed to read header file'));
return;
}
fail('Setting headerFile that does not exist should fail');
});
group('loadResources', () {
test('correctly initializes supportedLocales and supportedLanguageCodes properties', () {
_standardFlutterDirectoryL10nSetup(fs);
......@@ -248,7 +346,7 @@ void main() {
);
generator.loadResources();
} on L10nException catch (e) {
fail('Setting language and locales should not fail: \n$e');
fail('Setting language and locales should not fail: \n${e.message}');
}
expect(generator.supportedLocales.contains(LocaleInfo.fromString('en')), true);
......@@ -277,7 +375,7 @@ void main() {
);
generator.loadResources();
} on L10nException catch (e) {
fail('Setting language and locales should not fail: \n$e');
fail('Setting language and locales should not fail: \n${e.message}');
}
expect(generator.supportedLocales.first, LocaleInfo.fromString('en'));
......@@ -308,7 +406,7 @@ void main() {
);
generator.loadResources();
} on L10nException catch (e) {
fail('Setting language and locales should not fail: \n$e');
fail('Setting language and locales should not fail: \n${e.message}');
}
expect(generator.supportedLocales.first, LocaleInfo.fromString('zh'));
......@@ -419,7 +517,7 @@ void main() {
);
generator.loadResources();
} on L10nException catch (e) {
fail('Setting language and locales should not fail: \n$e');
fail('Setting language and locales should not fail: \n${e.message}');
}
if (Platform.isWindows) {
......@@ -470,7 +568,7 @@ void main() {
);
generator.loadResources();
} on L10nException catch (e) {
fail('Setting language and locales should not fail: \n$e');
fail('Setting language and locales should not fail: \n${e.message}');
}
expect(generator.supportedLocales.contains(LocaleInfo.fromString('en')), true);
......@@ -514,7 +612,7 @@ void main() {
);
generator.loadResources();
} on L10nException catch (e) {
fail('Setting language and locales should not fail: \n$e');
fail('Setting language and locales should not fail: \n${e.message}');
}
// @@locale property should hold higher priority
......
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