-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Localize expressions more thoroughly #11651
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR is looking good.
platform/darwin/src/MGLStyle.mm
Outdated
} | ||
} | ||
if (!locale) { | ||
locale = [NSLocale localeWithLocaleIdentifier:@"mul"]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
|
||
case NSFunctionExpressionType: { | ||
NSExpression *operand = self.operand; | ||
NSExpression *localizedOperand = [operand mgl_expressionLocalizedIntoLocale:locale replacingTokens:NO]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to this:
@param replacesTokens
YES
to localize{token}
syntax in constant value subexpressions;NO
otherwise.
NSExpression *localizedOperand = [operand mgl_expressionLocalizedIntoLocale:locale replacingTokens:NO];
overrides the value passed in replacesTokens
. What would happen if the function expression contains a constant value? should not this be behave accordingly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, this deserves clarification: the replacesTokens
parameter is only meant to replace the legacy token syntax, but that’s a subset of the syntax that we want to localize. The only reason that the replacesTokens
functionality is supported at all in functions is that three functions in particular may represent style functions, which can contain tokens. Nothing else in the expression language can contain tokens.
Having said all that, #11659 means that tokens are only supported for the MGLSymbolStyleLayer.text
and iconImageName
properties’ getters, not their setters. So as long as we come up with an expression to set, we need to upgrade all the tokens within the expression to key path expressions. 023624360aa37c4d984b3f49484c8d3552b2b414 does that, but only as a post-localization step on individual function calls.
We may end up needing to unconditionally upgrade the entire expression upfront, before even looking at whether to localize anything. If we do that, then the separate replacesTokens
functionality will no longer be necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
f3efae542788ff0978a3ba833a0b52a8e20e5af1 removes the replacesTokens
parameter outright. Instead, token upgrading happens as part of the property’s getter, which limits the scope and makes it easy to remove later on.
38a53e7
to
0de40b7
Compare
@@ -96,7 +96,7 @@ + (NSString *)preferredMapboxStreetsLanguage { | |||
mostSpecificLanguage = language; | |||
} | |||
} | |||
return mostSpecificLanguage ?: @"en"; | |||
return mostSpecificLanguage; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This fallback turned out to be redundant: preferredLanguages
is never empty, so mostSpecificLanguage
is never nil
.
+[NSBundle preferredLocalizationsFromArray:forPreferences:]
never returns an empty array of languages, because it always falls back to English if none of the available locales matches one of the preferred locales. To maximize the flexibility of the label localization functionality, I’ve been thinking it would be better if we fall back to name
rather than name_en
. That way, for instance, if a user prefers Hebrew – which is supported by the map SDK’s UI – they can at least get Hebrew labels in Israel rather than English everywhere.
The trick will be to distinguish between the case where +[NSBundle preferredLocalizationsFromArray:forPreferences:]
returns English because the locale really does match English (en
, en-US
, eng-AU
, etc.) from the case where it chose English as a last resort. I’m open to doing this as a followup task, potentially in a patch release, unless a solution comes to mind.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests LGTM 👍
} | ||
} | ||
return self; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that {Camera,Source,Composite}Function
now track whether or not they were constructed directly from an expression (as opposed to being converted from a stop function):
bool isExpression; |
It's likely not worth the extra complexity, but just noting that if needed, we could try to propagate that metadata to the NSExpression representation for an expression so that you could only do this replacement for those that originally came from stop functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think fixing #11659 would be more effective than trying to make the workaround for it more robust, but it’s good to know, for future reference, that mbgl is capable of persisting these distinctions.
This PR drops the ability to “delocalize” a style, which was previously possible by setting
If the developer needs to delocalize a style, they can take either of the following approaches:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍🏼
The broader feature is new to v4.0.0 as well.
Replaced the MGLStyle.localizesLabels property with a -localizeLabelsIntoLocale: method that allows the caller to specify the locale to localize into. Also exposed a per-expression localization method for developers who want to vary behavior from layer to layer.
Separated token upgrading into a separate process that only happens as part of the MGLSymbolStyleLayer.text and MGLSymbolStyleLayer.iconImageName properties’ getters, so that it’s easy to remove later when mbgl changes obviate this workaround. Removed the replacesTokens parameter to the expression localization methods.
Fixed a build warning.
For consistency, replace tokens with key paths in all string-typed style paint and layout properties.
Added tests for replacement of tokens with key paths in expressions. Fixed token replacement for raw strings in stop dictionaries. Avoid sticking a single string inside an mgl_join: call.
Added unit tests of token replacement and localization of expressions. Only NSExpression is responsible for resolving the preferred language now, since NSLocale tends to tack a region code onto the locale identifier and the NSExpression method can be called independently anyways. Added a private variation of +[MGLVectorTileSource preferredMapboxStreetsLanguage] that takes an array of preferred languages. Fixed localization of non-expressions in stop dictionaries.
501dbf7
to
6c87574
Compare
Replaced the
MGLStyle.localizesLabels
property with a-localizeLabelsIntoLocale:
method that allows the caller to specify the locale to localize into. This method relies on a new-[NSExpression(MGLAdditions) mgl_expressionLocalizedIntoLocale:]
method, for developers who want to vary behavior from layer to layer. (This will simplify mapbox/mapbox-navigation-ios#1076 considerably.)Due to #11659, this PR also adds some logic to automatically upgrade the legacy
{token}
syntax to key path expressions for string-typed property getters.More to come:
MGL_MATCH()
(equivalent to categorical interpolation)Localize(Localize abbreviations when localizing labels #9902){abbr}
usageAutomatically update localized styles when the locale changes?(Automatically relocalize labels when system locale changes #11660)Fixes #10713.
/cc @fabian-guerra @anandthakker @bsudekum @nickidlugash @langsmith