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 4 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) {
Copy link
Copy Markdown

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
Copy Markdown
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 perferred locale list to dart:ui
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit:

Suggested change
// Get and pass the user's perferred locale list to dart:ui
// 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,16 @@ - (void)setUp {
- (void)testNoLocalePrepend {
NSTimeInterval timeout = 10.0;

// The locales recieved by dart:ui are exposed onBeginFrame via semantics label.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit:

Suggested change
// The locales recieved by dart:ui are exposed onBeginFrame via semantics label.
// The locales received by dart:ui are exposed onBeginFrame via semantics label.

// There should only be one locale, as we have removed the locale prepend on iOS.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Maybe tweak the comment a little to describe why there should only be one locale. A newer Flutter developer reading this might get confused about what the "locale prepend on iOS" is since it never existed before the PR where it was removed.

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]);
}

Expand Down
40 changes: 40 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,8 @@ class LocaleInitialization extends Scenario {
: assert(window != null),
super(window);

int tapCount = 0;
Copy link
Copy Markdown

@shihaohong shihaohong May 20, 2020

Choose a reason for hiding this comment

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

nit, here and elsewhere (might be why the analyzer is failing too)

Suggested change
int tapCount = 0;
int _tapCount = 0;


@override
void onBeginFrame(Duration duration) {
// Doesn't matter what we draw. Just paint white.
Expand Down Expand Up @@ -66,4 +68,42 @@ 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 0: label = window.platformResolvedLocale.toString(); break;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: I find this syntax hard to read even though it's shorter, I'd prefer:

Suggested change
case 0: label = window.platformResolvedLocale.toString(); break;
case 0: {
label = window.platformResolvedLocale.toString();
}
break;

Copy link
Copy Markdown

@shihaohong shihaohong May 20, 2020

Choose a reason for hiding this comment

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

Also, to make sure, keeping track of the _tapCount is solely to make sure we set the semantics label with the platform resolve locale on the first tap? Is there a reason we want it to only set it the first time?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I expect to extend this in the future with further cases, and this allows easy extension by just adding an extra case here and sending another tap.

// Expand for other test cases.
}

window.updateSemantics((SemanticsUpdateBuilder()
..updateNode(
id: 0,
// SemanticsFlag.isTextField and SemanticsFlag.isFocused.
flags: 48,
actions: 18433,
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++;
}
}