| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| /// This program extracts localized date symbols and patterns from the intl |
| /// package for the subset of locales supported by the flutter_localizations |
| /// package. |
| /// |
| /// The extracted data is written into: |
| /// packages/flutter_localizations/lib/src/l10n/date_localizations.dart |
| /// |
| /// ## Usage |
| /// |
| /// Run this program from the root of the git repository. |
| /// |
| /// The following outputs the generated Dart code to the console as a dry run: |
| /// |
| /// ``` |
| /// dart dev/tools/gen_date_localizations.dart |
| /// ``` |
| /// |
| /// If the data looks good, use the `--overwrite` option to overwrite the |
| /// lib/src/l10n/date_localizations.dart file: |
| /// |
| /// ``` |
| /// dart dev/tools/gen_date_localizations.dart --overwrite |
| /// ``` |
| |
| import 'dart:async'; |
| import 'dart:convert'; |
| import 'dart:io'; |
| |
| import 'package:path/path.dart' as path; |
| |
| import 'localizations_utils.dart'; |
| |
| const String _kCommandName = 'gen_date_localizations.dart'; |
| |
| Future<Null> main(List<String> rawArgs) async { |
| checkCwdIsRepoRoot(_kCommandName); |
| |
| final bool writeToFile = parseArgs(rawArgs).writeToFile; |
| |
| final File dotPackagesFile = File(path.join('packages', 'flutter_localizations', '.packages')); |
| final bool dotPackagesExists = dotPackagesFile.existsSync(); |
| |
| if (!dotPackagesExists) { |
| exitWithError( |
| 'File not found: ${dotPackagesFile.path}. $_kCommandName must be run ' |
| 'after a successful "flutter update-packages".' |
| ); |
| } |
| |
| final String pathToIntl = dotPackagesFile |
| .readAsStringSync() |
| .split('\n') |
| .firstWhere( |
| (String line) => line.startsWith('intl:'), |
| orElse: () { |
| exitWithError('intl dependency not found in ${dotPackagesFile.path}'); |
| return null; // unreachable |
| }, |
| ) |
| .split(':') |
| .last; |
| |
| final Directory dateSymbolsDirectory = Directory(path.join(pathToIntl, 'src', 'data', 'dates', 'symbols')); |
| final Map<String, File> symbolFiles = _listIntlData(dateSymbolsDirectory); |
| final Directory datePatternsDirectory = Directory(path.join(pathToIntl, 'src', 'data', 'dates', 'patterns')); |
| final Map<String, File> patternFiles = _listIntlData(datePatternsDirectory); |
| final List<String> materialLocales = _materialLocales().toList(); |
| final StringBuffer buffer = StringBuffer(); |
| |
| buffer.writeln( |
| ''' |
| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // This file has been automatically generated. Please do not edit it manually. |
| // To regenerate run (omit --overwrite to print to console instead of the file): |
| // dart --enable-asserts dev/tools/gen_date_localizations.dart --overwrite |
| |
| // ignore_for_file: public_member_api_docs |
| ''' |
| ); |
| buffer.writeln('const Map<String, dynamic> dateSymbols = <String, dynamic> {'); |
| symbolFiles.forEach((String locale, File data) { |
| if (materialLocales.contains(locale)) |
| buffer.writeln(_jsonToMapEntry(locale, json.decode(data.readAsStringSync()))); |
| }); |
| buffer.writeln('};'); |
| |
| // Code that uses datePatterns expects it to contain values of type |
| // Map<String, String> not Map<String, dynamic>. |
| buffer.writeln('const Map<String, Map<String, String>> datePatterns = <String, Map<String, String>> {'); |
| patternFiles.forEach((String locale, File data) { |
| if (materialLocales.contains(locale)) { |
| final Map<String, dynamic> patterns = json.decode(data.readAsStringSync()); |
| buffer.writeln("'$locale': <String, String>{"); |
| patterns.forEach((String key, dynamic value) { |
| assert(value is String); |
| buffer.writeln(_jsonToMapEntry(key, value)); |
| }); |
| buffer.writeln('},'); |
| } |
| }); |
| buffer.writeln('};'); |
| |
| if (writeToFile) { |
| final File dateLocalizationsFile = File(path.join('packages', 'flutter_localizations', 'lib', 'src', 'l10n', 'date_localizations.dart')); |
| dateLocalizationsFile.writeAsStringSync(buffer.toString()); |
| Process.runSync(path.join('bin', 'cache', 'dart-sdk', 'bin', 'dartfmt'), <String>[ |
| '-w', |
| dateLocalizationsFile.path, |
| ]); |
| } else { |
| print(buffer); |
| } |
| } |
| |
| String _jsonToMapEntry(String key, dynamic value) { |
| return "'$key': ${_jsonToMap(value)},"; |
| } |
| |
| String _jsonToMap(dynamic json) { |
| if (json == null || json is num || json is bool) |
| return '$json'; |
| |
| if (json is String) { |
| if (json.contains("'")) |
| return 'r"""$json"""'; |
| else |
| return "r'''$json'''"; |
| } |
| |
| if (json is Iterable) |
| return '<dynamic>[${json.map(_jsonToMap).join(',')}]'; |
| |
| if (json is Map<String, dynamic>) { |
| final StringBuffer buffer = StringBuffer('<String, dynamic>{'); |
| json.forEach((String key, dynamic value) { |
| buffer.writeln(_jsonToMapEntry(key, value)); |
| }); |
| buffer.write('}'); |
| return buffer.toString(); |
| } |
| |
| throw 'Unsupported JSON type ${json.runtimeType} of value $json.'; |
| } |
| |
| Iterable<String> _materialLocales() sync* { |
| final RegExp filenameRE = RegExp(r'material_(\w+)\.arb$'); |
| final Directory materialLocalizationsDirectory = Directory(path.join('packages', 'flutter_localizations', 'lib', 'src', 'l10n')); |
| for (FileSystemEntity entity in materialLocalizationsDirectory.listSync()) { |
| final String filePath = entity.path; |
| if (FileSystemEntity.isFileSync(filePath) && filenameRE.hasMatch(filePath)) |
| yield filenameRE.firstMatch(filePath)[1]; |
| } |
| } |
| |
| Map<String, File> _listIntlData(Directory directory) { |
| final Map<String, File> localeFiles = <String, File>{}; |
| for (FileSystemEntity entity in directory.listSync()) { |
| final String filePath = entity.path; |
| if (FileSystemEntity.isFileSync(filePath) && filePath.endsWith('.json')) { |
| final String locale = path.basenameWithoutExtension(filePath); |
| localeFiles[locale] = entity; |
| } |
| } |
| |
| final List<String> locales = localeFiles.keys.toList(growable: false); |
| locales.sort(); |
| return Map<String, File>.fromIterable(locales, value: (dynamic locale) => localeFiles[locale]); |
| } |