Skip to content

Commit 5e09eab

Browse files
LaemonTlesnitsky
andauthored
fix(ui_localizations): fix loading Traditional Chinese (#128)
* Uses the way how _WidgetsLocalizationsDelegate choose an appropriate translation. * melos run format * Add trailing comma * Add test cases to verify that Traditional Chinese loads correctly and the localization overrides work properly. * Add test cases to verify that Traditional Chinese loads correctly and the localization overrides work properly. * Add widget tests for the `firebase_ui_localizations` package. * Code refactoring and applies `melos run format`. * Convert to block body. * Execute `melos run format` * formatting and naming --------- Co-authored-by: Andrei Lesnitsky <[email protected]>
1 parent 73d5f00 commit 5e09eab

File tree

3 files changed

+296
-59
lines changed

3 files changed

+296
-59
lines changed
+107-38
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,121 @@
11
// Copyright 2023, the Chromium project authors. Please see the AUTHORS file
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
4-
import "./default_localizations.dart";
4+
import 'dart:ui';
55

6+
import "./default_localizations.dart";
7+
import 'lang/ar.dart';
8+
import 'lang/de.dart';
9+
import 'lang/en.dart';
610
import 'lang/es.dart';
711
import 'lang/es_419.dart';
8-
import 'lang/ko.dart';
12+
import 'lang/fr.dart';
13+
import 'lang/he.dart';
14+
import 'lang/hi.dart';
915
import 'lang/hu.dart';
1016
import 'lang/id.dart';
11-
import 'lang/pt.dart';
12-
import 'lang/he.dart';
13-
import 'lang/de.dart';
1417
import 'lang/it.dart';
15-
import 'lang/zh.dart';
16-
import 'lang/zh_tw.dart';
17-
import 'lang/uk.dart';
18-
import 'lang/th.dart';
19-
import 'lang/ar.dart';
20-
import 'lang/tr.dart';
18+
import 'lang/ja.dart';
19+
import 'lang/ko.dart';
2120
import 'lang/nl.dart';
2221
import 'lang/pl.dart';
23-
import 'lang/en.dart';
24-
import 'lang/ja.dart';
25-
import 'lang/hi.dart';
22+
import 'lang/pt.dart';
2623
import 'lang/ru.dart';
27-
import 'lang/fr.dart';
24+
import 'lang/th.dart';
25+
import 'lang/tr.dart';
26+
import 'lang/uk.dart';
27+
import 'lang/zh.dart';
28+
import 'lang/zh_tw.dart';
2829

29-
final localizations = <String, FirebaseUILocalizationLabels>{
30-
'es': const EsLocalizations(),
31-
'es_419': const Es419Localizations(),
32-
'ko': const KoLocalizations(),
33-
'hu': const HuLocalizations(),
34-
'id': const IdLocalizations(),
35-
'pt': const PtLocalizations(),
36-
'he': const HeLocalizations(),
37-
'de': const DeLocalizations(),
38-
'it': const ItLocalizations(),
39-
'zh': const ZhLocalizations(),
40-
'zh_tw': const ZhTWLocalizations(),
41-
'uk': const UkLocalizations(),
42-
'th': const ThLocalizations(),
43-
'ar': const ArLocalizations(),
44-
'tr': const TrLocalizations(),
45-
'nl': const NlLocalizations(),
46-
'pl': const PlLocalizations(),
47-
'en': const EnLocalizations(),
48-
'ja': const JaLocalizations(),
49-
'hi': const HiLocalizations(),
50-
'ru': const RuLocalizations(),
51-
'fr': const FrLocalizations(),
30+
final Set<String> kSupportedLanguages = {
31+
'ar', // Arabic
32+
'de', // German
33+
'en', // English
34+
'es', // Spanish Castilian
35+
'fr', // French
36+
'he', // Hebrew
37+
'hi', // Hindi
38+
'hu', // Hungarian
39+
'id', // Indonesian
40+
'it', // Italian
41+
'ja', // Japanese
42+
'ko', // Korean
43+
'nl', // Dutch Flemish
44+
'pl', // Polish
45+
'pt', // Portuguese
46+
'ru', // Russian
47+
'th', // Thai
48+
'tr', // Turkish
49+
'uk', // Ukrainian
50+
'zh', // Chinese
5251
};
52+
53+
FirebaseUILocalizationLabels getFirebaseUITranslation(
54+
Locale useLocale, [
55+
Locale? defaultLocale,
56+
]) {
57+
final Locale locale;
58+
if (kSupportedLanguages.contains(useLocale.languageCode)) {
59+
locale = useLocale;
60+
} else {
61+
locale = defaultLocale ?? useLocale;
62+
}
63+
64+
switch (locale.languageCode) {
65+
case 'ar':
66+
return const ArLocalizations();
67+
case 'de':
68+
return const DeLocalizations();
69+
case 'en':
70+
return const EnLocalizations();
71+
case 'es':
72+
switch (locale.countryCode) {
73+
case '419':
74+
return const Es419Localizations();
75+
}
76+
return const EsLocalizations();
77+
case 'fr':
78+
return const FrLocalizations();
79+
case 'he':
80+
return const HeLocalizations();
81+
case 'hi':
82+
return const HiLocalizations();
83+
case 'hu':
84+
return const HuLocalizations();
85+
case 'id':
86+
return const IdLocalizations();
87+
case 'it':
88+
return const ItLocalizations();
89+
case 'ja':
90+
return const JaLocalizations();
91+
case 'ko':
92+
return const KoLocalizations();
93+
case 'nl':
94+
return const NlLocalizations();
95+
case 'pl':
96+
return const PlLocalizations();
97+
case 'pt':
98+
return const PtLocalizations();
99+
case 'ru':
100+
return const RuLocalizations();
101+
case 'th':
102+
return const ThLocalizations();
103+
case 'tr':
104+
return const TrLocalizations();
105+
case 'uk':
106+
return const UkLocalizations();
107+
case 'zh':
108+
switch (locale.scriptCode) {
109+
case 'Hant':
110+
return const ZhTWLocalizations();
111+
}
112+
switch (locale.countryCode) {
113+
case 'HK':
114+
case 'TW':
115+
return const ZhTWLocalizations();
116+
}
117+
return const ZhLocalizations();
118+
}
119+
120+
throw ('getTranslationLabels() called for unsupported locale "$locale"');
121+
}

Diff for: packages/firebase_ui_localizations/lib/src/l10n.dart

+9-21
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ class FirebaseUILocalizations<T extends FirebaseUILocalizationLabels> {
3636
return l;
3737
}
3838

39-
final defaultLocalizations = localizations[kDefaultLocale.languageCode]!;
40-
return FirebaseUILocalizations(kDefaultLocale, defaultLocalizations);
39+
final defaultTranslation = getFirebaseUITranslation(kDefaultLocale);
40+
return FirebaseUILocalizations(kDefaultLocale, defaultTranslation);
4141
}
4242

4343
/// Returns localization labels.
@@ -74,32 +74,20 @@ class FirebaseUILocalizationDelegate<T extends FirebaseUILocalizationLabels>
7474
]);
7575

7676
@override
77-
bool isSupported(Locale locale) {
78-
return _forceSupportAllLocales ||
79-
localizations.keys.contains(locale.languageCode);
80-
}
77+
bool isSupported(Locale locale) =>
78+
_forceSupportAllLocales ||
79+
kSupportedLanguages.contains(locale.languageCode);
8180

8281
@override
8382
Future<FirebaseUILocalizations> load(Locale locale) {
84-
late FirebaseUILocalizationLabels labels;
85-
86-
final key = locale.languageCode;
87-
final fullKey = '${key}_${locale.countryCode.toString()}';
88-
89-
if (localizations.containsKey(fullKey)) {
90-
labels = localizations[fullKey]!;
91-
} else if (localizations.containsKey(key)) {
92-
labels = localizations[key]!;
93-
} else {
94-
labels = localizations[kDefaultLocale.languageCode]!;
95-
}
83+
final translation = getFirebaseUITranslation(locale, kDefaultLocale);
9684

97-
final l = FirebaseUILocalizations(
85+
final localizations = FirebaseUILocalizations(
9886
locale,
99-
overrides ?? labels,
87+
overrides ?? translation,
10088
);
10189

102-
return SynchronousFuture<FirebaseUILocalizations>(l);
90+
return SynchronousFuture<FirebaseUILocalizations>(localizations);
10391
}
10492

10593
@override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
// Copyright 2022, the Chromium project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:firebase_ui_localizations/firebase_ui_localizations.dart';
6+
import 'package:firebase_ui_localizations/src/lang/zh_tw.dart';
7+
import 'package:flutter/material.dart';
8+
import 'package:flutter_localizations/flutter_localizations.dart';
9+
import 'package:flutter_test/flutter_test.dart';
10+
11+
const localeZh = Locale('zh');
12+
const localeTW = Locale('zh', 'TW');
13+
14+
Future<void> main() async {
15+
late FirebaseUILocalizationDelegate delegate;
16+
17+
group(
18+
'FirebaseUILocalization loads the appropriate Chinese translation',
19+
() {
20+
localizeText(BuildContext context) {
21+
final labels = FirebaseUILocalizations.labelsOf(context);
22+
return labels.signInWithPhoneButtonText;
23+
}
24+
25+
setUp(() async {
26+
delegate = const FirebaseUILocalizationDelegate();
27+
});
28+
29+
test(
30+
'Loads the correct translation with the language tag "${localeZh.toLanguageTag()}"',
31+
() async {
32+
final localizations = await delegate.load(localeZh);
33+
expect(localizations.labels.signInWithPhoneButtonText, '使用电话号码登录');
34+
},
35+
);
36+
37+
testWidgets(
38+
'UI test for the "${localeZh.toLanguageTag()}" translation',
39+
(tester) async {
40+
await tester.pumpWidget(
41+
TestMaterialApp(
42+
locale: localeZh,
43+
localizeText: localizeText,
44+
),
45+
);
46+
expect(find.text('使用电话号码登录'), findsOneWidget);
47+
},
48+
);
49+
50+
test(
51+
'Loads the correct translation with the language tag "${localeTW.toLanguageTag()}"',
52+
() async {
53+
final localizations = await delegate.load(localeTW);
54+
expect(localizations.labels.signInWithPhoneButtonText, '使用電話號碼登入');
55+
},
56+
);
57+
58+
testWidgets(
59+
'UI test for the "${localeTW.toLanguageTag()}" translation',
60+
(tester) async {
61+
await tester.pumpWidget(
62+
TestMaterialApp(
63+
locale: localeTW,
64+
localizeText: localizeText,
65+
),
66+
);
67+
expect(find.text('使用電話號碼登入'), findsOneWidget);
68+
},
69+
);
70+
},
71+
);
72+
73+
group(
74+
'Localization override',
75+
() {
76+
localizeText(BuildContext context) {
77+
return FirebaseUILocalizations.labelsOf(context).verifyEmailTitle;
78+
}
79+
80+
test(
81+
'Overrides the DefaultLocalizations',
82+
() async {
83+
final localizations = await const FirebaseUILocalizationDelegate(
84+
DefaultLocalizationsOverrides(),
85+
).load(localeTW);
86+
expect(localizations.labels.verifyEmailTitle, 'Overwritten');
87+
},
88+
);
89+
90+
testWidgets(
91+
'UI test for the default translation override',
92+
(tester) async {
93+
await tester.pumpWidget(
94+
TestMaterialApp(
95+
locale: localeZh,
96+
localizationsOverride: const FirebaseUILocalizationDelegate(
97+
DefaultLocalizationsOverrides(),
98+
),
99+
localizeText: localizeText,
100+
),
101+
);
102+
expect(find.text('Overwritten'), findsOneWidget);
103+
},
104+
);
105+
106+
test(
107+
'Overrides the DefaultLocalizations',
108+
() async {
109+
final localizations = await const FirebaseUILocalizationDelegate(
110+
ZhTWLocalizationsOverrides(),
111+
).load(localeTW);
112+
expect(localizations.labels.verifyEmailTitle, '覆寫標題');
113+
},
114+
);
115+
116+
testWidgets(
117+
'UI test for the "${localeTW.toLanguageTag()}" translation override',
118+
(tester) async {
119+
await tester.pumpWidget(
120+
TestMaterialApp(
121+
locale: localeTW,
122+
localizationsOverride: const FirebaseUILocalizationDelegate(
123+
ZhTWLocalizationsOverrides(),
124+
),
125+
localizeText: localizeText,
126+
),
127+
);
128+
expect(find.text('覆寫標題'), findsOneWidget);
129+
},
130+
);
131+
},
132+
);
133+
}
134+
135+
class DefaultLocalizationsOverrides extends DefaultLocalizations {
136+
const DefaultLocalizationsOverrides();
137+
138+
@override
139+
String get verifyEmailTitle => 'Overwritten';
140+
}
141+
142+
class ZhTWLocalizationsOverrides extends ZhTWLocalizations {
143+
const ZhTWLocalizationsOverrides();
144+
145+
@override
146+
String get verifyEmailTitle => '覆寫標題';
147+
}
148+
149+
class TestMaterialApp extends StatelessWidget {
150+
final Locale locale;
151+
final LocalizationsDelegate? localizationsOverride;
152+
final String Function(BuildContext context) localizeText;
153+
154+
const TestMaterialApp({
155+
super.key,
156+
required this.locale,
157+
this.localizationsOverride,
158+
required this.localizeText,
159+
});
160+
161+
@override
162+
Widget build(BuildContext context) {
163+
return MaterialApp(
164+
supportedLocales: const [localeZh, localeTW],
165+
locale: locale,
166+
localizationsDelegates: [
167+
GlobalMaterialLocalizations.delegate,
168+
GlobalCupertinoLocalizations.delegate,
169+
localizationsOverride == null
170+
? FirebaseUILocalizations.delegate
171+
: localizationsOverride!,
172+
],
173+
home: Builder(
174+
builder: (context) => Text(
175+
localizeText.call(context),
176+
),
177+
),
178+
);
179+
}
180+
}

0 commit comments

Comments
 (0)