diff --git a/lib/ui/platform_dispatcher.dart b/lib/ui/platform_dispatcher.dart index a218b283e5d16..dc7223b79cc5d 100644 --- a/lib/ui/platform_dispatcher.dart +++ b/lib/ui/platform_dispatcher.dart @@ -549,9 +549,10 @@ class PlatformDispatcher { /// This is the first locale selected by the user and is the user's primary /// locale (the locale the device UI is displayed in) /// - /// This is equivalent to `locales.first` and will provide an empty non-null - /// locale if the [locales] list has not been set or is empty. - Locale get locale => locales.first; + /// This is equivalent to `locales.first`, except that it will provide an + /// undefined (using the language tag "und") non-null locale if the [locales] + /// list has not been set or is empty. + Locale get locale => locales.isEmpty ? const Locale.fromSubtags() : locales.first; /// The full system-reported supported locales of the device. /// @@ -1318,6 +1319,10 @@ class Locale { /// [region](https://github.com/unicode-org/cldr/blob/master/common/validity/region.xml) for /// each of languageCode, scriptCode and countryCode respectively. /// + /// The [languageCode] subtag is optional. When there is no language subtag, + /// the parameter should be omitted or set to "und". When not supplied, the + /// [languageCode] defaults to "und", an undefined language code. + /// /// The [countryCode] subtag is optional. When there is no country subtag, /// the parameter should be omitted or passed `null` instead of an empty-string. /// diff --git a/lib/web_ui/lib/src/engine/platform_dispatcher.dart b/lib/web_ui/lib/src/engine/platform_dispatcher.dart index 78e9124361b52..7f6ce039c5a5c 100644 --- a/lib/web_ui/lib/src/engine/platform_dispatcher.dart +++ b/lib/web_ui/lib/src/engine/platform_dispatcher.dart @@ -546,6 +546,10 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher { EngineSemanticsOwner.instance.updateSemantics(update); } + /// This is equivalent to `locales.first`, except that it will provide an + /// undefined (using the language tag "und") non-null locale if the [locales] + /// list has not been set or is empty. + /// /// We use the first locale in the [locales] list instead of the browser's /// built-in `navigator.language` because browsers do not agree on the /// implementation. @@ -554,7 +558,7 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher { /// /// * https://developer.mozilla.org/en-US/docs/Web/API/NavigatorLanguage/languages, /// which explains browser quirks in the implementation notes. - ui.Locale get locale => locales.first; + ui.Locale get locale => locales.isEmpty ? const ui.Locale.fromSubtags() : locales.first; /// The full system-reported supported locales of the device. /// diff --git a/lib/web_ui/test/engine/window_test.dart b/lib/web_ui/test/engine/window_test.dart index 04ae42243e402..6dc9497c04c54 100644 --- a/lib/web_ui/test/engine/window_test.dart +++ b/lib/web_ui/test/engine/window_test.dart @@ -292,6 +292,7 @@ void testMain() { // that the list is populated again). EnginePlatformDispatcher.instance.debugResetLocales(); expect(window.locales, isEmpty); + expect(window.locale, equals(const ui.Locale.fromSubtags())); expect(localeChangedCount, 0); html.window.dispatchEvent(html.Event('languagechange')); expect(window.locales, isNotEmpty); diff --git a/testing/dart/window_hooks_integration_test.dart b/testing/dart/window_hooks_integration_test.dart index 27b2da80d8e9a..91c2036dbda91 100644 --- a/testing/dart/window_hooks_integration_test.dart +++ b/testing/dart/window_hooks_integration_test.dart @@ -426,4 +426,17 @@ void main() { expectEquals(window.padding.bottom, 0.0); expectEquals(window.systemGestureInsets.bottom, 44.0); }); + + test('PlatformDispatcher.locale returns unknown locale when locales is set to empty list', () { + late Locale locale; + runZoned(() { + window.onLocaleChanged = () { + locale = PlatformDispatcher.instance.locale; + }; + }); + + _updateLocales([]); + expectEquals(locale, const Locale.fromSubtags()); + expectEquals(locale.languageCode, 'und'); + }); }