mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Rebase ios-experimental branch onto main. This will make the PRs experimenting with newer versions of Xcode (like https://github.com/flutter/flutter/pull/173123) smaller and easier to reason about. Rebases #168860 and #170274 ``` $ git rebase main -Xtheirs ``` --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: gaaclarke <30870216+gaaclarke@users.noreply.github.com> Co-authored-by: Siva <a-siva@users.noreply.github.com> Co-authored-by: engine-flutter-autoroll <engine-flutter-autoroll@skia.org> Co-authored-by: Jamil Saadeh <jssaadeh@outlook.com> Co-authored-by: Dara Adedeji <76637177+SunkenInTime@users.noreply.github.com> Co-authored-by: Greg Price <gnprice@gmail.com> Co-authored-by: Ben Konyi <bkonyi@google.com> Co-authored-by: Ricardo Dalarme <ricardodalarme@outlook.com> Co-authored-by: Flutter GitHub Bot <fluttergithubbot@gmail.com> Co-authored-by: Justin McCandless <jmccandless@google.com> Co-authored-by: Alex Talebi <31685655+SalehTZ@users.noreply.github.com> Co-authored-by: Qun Cheng <36861262+QuncCccccc@users.noreply.github.com> Co-authored-by: Mouad Debbar <mdebbar@google.com> Co-authored-by: Zuckjet <1083941774@qq.com> Co-authored-by: Loïc Sharma <737941+loic-sharma@users.noreply.github.com> Co-authored-by: auto-submit[bot] <98614782+auto-submit[bot]@users.noreply.github.com> Co-authored-by: auto-submit[bot] <flutter-engprod-team@google.com> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Co-authored-by: yim <ybz975218925@gmail.com> Co-authored-by: bufffun <chenmingding.cmd@alibaba-inc.com> Co-authored-by: Chinmay Garde <chinmaygarde@google.com> Co-authored-by: Hannah Jin <jhy03261997@gmail.com> Co-authored-by: Kate Lovett <katelovett@google.com> Co-authored-by: Valentin Vignal <32538273+ValentinVignal@users.noreply.github.com> Co-authored-by: Derek Xu <derekx@google.com> Co-authored-by: Yash Dhrangdhariya <72062416+Yash-Dhrangdhariya@users.noreply.github.com> Co-authored-by: bungeman <bungeman@chromium.org> Co-authored-by: Ahmed Mohamed Sameh <ahmedsameha1@gmail.com> Co-authored-by: John "codefu" McDole <codefu@google.com> Co-authored-by: Dmitry Grand <dmgr@google.com> Co-authored-by: Kostia Sokolovskyi <sokolovskyi.konstantin@gmail.com> Co-authored-by: Reid Baker <1063596+reidbaker@users.noreply.github.com> Co-authored-by: Matthew Kosarek <matt.kosarek@canonical.com> Co-authored-by: Jason Simmons <jason-simmons@users.noreply.github.com> Co-authored-by: Jim Graham <flar@google.com> Co-authored-by: Michael Goderbauer <goderbauer@google.com> Co-authored-by: Gray Mackall <34871572+gmackall@users.noreply.github.com> Co-authored-by: Gray Mackall <mackall@google.com> Co-authored-by: Tong Mu <dkwingsmt@users.noreply.github.com> Co-authored-by: Jon Ihlas <jon.i@hotmail.fr> Co-authored-by: Micael Cid <micaelcid10@gmail.com> Co-authored-by: Alexander Aprelev <aam@google.com> Co-authored-by: hellohuanlin <41930132+hellohuanlin@users.noreply.github.com> Co-authored-by: Luke Memet <1598289+lukemmtt@users.noreply.github.com> Co-authored-by: Victoria Ashworth <15619084+vashworth@users.noreply.github.com> Co-authored-by: Mairramer <50643541+Mairramer@users.noreply.github.com> Co-authored-by: Florin Malita <fmalita@gmail.com> Co-authored-by: chunhtai <47866232+chunhtai@users.noreply.github.com> Co-authored-by: Salem Iranloye <127918074+salemiranloye@users.noreply.github.com> Co-authored-by: Kevin Moore <kevmoo@google.com> Co-authored-by: Sydney Bao <sydneybao@google.com> Co-authored-by: Wdestroier <Wdestroier@gmail.com> Co-authored-by: Matt Boetger <matt.boetger@gmail.com> Co-authored-by: Reid Baker <reidbaker@google.com> Co-authored-by: Victor Sanni <victorsanniay@gmail.com> Co-authored-by: Jessy Yameogo <jessy.yameogo@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: romain.gyh <11901536+romaingyh@users.noreply.github.com> Co-authored-by: Robert Ancell <robert.ancell@canonical.com> Co-authored-by: TheLastFlame <131446187+TheLastFlame@users.noreply.github.com> Co-authored-by: masato <returnymgstokh@icloud.com> Co-authored-by: Albin PK <56157868+albinpk@users.noreply.github.com> Co-authored-by: Huy <huy@nevercode.io> Co-authored-by: Matan Lurey <matanlurey@users.noreply.github.com> Co-authored-by: Azat Chorekliyev <azat24680@gmail.com> Co-authored-by: EdwynZN <edwinzn9@gmail.com> Co-authored-by: Bruno Leroux <bruno.leroux@gmail.com> Co-authored-by: Dev TtangKong <ttankkeo112@gmail.com> Co-authored-by: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com> Co-authored-by: Houssem Eddine Fadhli <houssemeddinefadhli81@gmail.com>
172 lines
6.1 KiB
Dart
172 lines
6.1 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.
|
|
|
|
// This program updates the language locale arb files with any missing resource
|
|
// entries that are included in the English arb files. This is useful when
|
|
// adding new resources for localization. You can just add the appropriate
|
|
// entries to the English arb file and then run this script. It will then check
|
|
// all of the other language locale arb files and update them with the English
|
|
// source for any missing resources. These will be picked up by the localization
|
|
// team and then translated.
|
|
//
|
|
// ## Usage
|
|
//
|
|
// Run this program from the root of the git repository.
|
|
//
|
|
// ```
|
|
// dart dev/tools/localization/bin/gen_missing_localizations.dart
|
|
// ```
|
|
|
|
import 'dart:convert';
|
|
import 'dart:io';
|
|
|
|
import 'package:path/path.dart' as path;
|
|
|
|
import '../localizations_utils.dart';
|
|
import '../localizations_validator.dart';
|
|
|
|
Future<void> main(List<String> rawArgs) async {
|
|
bool removeUndefined = false;
|
|
if (rawArgs.contains('--remove-undefined')) {
|
|
removeUndefined = true;
|
|
}
|
|
checkCwdIsRepoRoot('gen_missing_localizations');
|
|
|
|
final String localizationPath = path.join(
|
|
'packages',
|
|
'flutter_localizations',
|
|
'lib',
|
|
'src',
|
|
'l10n',
|
|
);
|
|
updateMissingResources(localizationPath, 'material', removeUndefined: removeUndefined);
|
|
updateMissingResources(localizationPath, 'cupertino', removeUndefined: removeUndefined);
|
|
updateMissingResources(localizationPath, 'widgets', removeUndefined: removeUndefined);
|
|
}
|
|
|
|
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 writeBundle(File file, Map<String, dynamic> bundle) {
|
|
final StringBuffer contents = StringBuffer();
|
|
contents.writeln('{');
|
|
for (final String key in bundle.keys) {
|
|
contents.writeln(' "$key": ${json.encode(bundle[key])}${key == bundle.keys.last ? '' : ','}');
|
|
}
|
|
contents.writeln('}');
|
|
file.writeAsStringSync(contents.toString());
|
|
}
|
|
|
|
Set<String> resourceKeys(Map<String, dynamic> bundle) {
|
|
return Set<String>.from(
|
|
// Skip any attribute keys
|
|
bundle.keys.where((String key) => !key.startsWith('@')),
|
|
);
|
|
}
|
|
|
|
bool intentionallyOmitted(String key, Map<String, dynamic> bundle) {
|
|
final String attributeKey = '@$key';
|
|
final dynamic attribute = bundle[attributeKey];
|
|
return attribute is Map && attribute.containsKey('notUsed');
|
|
}
|
|
|
|
/// Whether `key` corresponds to one of the plural variations of a key with
|
|
/// the same prefix and suffix "Other".
|
|
bool isPluralVariation(String key, Map<String, dynamic> bundle) {
|
|
final Match? pluralMatch = kPluralRegexp.firstMatch(key);
|
|
if (pluralMatch == null) {
|
|
return false;
|
|
}
|
|
final String prefix = pluralMatch[1]!;
|
|
return bundle.containsKey('${prefix}Other');
|
|
}
|
|
|
|
void updateMissingResources(
|
|
String localizationPath,
|
|
String groupPrefix, {
|
|
bool removeUndefined = false,
|
|
}) {
|
|
final Directory localizationDir = Directory(localizationPath);
|
|
final RegExp filenamePattern = RegExp('${groupPrefix}_(\\w+)\\.arb');
|
|
|
|
final Map<String, dynamic> englishBundle = loadBundle(
|
|
File(path.join(localizationPath, '${groupPrefix}_en.arb')),
|
|
);
|
|
final Set<String> requiredKeys = resourceKeys(englishBundle);
|
|
|
|
for (final FileSystemEntity entity
|
|
in localizationDir.listSync().toList()..sort(sortFilesByPath)) {
|
|
final String entityPath = entity.path;
|
|
if (FileSystemEntity.isFileSync(entityPath) && filenamePattern.hasMatch(entityPath)) {
|
|
final String localeString = filenamePattern.firstMatch(entityPath)![1]!;
|
|
final LocaleInfo locale = LocaleInfo.fromString(localeString);
|
|
|
|
// Only look at top-level language locales
|
|
if (locale.length == 1) {
|
|
final File arbFile = File(entityPath);
|
|
final Map<String, dynamic> localeBundle = loadBundle(arbFile);
|
|
final Set<String> localeResources = resourceKeys(localeBundle);
|
|
// Whether or not the resources were modified and need to be updated.
|
|
bool shouldWrite = false;
|
|
|
|
// Remove any localizations that are not defined in the canonical
|
|
// locale. This allows unused localizations to be removed if
|
|
// --remove-undefined is passed.
|
|
if (removeUndefined) {
|
|
bool isIncluded(String key) {
|
|
return !isPluralVariation(key, localeBundle) &&
|
|
!intentionallyOmitted(key, localeBundle);
|
|
}
|
|
|
|
// Find any resources in this locale that don't appear in the
|
|
// canonical locale, and skipping any which should not be included
|
|
// (plurals and intentionally omitted).
|
|
final Set<String> extraResources = localeResources
|
|
.difference(requiredKeys)
|
|
.where(isIncluded)
|
|
.toSet();
|
|
|
|
// Remove them.
|
|
localeBundle.removeWhere((String key, dynamic value) {
|
|
final bool found = extraResources.contains(key);
|
|
if (found) {
|
|
shouldWrite = true;
|
|
}
|
|
return found;
|
|
});
|
|
if (shouldWrite) {
|
|
print('Updating $entityPath by removing extra entries for $extraResources');
|
|
}
|
|
}
|
|
|
|
// Add in any resources that are in the canonical locale and not present
|
|
// in this locale.
|
|
final Set<String> missingResources = requiredKeys
|
|
.difference(localeResources)
|
|
.where(
|
|
(String key) =>
|
|
!isPluralVariation(key, localeBundle) && !intentionallyOmitted(key, localeBundle),
|
|
)
|
|
.toSet();
|
|
if (missingResources.isNotEmpty) {
|
|
localeBundle.addEntries(
|
|
missingResources.map(
|
|
(String k) => MapEntry<String, String>(k, englishBundle[k].toString()),
|
|
),
|
|
);
|
|
shouldWrite = true;
|
|
print('Updating $entityPath with missing entries for $missingResources');
|
|
}
|
|
if (shouldWrite) {
|
|
writeBundle(arbFile, localeBundle);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|