• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// This program replaces the material_kn.arb and cupertino_kn.arb
6// files in flutter_localizations/packages/lib/src/l10n with versions
7// where the contents of the localized strings have been replaced by JSON
8// escapes. This is done because some of those strings contain characters
9// that can crash Emacs on Linux. There is more information
10// here: https://github.com/flutter/flutter/issues/36704 and in the README
11// in flutter_localizations/packages/lib/src/l10n.
12//
13// This app needs to be run by hand when material_kn.arb or cupertino_kn.arb
14// have been updated.
15//
16// ## Usage
17//
18// Run this program from the root of the git repository.
19//
20// ```
21// dart dev/tools/localization/encode_kn_arb_files.dart
22// ```
23
24import 'dart:async';
25import 'dart:convert';
26import 'dart:io';
27
28import 'package:path/path.dart' as path;
29
30import 'localizations_utils.dart';
31
32Map<String, dynamic> loadBundle(File file) {
33  if (!FileSystemEntity.isFileSync(file.path))
34    exitWithError('Unable to find input file: ${file.path}');
35  return json.decode(file.readAsStringSync());
36}
37
38void encodeBundleTranslations(Map<String, dynamic> bundle) {
39  for (String key in bundle.keys) {
40    // The ARB file resource "attributes" for foo are called @foo. Don't need
41    // to encode them.
42    if (key.startsWith('@'))
43      continue;
44    final String translation = bundle[key];
45    // Rewrite the string as a series of unicode characters in JSON format.
46    // Like "\u0012\u0123\u1234".
47    bundle[key] = translation.runes.map((int code) {
48      final String codeString = '00${code.toRadixString(16)}';
49      return '\\u${codeString.substring(codeString.length - 4)}';
50    }).join();
51  }
52}
53
54void checkEncodedTranslations(Map<String, dynamic> encodedBundle, Map<String, dynamic> bundle) {
55  bool errorFound = false;
56  const JsonDecoder decoder = JsonDecoder();
57  for (String key in bundle.keys) {
58    if (decoder.convert('"${encodedBundle[key]}"') != bundle[key]) {
59      stderr.writeln('  encodedTranslation for $key does not match original value "${bundle[key]}"');
60      errorFound = true;
61    }
62  }
63  if (errorFound)
64    exitWithError('JSON unicode translation encoding failed');
65}
66
67void rewriteBundle(File file, Map<String, dynamic> bundle) {
68  final StringBuffer contents = StringBuffer();
69  contents.writeln('{');
70  for (String key in bundle.keys) {
71    contents.writeln('  "$key": "${bundle[key]}"${key == bundle.keys.last ? '' : ','}');
72  }
73  contents.writeln('}');
74  file.writeAsStringSync(contents.toString());
75}
76
77Future<void> main(List<String> rawArgs) async {
78  checkCwdIsRepoRoot('encode_kn_arb_files');
79
80  final String l10nPath = path.join('packages', 'flutter_localizations', 'lib', 'src', 'l10n');
81  final File materialArbFile = File(path.join(l10nPath, 'material_kn.arb'));
82  final File cupertinoArbFile = File(path.join(l10nPath, 'cupertino_kn.arb'));
83
84  final Map<String, dynamic> materialBundle = loadBundle(materialArbFile);
85  final Map<String, dynamic> cupertinoBundle = loadBundle(cupertinoArbFile);
86
87  encodeBundleTranslations(materialBundle);
88  encodeBundleTranslations(cupertinoBundle);
89
90  checkEncodedTranslations(materialBundle, loadBundle(materialArbFile));
91  checkEncodedTranslations(cupertinoBundle, loadBundle(cupertinoArbFile));
92
93  rewriteBundle(materialArbFile, materialBundle);
94  rewriteBundle(cupertinoArbFile, cupertinoBundle);
95}
96