Send platformResolvedLocale from iOS embedder (#18519)
diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm
index ad00946..59eae77 100644
--- a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm
+++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm
@@ -759,27 +759,46 @@
#pragma mark - Locale updates
- (void)onLocaleUpdated:(NSNotification*)notification {
- NSArray<NSString*>* preferredLocales = [NSLocale preferredLanguages];
- NSMutableArray<NSString*>* data = [[NSMutableArray new] autorelease];
+ // [NSLocale currentLocale] provides an iOS resolved locale if the
+ // supported locales are exposed to the iOS embedder. Here, we get
+ // currentLocale and pass it to dart:ui
+ NSMutableArray<NSString*>* localeData = [[NSMutableArray new] autorelease];
+ NSLocale* platformResolvedLocale = [NSLocale currentLocale];
+ NSString* languageCode = [platformResolvedLocale objectForKey:NSLocaleLanguageCode];
+ NSString* countryCode = [platformResolvedLocale objectForKey:NSLocaleCountryCode];
+ NSString* scriptCode = [platformResolvedLocale objectForKey:NSLocaleScriptCode];
+ NSString* variantCode = [platformResolvedLocale objectForKey:NSLocaleVariantCode];
+ if (languageCode) {
+ [localeData addObject:languageCode];
+ [localeData addObject:(countryCode ? countryCode : @"")];
+ [localeData addObject:(scriptCode ? scriptCode : @"")];
+ [localeData addObject:(variantCode ? variantCode : @"")];
+ }
+ if (localeData.count != 0) {
+ [self.localizationChannel invokeMethod:@"setPlatformResolvedLocale" arguments:localeData];
+ }
+ // Get and pass the user's preferred locale list to dart:ui
+ localeData = [[NSMutableArray new] autorelease];
+ NSArray<NSString*>* preferredLocales = [NSLocale preferredLanguages];
for (NSString* localeID in preferredLocales) {
- NSLocale* currentLocale = [[[NSLocale alloc] initWithLocaleIdentifier:localeID] autorelease];
- NSString* languageCode = [currentLocale objectForKey:NSLocaleLanguageCode];
- NSString* countryCode = [currentLocale objectForKey:NSLocaleCountryCode];
- NSString* scriptCode = [currentLocale objectForKey:NSLocaleScriptCode];
- NSString* variantCode = [currentLocale objectForKey:NSLocaleVariantCode];
+ NSLocale* locale = [[[NSLocale alloc] initWithLocaleIdentifier:localeID] autorelease];
+ NSString* languageCode = [locale objectForKey:NSLocaleLanguageCode];
+ NSString* countryCode = [locale objectForKey:NSLocaleCountryCode];
+ NSString* scriptCode = [locale objectForKey:NSLocaleScriptCode];
+ NSString* variantCode = [locale objectForKey:NSLocaleVariantCode];
if (!languageCode) {
continue;
}
- [data addObject:languageCode];
- [data addObject:(countryCode ? countryCode : @"")];
- [data addObject:(scriptCode ? scriptCode : @"")];
- [data addObject:(variantCode ? variantCode : @"")];
+ [localeData addObject:languageCode];
+ [localeData addObject:(countryCode ? countryCode : @"")];
+ [localeData addObject:(scriptCode ? scriptCode : @"")];
+ [localeData addObject:(variantCode ? variantCode : @"")];
}
- if (data.count == 0) {
+ if (localeData.count == 0) {
return;
}
- [self.localizationChannel invokeMethod:@"setLocale" arguments:data];
+ [self.localizationChannel invokeMethod:@"setLocale" arguments:localeData];
}
@end
diff --git a/testing/scenario_app/ios/Scenarios/ScenariosUITests/LocalizationInitializationTest.m b/testing/scenario_app/ios/Scenarios/ScenariosUITests/LocalizationInitializationTest.m
index 974022e..3648eb9 100644
--- a/testing/scenario_app/ios/Scenarios/ScenariosUITests/LocalizationInitializationTest.m
+++ b/testing/scenario_app/ios/Scenarios/ScenariosUITests/LocalizationInitializationTest.m
@@ -25,11 +25,17 @@
- (void)testNoLocalePrepend {
NSTimeInterval timeout = 10.0;
+ // The locales received by dart:ui are exposed onBeginFrame via semantics label.
+ // There should only be one locale, since the default iOS app only has en_US as
+ // the locale. The list should consist of just the en locale.
XCUIElement* textInputSemanticsObject =
[self.application.textFields matchingIdentifier:@"[en]"].element;
+ XCTAssertTrue([textInputSemanticsObject waitForExistenceWithTimeout:timeout]);
- // The locales recieved by dart:ui are exposed onBeginFrame via semantics label.
- // There should only be one locale, as we have removed the locale prepend on iOS.
+ [textInputSemanticsObject tap];
+
+ // [NSLocale currentLocale] always includes a country code.
+ textInputSemanticsObject = [self.application.textFields matchingIdentifier:@"en_US"].element;
XCTAssertTrue([textInputSemanticsObject waitForExistenceWithTimeout:timeout]);
}
diff --git a/testing/scenario_app/lib/src/locale_initialization.dart b/testing/scenario_app/lib/src/locale_initialization.dart
index f20985e..e19bc41 100644
--- a/testing/scenario_app/lib/src/locale_initialization.dart
+++ b/testing/scenario_app/lib/src/locale_initialization.dart
@@ -16,6 +16,9 @@
: assert(window != null),
super(window);
+ int _tapCount = 0;
+
+ /// Start off by sending the supported locales list via semantics.
@override
void onBeginFrame(Duration duration) {
// Doesn't matter what we draw. Just paint white.
@@ -66,4 +69,46 @@
)).build()
);
}
+
+ /// Handle taps.
+ ///
+ /// Send changing information via semantics on each successive tap.
+ @override
+ void onPointerDataPacket(PointerDataPacket packet) {
+ String label;
+ switch(_tapCount) {
+ case 1: {
+ label = window.platformResolvedLocale.toString();
+ break;
+ }
+ // Expand for other test cases.
+ }
+
+ window.updateSemantics((SemanticsUpdateBuilder()
+ ..updateNode(
+ id: 0,
+ // SemanticsFlag.isTextField.
+ flags: 16,
+ // SemanticsAction.tap.
+ actions: 1,
+ rect: const Rect.fromLTRB(0.0, 0.0, 414.0, 48.0),
+ label: label,
+ textDirection: TextDirection.ltr,
+ textSelectionBase: 0,
+ textSelectionExtent: 0,
+ platformViewId: -1,
+ maxValueLength: -1,
+ currentValueLength: 0,
+ scrollChildren: 0,
+ scrollIndex: 0,
+ transform: Matrix4.identity().storage,
+ elevation: 0.0,
+ thickness: 0.0,
+ childrenInTraversalOrder: Int32List(0),
+ childrenInHitTestOrder: Int32List(0),
+ additionalActions: Int32List(0),
+ )).build()
+ );
+ _tapCount++;
+ }
}