flutter_flutter/dev/tools/localization/bin/encode_kn_arb_files.dart
Kate Lovett a04fb324be
Bump Dart to 3.8 and reformat (#171703)
Bumps the Dart version to 3.8 across the repo (excluding
engine/src/flutter/third_party) and applies formatting updates from Dart
3.8.

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [ ] I listed at least one issue that this PR fixes in the description
above.
- [ ] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
2025-07-07 17:58:32 +00:00

94 lines
3.6 KiB
Dart

// 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.
// The utility function `encodeKnArbFiles` replaces the material_kn.arb
// and cupertino_kn.arb files in flutter_localizations/packages/lib/src/l10n
// with versions where the contents of the localized strings have been
// replaced by JSON escapes. This is done because some of those strings
// contain characters that can crash Emacs on Linux. There is more information
// here: https://github.com/flutter/flutter/issues/36704 and in the README
// in flutter_localizations/packages/lib/src/l10n.
//
// This utility is run by `gen_localizations.dart` if --overwrite is passed
// in as an option.
import 'dart:convert';
import 'dart:io';
import 'package:path/path.dart' as path;
import '../localizations_utils.dart';
Map<String, dynamic> _loadBundle(File file) {
if (!FileSystemEntity.isFileSync(file.path)) {
exitWithError('Unable to find input file: ${file.path}');
}
return json.decode(file.readAsStringSync()) as Map<String, dynamic>;
}
void _encodeBundleTranslations(Map<String, dynamic> bundle) {
for (final String key in bundle.keys) {
// The ARB file resource "attributes" for foo are called @foo. Don't need
// to encode them.
if (key.startsWith('@')) {
continue;
}
final String translation = bundle[key] as String;
// Rewrite the string as a series of unicode characters in JSON format.
// Like "\u0012\u0123\u1234".
bundle[key] = translation.runes.map((int code) {
final String codeString = '00${code.toRadixString(16)}';
return '\\u${codeString.substring(codeString.length - 4)}';
}).join();
}
}
void _checkEncodedTranslations(Map<String, dynamic> encodedBundle, Map<String, dynamic> bundle) {
bool errorFound = false;
const JsonDecoder decoder = JsonDecoder();
for (final String key in bundle.keys) {
if (decoder.convert('"${encodedBundle[key]}"') != bundle[key]) {
stderr.writeln(
' encodedTranslation for $key does not match original value "${bundle[key]}"',
);
errorFound = true;
}
}
if (errorFound) {
exitWithError('JSON unicode translation encoding failed');
}
}
void _rewriteBundle(File file, Map<String, dynamic> bundle) {
final StringBuffer contents = StringBuffer();
contents.writeln('{');
for (final String key in bundle.keys) {
contents.writeln(' "$key": "${bundle[key]}"${key == bundle.keys.last ? '' : ','}');
}
contents.writeln('}');
file.writeAsStringSync(contents.toString());
}
void encodeKnArbFiles(Directory directory) {
final File widgetsArbFile = File(path.join(directory.path, 'widgets_kn.arb'));
final File materialArbFile = File(path.join(directory.path, 'material_kn.arb'));
final File cupertinoArbFile = File(path.join(directory.path, 'cupertino_kn.arb'));
final Map<String, dynamic> widgetsBundle = _loadBundle(widgetsArbFile);
final Map<String, dynamic> materialBundle = _loadBundle(materialArbFile);
final Map<String, dynamic> cupertinoBundle = _loadBundle(cupertinoArbFile);
_encodeBundleTranslations(widgetsBundle);
_encodeBundleTranslations(materialBundle);
_encodeBundleTranslations(cupertinoBundle);
_checkEncodedTranslations(widgetsBundle, _loadBundle(widgetsArbFile));
_checkEncodedTranslations(materialBundle, _loadBundle(materialArbFile));
_checkEncodedTranslations(cupertinoBundle, _loadBundle(cupertinoArbFile));
_rewriteBundle(widgetsArbFile, widgetsBundle);
_rewriteBundle(materialArbFile, materialBundle);
_rewriteBundle(cupertinoArbFile, cupertinoBundle);
}