From 4f7beeb46301d44d011f74651bb3527a2d07eee1 Mon Sep 17 00:00:00 2001 From: abdessalem Date: Sat, 19 Sep 2026 17:28:10 +0100 Subject: [PATCH 1/3] Add tests for Indonesian, Korean and Thai locales tests in TimePicker i10n tests --- .../change_2026_09_19_1789835052875.yaml | 3 + .../test/l10n/time_picker_test.dart | 142 +++++++++++++++++- 2 files changed, 139 insertions(+), 6 deletions(-) create mode 100644 packages/material_ui/pending_changelogs/change_2026_09_19_1789835052875.yaml diff --git a/packages/material_ui/pending_changelogs/change_2026_09_19_1789835052875.yaml b/packages/material_ui/pending_changelogs/change_2026_09_19_1789835052875.yaml new file mode 100644 index 000000000000..c3f9ad326700 --- /dev/null +++ b/packages/material_ui/pending_changelogs/change_2026_09_19_1789835052875.yaml @@ -0,0 +1,3 @@ +changelog: | + - Adds tests for Indonesian, Korean and Thai locales tests in TimePicker i10n tests +version: patch diff --git a/packages/material_ui/test/l10n/time_picker_test.dart b/packages/material_ui/test/l10n/time_picker_test.dart index c23f10a0e357..45b27011a683 100644 --- a/packages/material_ui/test/l10n/time_picker_test.dart +++ b/packages/material_ui/test/l10n/time_picker_test.dart @@ -35,7 +35,6 @@ void main() { (Widget w) => '${w.runtimeType}' == '_DayPeriodControl', ); - // TODO(yjbanov): also test `HH.mm` (in_ID), `a h:mm` (ko_KR) and `HH:mm น.` (th_TH) when we have .arb files for them final locales = [ const Locale('en', 'US'), //'h:mm a' const Locale('en', 'GB'), //'HH:mm' @@ -43,6 +42,9 @@ void main() { const Locale('fr', 'CA'), //'HH \'h\' mm' const Locale('zh', 'ZH'), //'ah:mm' const Locale('fa', 'IR'), //'H:mm' but RTL + const Locale('in', 'ID'), //'HH.mm' + const Locale('ko', 'KR'), //'a h:mm` + const Locale('th', 'TH'), //`HH:mm น.` ]; for (final locale in locales) { @@ -90,6 +92,22 @@ void main() { expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); expect(dayPeriodControlFinder, findsNothing); + } else if (locale == const Locale('in', 'ID')) { + // This is an LTR locale, it uses a dot separator instead of a standard colon. + expect(stringFragmentText.data, '.'); + expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); + expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); + expect(dayPeriodControlFinder, findsNothing); + } else if (locale == const Locale('ko', 'KR')) { + expect(stringFragmentText.data, ':'); + expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); + expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); + expect(dayPeriodControlFinder, findsOne); + } else if (locale == const Locale('th', 'TH')) { + expect(stringFragmentText.data, ':'); + expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); + expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); + expect(dayPeriodControlFinder, findsOne); } await tester.tapAt(Offset(center.dx, center.dy - 50.0)); await finishPicker(tester); @@ -120,7 +138,6 @@ void main() { (Widget w) => '${w.runtimeType}' == '_DayPeriodControl', ); - // TODO(yjbanov): also test `HH.mm` (in_ID), `a h:mm` (ko_KR) and `HH:mm น.` (th_TH) when we have .arb files for them final locales = [ const Locale('en', 'US'), //'h:mm a' const Locale('en', 'GB'), //'HH:mm' @@ -128,6 +145,9 @@ void main() { const Locale('fr', 'CA'), //'HH \'h\' mm' const Locale('zh', 'ZH'), //'ah:mm' const Locale('fa', 'IR'), //'H:mm' but RTL + const Locale('in', 'ID'), //'HH.mm' + const Locale('ko', 'KR'), //'a h:mm` + const Locale('th', 'TH'), //`HH:mm น.` ]; for (final locale in locales) { @@ -170,6 +190,22 @@ void main() { expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); expect(dayPeriodControlFinder, findsNothing); + } else if (locale == const Locale('in', 'ID')) { + // This is an LTR locale, it uses a dot separator instead of a standard colon. + expect(stringFragmentText.data, '.'); + expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); + expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); + expect(dayPeriodControlFinder, findsNothing); + } else if (locale == const Locale('ko', 'KR')) { + expect(stringFragmentText.data, ':'); + expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); + expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); + expect(dayPeriodControlFinder, findsOne); + } else if (locale == const Locale('th', 'TH')) { + expect(stringFragmentText.data, ':'); + expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); + expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); + expect(dayPeriodControlFinder, findsOne); } await tester.tapAt(Offset(center.dx, center.dy - 50.0)); await finishPicker(tester); @@ -200,7 +236,6 @@ void main() { (Widget w) => '${w.runtimeType}' == '_DayPeriodControl', ); - // TODO(yjbanov): also test `HH.mm` (in_ID), `a h:mm` (ko_KR) and `HH:mm น.` (th_TH) when we have .arb files for them final locales = [ const Locale('en', 'US'), //'h:mm a' const Locale('en', 'GB'), //'HH:mm' @@ -208,6 +243,9 @@ void main() { const Locale('fr', 'CA'), //'HH \'h\' mm' const Locale('zh', 'ZH'), //'ah:mm' const Locale('fa', 'IR'), //'H:mm' but RTL + const Locale('in', 'ID'), //'HH.mm' + const Locale('ko', 'KR'), //'a h:mm` + const Locale('th', 'TH'), //`HH:mm น.` ]; for (final locale in locales) { @@ -260,6 +298,22 @@ void main() { expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); expect(dayPeriodControlFinder, findsNothing); + } else if (locale == const Locale('in', 'ID')) { + // This is an LTR locale, it uses a dot separator instead of a standard colon. + expect(stringFragmentText.data, '.'); + expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); + expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); + expect(dayPeriodControlFinder, findsNothing); + } else if (locale == const Locale('ko', 'KR')) { + expect(stringFragmentText.data, ':'); + expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); + expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); + expect(dayPeriodControlFinder, findsOne); + } else if (locale == const Locale('th', 'TH')) { + expect(stringFragmentText.data, ':'); + expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); + expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); + expect(dayPeriodControlFinder, findsOne); } await tester.tapAt(Offset(center.dx, center.dy - 50.0)); await finishPicker(tester); @@ -290,7 +344,6 @@ void main() { (Widget w) => '${w.runtimeType}' == '_DayPeriodControl', ); - // TODO(yjbanov): also test `HH.mm` (in_ID), `a h:mm` (ko_KR) and `HH:mm น.` (th_TH) when we have .arb files for them final locales = [ const Locale('en', 'US'), //'h:mm a' const Locale('en', 'GB'), //'HH:mm' @@ -298,6 +351,9 @@ void main() { const Locale('fr', 'CA'), //'HH \'h\' mm' const Locale('zh', 'ZH'), //'ah:mm' const Locale('fa', 'IR'), //'H:mm' but RTL + const Locale('in', 'ID'), //'HH.mm' + const Locale('ko', 'KR'), //'a h:mm` + const Locale('th', 'TH'), //`HH:mm น.` ]; for (final locale in locales) { @@ -345,6 +401,38 @@ void main() { expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); expect(dayPeriodControlFinder, findsNothing); + } else if (locale == const Locale('in', 'ID')) { + // This is an LTR locale, it uses a dot separator instead of a standard colon. + expect(stringFragmentText.data, '.'); + expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); + expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); + expect(dayPeriodControlFinder, findsNothing); + } else if (locale == const Locale('ko', 'KR')) { + expect(stringFragmentText.data, ':'); + expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); + expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); + expect(dayPeriodControlFinder, findsOne); + } else if (locale == const Locale('th', 'TH')) { + expect(stringFragmentText.data, ':'); + expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); + expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); + expect(dayPeriodControlFinder, findsOne); + } else if (locale == const Locale('in', 'ID')) { + // This is an LTR locale, it uses a dot separator instead of a standard colon. + expect(stringFragmentText.data, '.'); + expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); + expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); + expect(dayPeriodControlFinder, findsNothing); + } else if (locale == const Locale('ko', 'KR')) { + expect(stringFragmentText.data, ':'); + expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); + expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); + expect(dayPeriodControlFinder, findsOne); + } else if (locale == const Locale('th', 'TH')) { + expect(stringFragmentText.data, ':'); + expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); + expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); + expect(dayPeriodControlFinder, findsOne); } await tester.tapAt(Offset(center.dx, center.dy - 50.0)); await finishPicker(tester); @@ -370,7 +458,6 @@ void main() { ) .first; - // TODO(yjbanov): also test `HH.mm` (in_ID), `a h:mm` (ko_KR) and `HH:mm น.` (th_TH) when we have .arb files for them final locales = [ const Locale('en', 'US'), //'h:mm a' const Locale('en', 'GB'), //'HH:mm' @@ -378,9 +465,15 @@ void main() { const Locale('fr', 'CA'), //'HH \'h\' mm' const Locale('zh', 'ZH'), //'ah:mm' const Locale('fa', 'IR'), //'H:mm' but RTL + const Locale('in', 'ID'), //'HH.mm' + const Locale('ko', 'KR'), //'a h:mm` + const Locale('th', 'TH'), //`HH:mm น.` ]; for (final locale in locales) { + await tester.pumpWidget( + const SizedBox(), + ); // this is needed to reset the widget tree and prevent state/Directionality leaks between loop iterations. await tester.pumpWidget( _TimePickerLauncher( onChanged: (TimeOfDay? time) {}, @@ -430,6 +523,22 @@ void main() { expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); expect(dayPeriodControlFinder, findsNothing); + } else if (locale == const Locale('in', 'ID')) { + // This is an LTR locale, it uses a dot separator instead of a standard colon. + expect(stringFragmentText.data, '.'); + expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); + expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); + expect(dayPeriodControlFinder, findsNothing); + } else if (locale == const Locale('ko', 'KR')) { + expect(stringFragmentText.data, ':'); + expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); + expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); + expect(dayPeriodControlFinder, findsOne); + } else if (locale == const Locale('th', 'TH')) { + expect(stringFragmentText.data, ':'); + expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); + expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); + expect(dayPeriodControlFinder, findsOne); } await finishPicker(tester); expect(tester.takeException(), isNot(throwsFlutterError)); @@ -455,7 +564,6 @@ void main() { ) .first; - // TODO(yjbanov): also test `HH.mm` (in_ID), `a h:mm` (ko_KR) and `HH:mm น.` (th_TH) when we have .arb files for them final locales = [ const Locale('en', 'US'), //'h:mm a' const Locale('en', 'GB'), //'HH:mm' @@ -463,9 +571,15 @@ void main() { const Locale('fr', 'CA'), //'HH \'h\' mm' const Locale('zh', 'ZH'), //'ah:mm' const Locale('fa', 'IR'), //'H:mm' but RTL + const Locale('in', 'ID'), //'HH.mm' + const Locale('ko', 'KR'), //'a h:mm` + const Locale('th', 'TH'), //`HH:mm น.` ]; for (final locale in locales) { + await tester.pumpWidget( + const SizedBox(), + ); // this is needed to reset the widget tree and prevent state/Directionality leaks between loop iterations. await tester.pumpWidget( _TimePickerLauncher( onChanged: (TimeOfDay? time) {}, @@ -514,6 +628,22 @@ void main() { expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); expect(dayPeriodControlFinder, findsNothing); + } else if (locale == const Locale('in', 'ID')) { + // This is an LTR locale, it uses a dot separator instead of a standard colon. + expect(stringFragmentText.data, '.'); + expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); + expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); + expect(dayPeriodControlFinder, findsNothing); + } else if (locale == const Locale('ko', 'KR')) { + expect(stringFragmentText.data, ':'); + expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); + expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); + expect(dayPeriodControlFinder, findsOne); + } else if (locale == const Locale('th', 'TH')) { + expect(stringFragmentText.data, ':'); + expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); + expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); + expect(dayPeriodControlFinder, findsOne); } await finishPicker(tester); expect(tester.takeException(), isNot(throwsFlutterError)); From 44f7b7c5cd0d1f7d4f89c7f3daa9a7358424ed76 Mon Sep 17 00:00:00 2001 From: abdessalem Date: Tue, 29 Sep 2026 21:48:45 +0100 Subject: [PATCH 2/3] remove changelog entry --- .../pending_changelogs/change_2026_09_19_1789835052875.yaml | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 packages/material_ui/pending_changelogs/change_2026_09_19_1789835052875.yaml diff --git a/packages/material_ui/pending_changelogs/change_2026_09_19_1789835052875.yaml b/packages/material_ui/pending_changelogs/change_2026_09_19_1789835052875.yaml deleted file mode 100644 index c3f9ad326700..000000000000 --- a/packages/material_ui/pending_changelogs/change_2026_09_19_1789835052875.yaml +++ /dev/null @@ -1,3 +0,0 @@ -changelog: | - - Adds tests for Indonesian, Korean and Thai locales tests in TimePicker i10n tests -version: patch From 59c63515253c77606a323f0068342a48eeabeb15 Mon Sep 17 00:00:00 2001 From: abdessalem Date: Tue, 29 Sep 2026 23:04:32 +0100 Subject: [PATCH 3/3] address gemini's comments --- .../test/l10n/time_picker_test.dart | 40 ++++++------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/packages/material_ui/test/l10n/time_picker_test.dart b/packages/material_ui/test/l10n/time_picker_test.dart index 45b27011a683..53b69afc5931 100644 --- a/packages/material_ui/test/l10n/time_picker_test.dart +++ b/packages/material_ui/test/l10n/time_picker_test.dart @@ -43,8 +43,8 @@ void main() { const Locale('zh', 'ZH'), //'ah:mm' const Locale('fa', 'IR'), //'H:mm' but RTL const Locale('in', 'ID'), //'HH.mm' - const Locale('ko', 'KR'), //'a h:mm` - const Locale('th', 'TH'), //`HH:mm น.` + const Locale('ko', 'KR'), //'a h:mm' + const Locale('th', 'TH'), //'HH:mm น.' ]; for (final locale in locales) { @@ -146,8 +146,8 @@ void main() { const Locale('zh', 'ZH'), //'ah:mm' const Locale('fa', 'IR'), //'H:mm' but RTL const Locale('in', 'ID'), //'HH.mm' - const Locale('ko', 'KR'), //'a h:mm` - const Locale('th', 'TH'), //`HH:mm น.` + const Locale('ko', 'KR'), //'a h:mm' + const Locale('th', 'TH'), //'HH:mm น.' ]; for (final locale in locales) { @@ -244,8 +244,8 @@ void main() { const Locale('zh', 'ZH'), //'ah:mm' const Locale('fa', 'IR'), //'H:mm' but RTL const Locale('in', 'ID'), //'HH.mm' - const Locale('ko', 'KR'), //'a h:mm` - const Locale('th', 'TH'), //`HH:mm น.` + const Locale('ko', 'KR'), //'a h:mm' + const Locale('th', 'TH'), //'HH:mm น.' ]; for (final locale in locales) { @@ -352,8 +352,8 @@ void main() { const Locale('zh', 'ZH'), //'ah:mm' const Locale('fa', 'IR'), //'H:mm' but RTL const Locale('in', 'ID'), //'HH.mm' - const Locale('ko', 'KR'), //'a h:mm` - const Locale('th', 'TH'), //`HH:mm น.` + const Locale('ko', 'KR'), //'a h:mm' + const Locale('th', 'TH'), //'HH:mm น.' ]; for (final locale in locales) { @@ -417,22 +417,6 @@ void main() { expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); expect(dayPeriodControlFinder, findsOne); - } else if (locale == const Locale('in', 'ID')) { - // This is an LTR locale, it uses a dot separator instead of a standard colon. - expect(stringFragmentText.data, '.'); - expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); - expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); - expect(dayPeriodControlFinder, findsNothing); - } else if (locale == const Locale('ko', 'KR')) { - expect(stringFragmentText.data, ':'); - expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); - expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); - expect(dayPeriodControlFinder, findsOne); - } else if (locale == const Locale('th', 'TH')) { - expect(stringFragmentText.data, ':'); - expect(hourLeftOffset, lessThan(stringFragmentLeftOffset)); - expect(stringFragmentLeftOffset, lessThan(minuteLeftOffset)); - expect(dayPeriodControlFinder, findsOne); } await tester.tapAt(Offset(center.dx, center.dy - 50.0)); await finishPicker(tester); @@ -466,8 +450,8 @@ void main() { const Locale('zh', 'ZH'), //'ah:mm' const Locale('fa', 'IR'), //'H:mm' but RTL const Locale('in', 'ID'), //'HH.mm' - const Locale('ko', 'KR'), //'a h:mm` - const Locale('th', 'TH'), //`HH:mm น.` + const Locale('ko', 'KR'), //'a h:mm' + const Locale('th', 'TH'), //'HH:mm น.' ]; for (final locale in locales) { @@ -572,8 +556,8 @@ void main() { const Locale('zh', 'ZH'), //'ah:mm' const Locale('fa', 'IR'), //'H:mm' but RTL const Locale('in', 'ID'), //'HH.mm' - const Locale('ko', 'KR'), //'a h:mm` - const Locale('th', 'TH'), //`HH:mm น.` + const Locale('ko', 'KR'), //'a h:mm' + const Locale('th', 'TH'), //'HH:mm น.' ]; for (final locale in locales) {