| // 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<void> 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<String>(_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]); | |
| } |