Unverified Commit 365528aa authored by Shi-Hao Hong's avatar Shi-Hao Hong Committed by GitHub

Use `no` locale as synonym for `nb` (#53880)

parent e0127526
......@@ -172,6 +172,14 @@ Set<String> _supportedLocales() {
if (FileSystemEntity.isFileSync(filePath) && filenameRE.hasMatch(filePath))
supportedLocales.add(filenameRE.firstMatch(filePath)[1]);
}
// See https://github.com/flutter/flutter/issues/53036 for context on why
// 'no' is being used as a synonym for 'nb'. It only uses this synonym
// if 'nb' is not detected as a valid arb file.
if (supportedLocales.contains('no') && !supportedLocales.contains('nb')) {
supportedLocales.add('nb');
}
return supportedLocales;
}
......
......@@ -76,6 +76,11 @@ String generateArbBasedLocalizationSubclasses({
assert(supportedLanguagesConstant.isNotEmpty);
assert(supportedLanguagesDocMacro.isNotEmpty);
// See https://github.com/flutter/flutter/issues/53036 for context on why
// 'no' is being used as a synonym for 'nb'. It only uses this synonym
// if 'nb' is not detected as a valid arb file.
bool isNbSynonymOfNo = false;
final StringBuffer output = StringBuffer();
output.writeln(generateHeader('dart dev/tools/localization/bin/gen_localizations.dart --overwrite'));
......@@ -101,6 +106,12 @@ String generateArbBasedLocalizationSubclasses({
allResourceIdentifiers.addAll(localeToResources[locale].keys.toList()..sort());
}
if (languageToLocales['no'] != null && languageToLocales['nb'] == null) {
languageToLocales['nb'] ??= <LocaleInfo>[];
languageToLocales['nb'].add(LocaleInfo.fromString('nb'));
isNbSynonymOfNo = true;
}
// We generate one class per supported language (e.g.
// `MaterialLocalizationEn`). These implement everything that is needed by the
// superclass (e.g. GlobalMaterialLocalizations).
......@@ -117,7 +128,7 @@ String generateArbBasedLocalizationSubclasses({
// If scriptCodes for a language are defined, we expect a scriptCode to be
// defined for locales that contain a countryCode. The superclass becomes
// the script sublcass (e.g. `MaterialLocalizationZhHant`) and the generated
// the script subclass (e.g. `MaterialLocalizationZhHant`) and the generated
// subclass will also contain the script code (e.g. `MaterialLocalizationZhHantTW`).
// When scriptCodes are not defined for languages that use scriptCodes to distinguish
......@@ -130,6 +141,22 @@ String generateArbBasedLocalizationSubclasses({
final LocaleInfo canonicalLocale = LocaleInfo.fromString('en');
for (final String languageName in languageCodes) {
final LocaleInfo languageLocale = LocaleInfo.fromString(languageName);
// See https://github.com/flutter/flutter/issues/53036 for context on why
// 'no' is being used as a synonym for 'nb'. It only uses this synonym
// if 'nb' is not detected as a valid arb file.
if (languageName == 'nb' && isNbSynonymOfNo) {
output.writeln(generateClassDeclaration(
languageLocale,
generatedClassPrefix,
'${generatedClassPrefix}No'),
);
output.writeln(generateConstructor(languageLocale));
output.writeln('}');
supportedLocales.writeln('/// * `$languageName` - ${describeLocale(languageName)}, which, in this library, is a synonym of `no`');
continue;
}
output.writeln(generateClassDeclaration(languageLocale, generatedClassPrefix, baseClass));
output.writeln(generateConstructor(languageLocale));
......@@ -212,6 +239,7 @@ String generateArbBasedLocalizationSubclasses({
output.writeln('}');
}
}
final String scriptCodeMessage = scriptCodeCount == 0 ? '' : ' and $scriptCodeCount script' + (scriptCodeCount == 1 ? '' : 's');
if (countryCodeCount == 0) {
if (scriptCodeCount == 0)
......
......@@ -11985,6 +11985,196 @@ const Map<String, dynamic> dateSymbols = <String, dynamic>{
'{1} {0}',
],
},
'no': <String, dynamic>{
'NAME': 'no',
'ERAS': <dynamic>[
'f.Kr.',
'e.Kr.',
],
'ERANAMES': <dynamic>[
'før Kristus',
'etter Kristus',
],
'NARROWMONTHS': <dynamic>[
'J',
'F',
'M',
'A',
'M',
'J',
'J',
'A',
'S',
'O',
'N',
'D',
],
'STANDALONENARROWMONTHS': <dynamic>[
'J',
'F',
'M',
'A',
'M',
'J',
'J',
'A',
'S',
'O',
'N',
'D',
],
'MONTHS': <dynamic>[
'januar',
'februar',
'mars',
'april',
'mai',
'juni',
'juli',
'august',
'september',
'oktober',
'november',
'desember',
],
'STANDALONEMONTHS': <dynamic>[
'januar',
'februar',
'mars',
'april',
'mai',
'juni',
'juli',
'august',
'september',
'oktober',
'november',
'desember',
],
'SHORTMONTHS': <dynamic>[
'jan.',
'feb.',
'mar.',
'apr.',
'mai',
'jun.',
'jul.',
'aug.',
'sep.',
'okt.',
'nov.',
'des.',
],
'STANDALONESHORTMONTHS': <dynamic>[
'jan',
'feb',
'mar',
'apr',
'mai',
'jun',
'jul',
'aug',
'sep',
'okt',
'nov',
'des',
],
'WEEKDAYS': <dynamic>[
'søndag',
'mandag',
'tirsdag',
'onsdag',
'torsdag',
'fredag',
'lørdag',
],
'STANDALONEWEEKDAYS': <dynamic>[
'søndag',
'mandag',
'tirsdag',
'onsdag',
'torsdag',
'fredag',
'lørdag',
],
'SHORTWEEKDAYS': <dynamic>[
'søn.',
'man.',
'tir.',
'ons.',
'tor.',
'fre.',
'lør.',
],
'STANDALONESHORTWEEKDAYS': <dynamic>[
'søn.',
'man.',
'tir.',
'ons.',
'tor.',
'fre.',
'lør.',
],
'NARROWWEEKDAYS': <dynamic>[
'S',
'M',
'T',
'O',
'T',
'F',
'L',
],
'STANDALONENARROWWEEKDAYS': <dynamic>[
'S',
'M',
'T',
'O',
'T',
'F',
'L',
],
'SHORTQUARTERS': <dynamic>[
'K1',
'K2',
'K3',
'K4',
],
'QUARTERS': <dynamic>[
'1. kvartal',
'2. kvartal',
'3. kvartal',
'4. kvartal',
],
'AMPMS': <dynamic>[
'a.m.',
'p.m.',
],
'DATEFORMATS': <dynamic>[
'EEEE d. MMMM y',
'd. MMMM y',
'd. MMM y',
'dd.MM.y',
],
'TIMEFORMATS': <dynamic>[
'HH:mm:ss zzzz',
'HH:mm:ss z',
'HH:mm:ss',
'HH:mm',
],
'AVAILABLEFORMATS': null,
'FIRSTDAYOFWEEK': 0,
'WEEKENDRANGE': <dynamic>[
5,
6,
],
'FIRSTWEEKCUTOFFDAY': 3,
'DATETIMEFORMATS': <dynamic>[
'{1} {0}',
'{1} \'kl\'. {0}',
'{1}, {0}',
'{1}, {0}',
],
},
'or': <String, dynamic>{
'NAME': 'or',
'ERAS': <dynamic>[
......@@ -20400,6 +20590,52 @@ const Map<String, Map<String, String>> datePatterns =
'zzzz': 'zzzz',
'ZZZZ': 'ZZZZ',
},
'no': <String, String>{
'd': 'd.',
'E': 'ccc',
'EEEE': 'cccc',
'LLL': 'LLL',
'LLLL': 'LLLL',
'M': 'L.',
'Md': 'd.M.',
'MEd': 'EEE d.M.',
'MMM': 'LLL',
'MMMd': 'd. MMM',
'MMMEd': 'EEE d. MMM',
'MMMM': 'LLLL',
'MMMMd': 'd. MMMM',
'MMMMEEEEd': 'EEEE d. MMMM',
'QQQ': 'QQQ',
'QQQQ': 'QQQQ',
'y': 'y',
'yM': 'M.y',
'yMd': 'd.M.y',
'yMEd': 'EEE d.MM.y',
'yMMM': 'MMM y',
'yMMMd': 'd. MMM y',
'yMMMEd': 'EEE d. MMM y',
'yMMMM': 'MMMM y',
'yMMMMd': 'd. MMMM y',
'yMMMMEEEEd': 'EEEE d. MMMM y',
'yQQQ': 'QQQ y',
'yQQQQ': 'QQQQ y',
'H': 'HH',
'Hm': 'HH:mm',
'Hms': 'HH:mm:ss',
'j': 'HH',
'jm': 'HH:mm',
'jms': 'HH:mm:ss',
'jmv': 'HH:mm v',
'jmz': 'HH:mm z',
'jz': 'HH z',
'm': 'm',
'ms': 'mm:ss',
's': 's',
'v': 'v',
'z': 'z',
'zzzz': 'zzzz',
'ZZZZ': 'ZZZZ',
},
'or': <String, String>{
'd': 'd',
'E': 'ccc',
......
......@@ -5,6 +5,7 @@
"backButtonTooltip": "Tilbake",
"closeButtonTooltip": "Lukk",
"deleteButtonTooltip": "Slett",
"moreButtonTooltip": "Mer",
"nextMonthTooltip": "Neste måned",
"previousMonthTooltip": "Forrige måned",
"nextPageTooltip": "Neste side",
......@@ -51,6 +52,5 @@
"remainingTextFieldCharacterCountZero": "TBD",
"remainingTextFieldCharacterCountOne": "1 tegn gjenstår",
"remainingTextFieldCharacterCountOther": "$remainingCount tegn gjenstår",
"refreshIndicatorSemanticLabel": "Laster inn på nytt",
"moreButtonTooltip": "Mer"
"refreshIndicatorSemanticLabel": "Laster inn på nytt"
}
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_test/flutter_test.dart';
......@@ -118,4 +120,29 @@ void main() {
expect(localizations.selectAllButtonLabel, '全选');
expect(localizations.timerPickerMinute(10), '10');
});
// Regression test for https://github.com/flutter/flutter/issues/53036.
testWidgets('`nb` uses `no` as its synonym when `nb` arb file is not present', (WidgetTester tester) async {
final File nbCupertinoArbFile = File('lib/src/l10n/cupertino_nb.arb');
final File noCupertinoArbFile = File('lib/src/l10n/cupertino_no.arb');
if (noCupertinoArbFile.existsSync() && !nbCupertinoArbFile.existsSync()) {
Locale locale = const Locale.fromSubtags(languageCode: 'no', scriptCode: null, countryCode: null);
expect(GlobalCupertinoLocalizations.delegate.isSupported(locale), isTrue);
CupertinoLocalizations localizations = await GlobalCupertinoLocalizations.delegate.load(locale);
expect(localizations, isA<CupertinoLocalizationNo>());
final String pasteButtonLabelNo = localizations.pasteButtonLabel;
final String copyButtonLabelNo = localizations.copyButtonLabel;
final String cutButtonLabelNo = localizations.cutButtonLabel;
locale = const Locale.fromSubtags(languageCode: 'nb', scriptCode: null, countryCode: null);
expect(GlobalCupertinoLocalizations.delegate.isSupported(locale), isTrue);
localizations = await GlobalCupertinoLocalizations.delegate.load(locale);
expect(localizations, isA<CupertinoLocalizationNb>());
expect(localizations.pasteButtonLabel, pasteButtonLabelNo);
expect(localizations.copyButtonLabel, copyButtonLabelNo);
expect(localizations.cutButtonLabel, cutButtonLabelNo);
}
});
}
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
......@@ -28,6 +29,19 @@ void main() {
}, throwsAssertionError);
});
// Regression test for https://github.com/flutter/flutter/issues/53036.
test('`nb` uses `no` as a synonym when `nb` arb file is not present', () async {
final File nbMaterialArbFile = File('lib/src/l10n/material_nb.arb');
final File noMaterialArbFile = File('lib/src/l10n/material_no.arb');
// No need to run test if `nb` arb file exists or if `no` arb file does not exist.
if (noMaterialArbFile.existsSync() && !nbMaterialArbFile.existsSync()) {
final GlobalMaterialLocalizations localizations = await GlobalMaterialLocalizations.delegate
.load(const Locale('nb')) as GlobalMaterialLocalizations;
expect(localizations.formatMediumDate(DateTime(2020, 4, 3)), 'fre. 3. apr.');
}
});
group('formatHour', () {
Future<String> formatHour(WidgetTester tester, Locale locale, TimeOfDay timeOfDay) async {
final Completer<String> completer = Completer<String>();
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_test/flutter_test.dart';
......@@ -462,4 +464,32 @@ void main() {
expect(localizations.closeButtonLabel, '關閉');
expect(localizations.okButtonLabel, '確定');
});
// Regression test for https://github.com/flutter/flutter/issues/53036.
testWidgets('`nb` uses `no` as its synonym when `nb` arb file is not present', (WidgetTester tester) async {
final File nbMaterialArbFile = File('lib/src/l10n/material_nb.arb');
final File noMaterialArbFile = File('lib/src/l10n/material_no.arb');
// No need to run test if `nb` arb file exists or if `no` arb file does not exist.
if (noMaterialArbFile.existsSync() && !nbMaterialArbFile.existsSync()) {
Locale locale = const Locale.fromSubtags(languageCode: 'no', scriptCode: null, countryCode: null);
expect(GlobalMaterialLocalizations.delegate.isSupported(locale), isTrue);
MaterialLocalizations localizations = await GlobalMaterialLocalizations.delegate.load(locale);
expect(localizations, isA<MaterialLocalizationNo>());
final String alertDialogLabelNo = localizations.alertDialogLabel;
final String anteMeridiemAbbreviationNo = localizations.anteMeridiemAbbreviation;
final String closeButtonLabelNo = localizations.closeButtonLabel;
final String okButtonLabelNo = localizations.okButtonLabel;
locale = const Locale.fromSubtags(languageCode: 'nb', scriptCode: null, countryCode: null);
expect(GlobalMaterialLocalizations.delegate.isSupported(locale), isTrue);
localizations = await GlobalMaterialLocalizations.delegate.load(locale);
expect(localizations, isA<MaterialLocalizationNb>());
expect(localizations.alertDialogLabel, alertDialogLabelNo);
expect(localizations.anteMeridiemAbbreviation, anteMeridiemAbbreviationNo);
expect(localizations.closeButtonLabel, closeButtonLabelNo);
expect(localizations.okButtonLabel, okButtonLabelNo);
}
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment