Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 32 additions & 13 deletions shell/platform/darwin/ios/framework/Source/FlutterEngine.mm
Original file line number Diff line number Diff line change
Expand Up @@ -759,27 +759,46 @@ - (void)setIsGpuDisabled:(BOOL)value {
#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) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a pointer to the Android side of platform-resolved locales? That just helps with making sure that I can see what I'm comparing this to when looking at this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,17 @@ - (void)setUp {
- (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]);

[textInputSemanticsObject tap];

// 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.
// [NSLocale currentLocale] always includes a country code.
textInputSemanticsObject = [self.application.textFields matchingIdentifier:@"en_US"].element;
XCTAssertTrue([textInputSemanticsObject waitForExistenceWithTimeout:timeout]);
}

Expand Down
45 changes: 45 additions & 0 deletions testing/scenario_app/lib/src/locale_initialization.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ class LocaleInitialization extends Scenario {
: 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.
Expand Down Expand Up @@ -66,4 +69,46 @@ class LocaleInitialization extends Scenario {
)).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++;
}
}