generate_localizations.dart 9 KB
Newer Older
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
// 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 '../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({
    FileSystem fileSystem,
  }) :
    _fileSystem = fileSystem {
    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\n'
        'messages have not been translated yet. Using this option will create\n'
        '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\n'
        '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.',
    );
68
    argParser.addMultiOption(
69
      'preferred-supported-locales',
70
      valueHelp: 'locale',
71 72 73 74
      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. \n\n'
75 76 77
        'For example, pass in `en_US` if you would like your app to '
        'default to American English if a device supports it.'
        '(Pass this option multiple times for defining multiple items',
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
    );
    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',
      defaultsTo: false,
      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'
        'Note that 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.'
    );
  }

  final FileSystem _fileSystem;

  @override
158
  String get description => 'Generate localizations for the current project.';
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173

  @override
  String get name => 'gen-l10n';

  @override
  Future<FlutterCommandResult> runCommand() async {

    precacheLanguageAndRegionTags();

    final String inputPathString = stringArg('arb-dir');
    final String outputPathString = stringArg('output-dir');
    final String outputFileString = stringArg('output-localization-file');
    final String templateArbFileName = stringArg('template-arb-file');
    final String untranslatedMessagesFile = stringArg('untranslated-messages-file');
    final String classNameString = stringArg('output-class');
174
    final List<String> preferredSupportedLocale = stringsArg('preferred-supported-locales');
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
    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 LocalizationsGenerator localizationsGenerator = LocalizationsGenerator(_fileSystem);

    try {
      localizationsGenerator
        ..initialize(
          inputPathString: inputPathString,
          outputPathString: outputPathString,
          templateArbFileName: templateArbFileName,
          outputFileString: outputFileString,
          classNameString: classNameString,
192
          preferredSupportedLocale: preferredSupportedLocale,
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
          headerString: headerString,
          headerFile: headerFile,
          useDeferredLoading: useDeferredLoading,
          inputsAndOutputsListPath: inputsAndOutputsListPath,
          useSyntheticPackage: useSyntheticPackage,
          projectPathString: projectPathString,
        )
        ..loadResources()
        ..writeOutputFiles()
        ..outputUnimplementedMessages(untranslatedMessagesFile, globals.logger);
    } on L10nException catch (e) {
      throwToolExit(e.message);
    }

    return FlutterCommandResult.success();
  }
}