1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
// 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 '../base/common.dart';
import '../base/file_system.dart';
import '../base/logger.dart';
import '../globals.dart' as globals;
import '../localizations/gen_l10n.dart';
import '../localizations/gen_l10n_types.dart';
import '../localizations/localizations_utils.dart';
import '../runner/flutter_command.dart';
/// A command to generate localizations source files for a Flutter project.
///
/// It generates Dart localization source files from arb files.
///
/// For a more comprehensive tutorial on the tool, please see the
/// [internationalization user guide](flutter.dev/go/i18n-user-guide).
class GenerateLocalizationsCommand extends FlutterCommand {
GenerateLocalizationsCommand({
required FileSystem fileSystem,
required Logger logger,
}) :
_fileSystem = fileSystem,
_logger = logger {
argParser.addOption(
'arb-dir',
defaultsTo: globals.fs.path.join('lib', 'l10n'),
help: 'The directory where the template and translated arb files are located.',
);
argParser.addOption(
'output-dir',
help: 'The directory where the generated localization classes will be written '
'if the synthetic-package flag is set to false.\n'
'\n'
'If output-dir is specified and the synthetic-package flag is enabled, '
'this option will be ignored by the tool.\n'
'\n'
'The app must import the file specified in the "--output-localization-file" '
'option from this directory. If unspecified, this defaults to the same '
'directory as the input directory specified in "--arb-dir".',
);
argParser.addOption(
'template-arb-file',
defaultsTo: 'app_en.arb',
help: 'The template arb file that will be used as the basis for '
'generating the Dart localization and messages files.',
);
argParser.addOption(
'output-localization-file',
defaultsTo: 'app_localizations.dart',
help: 'The filename for the output localization and localizations '
'delegate classes.',
);
argParser.addOption(
'untranslated-messages-file',
help: 'The location of a file that describes the localization '
'messages have not been translated yet. Using this option will create '
'a JSON file at the target location, in the following format:\n'
'\n'
' "locale": ["message_1", "message_2" ... "message_n"]\n'
'\n'
'If this option is not specified, a summary of the messages that '
'have not been translated will be printed on the command line.',
);
argParser.addOption(
'output-class',
defaultsTo: 'AppLocalizations',
help: 'The Dart class name to use for the output localization and '
'localizations delegate classes.',
);
argParser.addMultiOption(
'preferred-supported-locales',
valueHelp: 'locale',
help: 'The list of preferred supported locales for the application. '
'By default, the tool will generate the supported locales list in '
'alphabetical order. Use this flag if you would like to default to '
'a different locale. '
'For example, pass in "en_US" if you would like your app to '
'default to American English on devices that support it. '
'Pass this option multiple times to define multiple items.',
);
argParser.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.'
);
argParser.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 which will be inserted at the top '
'of each generated Dart file.\n'
'\n'
'Alternatively, see the "--header" option to pass in a string '
'for a simpler header.\n'
'\n'
'This file should be placed in the directory specified in "--arb-dir".'
);
argParser.addFlag(
'use-deferred-loading',
help: 'Whether to generate the Dart localization file with locales imported '
'as deferred, allowing for lazy loading of each locale in Flutter web.\n'
'\n'
'This can reduce a web app’s initial startup time by decreasing the '
'size of the JavaScript bundle. When this flag is set to true, the '
'messages for a particular locale are only downloaded and loaded by the '
'Flutter app as they are needed. For projects with a lot of different '
'locales and many localization strings, it can be an performance '
'improvement to have deferred loading. For projects with a small number '
'of locales, the difference is negligible, and might slow down the start '
'up compared to bundling the localizations with the rest of the '
'application.\n'
'\n'
'This flag does not affect other platforms such as mobile or desktop.',
);
argParser.addOption(
'gen-inputs-and-outputs-list',
valueHelp: 'path-to-output-directory',
help: 'When specified, the tool generates a JSON file containing the '
"tool's inputs and outputs named gen_l10n_inputs_and_outputs.json.\n"
'\n'
'This can be useful for keeping track of which files of the Flutter '
'project were used when generating the latest set of localizations. '
"For example, the Flutter tool's build system uses this file to "
'keep track of when to call gen_l10n during hot reload.\n'
'\n'
'The value of this option is the directory where the JSON file will be '
'generated.\n'
'\n'
'When null, the JSON file will not be generated.'
);
argParser.addFlag(
'synthetic-package',
defaultsTo: true,
help: 'Determines whether or not the generated output files will be '
'generated as a synthetic package or at a specified directory in '
'the Flutter project.\n'
'\n'
'This flag is set to true by default.\n'
'\n'
'When synthetic-package is set to false, it will generate the '
'localizations files in the directory specified by arb-dir by default.\n'
'\n'
'If output-dir is specified, files will be generated there.',
);
argParser.addOption(
'project-dir',
valueHelp: 'absolute/path/to/flutter/project',
help: 'When specified, the tool uses the path passed into this option '
'as the directory of the root Flutter project.\n'
'\n'
'When null, the relative path to the present working directory will be used.'
);
argParser.addFlag(
'required-resource-attributes',
help: 'Requires all resource ids to contain a corresponding resource attribute.\n'
'\n'
'By default, simple messages will not require metadata, but it is highly '
'recommended as this provides context for the meaning of a message to '
'readers.\n'
'\n'
'Resource attributes are still required for plural messages.'
);
argParser.addFlag(
'nullable-getter',
help: 'Whether or not the localizations class getter is nullable.\n'
'\n'
'By default, this value is set to true so that '
'Localizations.of(context) returns a nullable value '
'for backwards compatibility. If this value is set to false, then '
'a null check is performed on the returned value of '
'Localizations.of(context), removing the need for null checking in '
'user code.'
);
}
final FileSystem _fileSystem;
final Logger _logger;
@override
String get description => 'Generate localizations for the current project.';
@override
String get name => 'gen-l10n';
@override
String get category => FlutterCommandCategory.project;
@override
Future<FlutterCommandResult> runCommand() async {
if (_fileSystem.file('l10n.yaml').existsSync()) {
final LocalizationOptions options = parseLocalizationsOptions(
file: _fileSystem.file('l10n.yaml'),
logger: _logger,
);
_logger.printStatus(
'Because l10n.yaml exists, the options defined there will be used '
'instead.\n'
'To use the command line arguments, delete the l10n.yaml file in the '
'Flutter project.\n\n'
);
generateLocalizations(
logger: _logger,
options: options,
projectDir: _fileSystem.currentDirectory,
fileSystem: _fileSystem,
);
return FlutterCommandResult.success();
}
final String inputPathString = stringArg('arb-dir')!; // Has default value, cannot be null.
final String? outputPathString = stringArg('output-dir');
final String outputFileString = stringArg('output-localization-file')!; // Has default value, cannot be null.
final String templateArbFileName = stringArg('template-arb-file')!; // Has default value, cannot be null.
final String? untranslatedMessagesFile = stringArg('untranslated-messages-file');
final String classNameString = stringArg('output-class')!; // Has default value, cannot be null.
final List<String> preferredSupportedLocales = stringsArg('preferred-supported-locales');
final String? headerString = stringArg('header');
final String? headerFile = stringArg('header-file');
final bool useDeferredLoading = boolArg('use-deferred-loading');
final String? inputsAndOutputsListPath = stringArg('gen-inputs-and-outputs-list');
final bool useSyntheticPackage = boolArg('synthetic-package');
final String? projectPathString = stringArg('project-dir');
final bool areResourceAttributesRequired = boolArg('required-resource-attributes');
final bool usesNullableGetter = boolArg('nullable-getter');
precacheLanguageAndRegionTags();
try {
LocalizationsGenerator(
fileSystem: _fileSystem,
inputPathString: inputPathString,
outputPathString: outputPathString,
templateArbFileName: templateArbFileName,
outputFileString: outputFileString,
classNameString: classNameString,
preferredSupportedLocales: preferredSupportedLocales,
headerString: headerString,
headerFile: headerFile,
useDeferredLoading: useDeferredLoading,
inputsAndOutputsListPath: inputsAndOutputsListPath,
useSyntheticPackage: useSyntheticPackage,
projectPathString: projectPathString,
areResourceAttributesRequired: areResourceAttributesRequired,
untranslatedMessagesFile: untranslatedMessagesFile,
usesNullableGetter: usesNullableGetter,
)
..loadResources()
..writeOutputFiles(_logger);
} on L10nException catch (e) {
throwToolExit(e.message);
}
return FlutterCommandResult.success();
}
}