summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMinh Nguyễn <mxn@1ec5.org>2016-12-12 16:05:56 -0800
committerMinh Nguyễn <mxn@1ec5.org>2016-12-20 21:05:40 -0800
commitf431b1b73ba6181cbdc35ae712e9ad1f1cca4f98 (patch)
treec1d33d4500276b4fc7a2a99f607b79d627051ba5
parent224fe6b96f18a4e86f7d26e1e5dff5753d9e8483 (diff)
downloadqtlocation-mapboxgl-f431b1b73ba6181cbdc35ae712e9ad1f1cca4f98.tar.gz
[macos] Refactored label localization
Localize only Mapbox Streets v6–v7, and do so more systematically than before.
-rw-r--r--platform/macos/app/MGLVectorSource+MBXAdditions.h15
-rw-r--r--platform/macos/app/MGLVectorSource+MBXAdditions.m49
-rw-r--r--platform/macos/app/MapDocument.m67
-rw-r--r--platform/macos/macos.xcodeproj/project.pbxproj6
4 files changed, 105 insertions, 32 deletions
diff --git a/platform/macos/app/MGLVectorSource+MBXAdditions.h b/platform/macos/app/MGLVectorSource+MBXAdditions.h
new file mode 100644
index 0000000000..312081ec51
--- /dev/null
+++ b/platform/macos/app/MGLVectorSource+MBXAdditions.h
@@ -0,0 +1,15 @@
+#import <Mapbox/Mapbox.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MGLVectorSource (MBXAdditions)
+
++ (nullable NSString *)preferredMapboxStreetsLanguage;
+
+- (NS_DICTIONARY_OF(NSString *, NSString *) *)localizedKeysByKeyForPreferredLanguage:(nullable NSString *)preferredLanguage;
+
+@property (nonatomic, readonly, getter=isMapboxStreets) BOOL mapboxStreets;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/macos/app/MGLVectorSource+MBXAdditions.m b/platform/macos/app/MGLVectorSource+MBXAdditions.m
new file mode 100644
index 0000000000..f59b72aa9f
--- /dev/null
+++ b/platform/macos/app/MGLVectorSource+MBXAdditions.m
@@ -0,0 +1,49 @@
+#import "MGLVectorSource+MBXAdditions.h"
+
+@implementation MGLVectorSource (MBXAdditions)
+
++ (NS_SET_OF(NSString *) *)mapboxStreetsLanguages {
+ // https://www.mapbox.com/vector-tiles/mapbox-streets-v7/#overview
+ static dispatch_once_t onceToken;
+ static NS_SET_OF(NSString *) *mapboxStreetsLanguages;
+ dispatch_once(&onceToken, ^{
+ mapboxStreetsLanguages = [NSSet setWithObjects:@"en", @"es", @"fr", @"de", @"ru", @"zh", nil];
+ });
+ return mapboxStreetsLanguages;
+}
+
++ (nullable NSString *)preferredMapboxStreetsLanguage {
+ for (NSString *language in [NSLocale preferredLanguages]) {
+ NSString *languageCode = [[NSLocale localeWithLocaleIdentifier:language] objectForKey:NSLocaleLanguageCode];
+ if ([[MGLVectorSource mapboxStreetsLanguages] containsObject:languageCode]) {
+ return languageCode;
+ }
+ }
+ return nil;
+}
+
+- (BOOL)isMapboxStreets {
+ NSURL *url = self.configurationURL;
+ if (![url.scheme isEqualToString:@"mapbox"]) {
+ return NO;
+ }
+ NSArray *identifiers = [url.host componentsSeparatedByString:@","];
+ return [identifiers containsObject:@"mapbox.mapbox-streets-v7"] || [identifiers containsObject:@"mapbox.mapbox-streets-v6"];
+}
+
+- (NS_DICTIONARY_OF(NSString *, NSString *) *)localizedKeysByKeyForPreferredLanguage:(nullable NSString *)preferredLanguage {
+ if (!self.mapboxStreets) {
+ return @{};
+ }
+
+ // Replace {name} and {name_*} with the matching localized name tag.
+ NSString *localizedKey = preferredLanguage ? [NSString stringWithFormat:@"name_%@", preferredLanguage] : @"name";
+ NSMutableDictionary *localizedKeysByKey = [NSMutableDictionary dictionaryWithObject:localizedKey forKey:@"name"];
+ for (NSString *languageCode in [MGLVectorSource mapboxStreetsLanguages]) {
+ NSString *key = [NSString stringWithFormat:@"name_%@", languageCode];
+ localizedKeysByKey[key] = localizedKey;
+ }
+ return localizedKeysByKey;
+}
+
+@end
diff --git a/platform/macos/app/MapDocument.m b/platform/macos/app/MapDocument.m
index 2c31610779..705ebb8a45 100644
--- a/platform/macos/app/MapDocument.m
+++ b/platform/macos/app/MapDocument.m
@@ -4,6 +4,8 @@
#import "LimeGreenStyleLayer.h"
#import "DroppedPinAnnotation.h"
+#import "MGLVectorSource+MBXAdditions.h"
+
#import <Mapbox/Mapbox.h>
static NSString * const MGLDroppedPinAnnotationImageIdentifier = @"dropped";
@@ -331,36 +333,50 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
- (IBAction)setLabelLanguage:(NSMenuItem *)sender {
_isLocalizingLabels = sender.tag;
- [self updateLabels];
+ [self reload:sender];
}
- (void)updateLabels {
- NSString *preferredLanguageCode = self.preferredLanguageCode;
- NSString *preferredNameToken = _isLocalizingLabels ? [NSString stringWithFormat:@"{name_%@}", preferredLanguageCode] : @"{name}";
- NSRegularExpression *nameTokenExpression = [NSRegularExpression regularExpressionWithPattern:@"\\{name(?:_\\w{2})?\\}" options:0 error:NULL];
-
- for (MGLSymbolStyleLayer *layer in self.mapView.style.layers) {
+ MGLStyle *style = self.mapView.style;
+ NSString *preferredLanguage = _isLocalizingLabels ? ([MGLVectorSource preferredMapboxStreetsLanguage] ?: @"en") : nil;
+ NSMutableDictionary *localizedKeysByKeyBySourceIdentifier = [NSMutableDictionary dictionary];
+ for (MGLSymbolStyleLayer *layer in style.layers) {
if (![layer isKindOfClass:[MGLSymbolStyleLayer class]]) {
continue;
}
+ MGLVectorSource *source = (MGLVectorSource *)[style sourceWithIdentifier:layer.sourceIdentifier];
+ if (![source isKindOfClass:[MGLVectorSource class]] || !source.mapboxStreets) {
+ continue;
+ }
+
+ NSDictionary *localizedKeysByKey = localizedKeysByKeyBySourceIdentifier[layer.sourceIdentifier];
+ if (!localizedKeysByKey) {
+ localizedKeysByKey = localizedKeysByKeyBySourceIdentifier[layer.sourceIdentifier] = [source localizedKeysByKeyForPreferredLanguage:preferredLanguage];
+ }
+
+ NSString *(^stringByLocalizingString)(NSString *) = ^ NSString * (NSString *string) {
+ NSMutableString *localizedString = string.mutableCopy;
+ [localizedKeysByKey enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull localizedKey, BOOL * _Nonnull stop) {
+ NSAssert([key isKindOfClass:[NSString class]], @"key is not a string");
+ NSAssert([localizedKey isKindOfClass:[NSString class]], @"localizedKey is not a string");
+ [localizedString replaceOccurrencesOfString:[NSString stringWithFormat:@"{%@}", key]
+ withString:[NSString stringWithFormat:@"{%@}", localizedKey]
+ options:0
+ range:NSMakeRange(0, localizedString.length)];
+ }];
+ return localizedString;
+ };
+
if ([layer.textField isKindOfClass:[MGLStyleConstantValue class]]) {
NSString *textField = [(MGLStyleConstantValue<NSString *> *)layer.textField rawValue];
- textField = [nameTokenExpression stringByReplacingMatchesInString:textField
- options:0
- range:NSMakeRange(0, textField.length)
- withTemplate:preferredNameToken];
- layer.textField = [MGLStyleValue<NSString *> valueWithRawValue:textField];
+ layer.textField = [MGLStyleValue<NSString *> valueWithRawValue:stringByLocalizingString(textField)];
} else if ([layer.textField isKindOfClass:[MGLStyleFunction class]]) {
MGLStyleFunction *function = (MGLStyleFunction<NSString *> *)layer.textField;
NSMutableDictionary *stops = function.stops.mutableCopy;
[stops enumerateKeysAndObjectsUsingBlock:^(NSNumber *zoomLevel, MGLStyleConstantValue<NSString *> *stop, BOOL *done) {
NSString *textField = stop.rawValue;
- textField = [nameTokenExpression stringByReplacingMatchesInString:textField
- options:0
- range:NSMakeRange(0, textField.length)
- withTemplate:preferredNameToken];
- stops[zoomLevel] = [MGLStyleValue<NSString *> valueWithRawValue:textField];
+ stops[zoomLevel] = [MGLStyleValue<NSString *> valueWithRawValue:stringByLocalizingString(textField)];
}];
function.stops = stops;
layer.textField = function;
@@ -368,21 +384,6 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
}
}
-- (NSString *)preferredLanguageCode {
- // Languages supported by Mapbox Streets v10.
- NSSet *supportedLanguages = [NSSet setWithObjects:@"en", @"es", @"fr", @"de", @"ru", @"zh", nil];
- NSArray *preferredLanguages = [NSLocale preferredLanguages];
-
- for (NSString *language in preferredLanguages) {
- NSString *languageCode = [[NSLocale localeWithLocaleIdentifier:language] objectForKey:NSLocaleLanguageCode];
- if ([supportedLanguages containsObject:languageCode]) {
- return languageCode;
- }
- }
-
- return @"en";
-}
-
- (void)applyPendingState {
if (_inheritedStyleURL) {
self.mapView.styleURL = _inheritedStyleURL;
@@ -836,7 +837,9 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
menuItem.state = menuItem.tag == _isLocalizingLabels ? NSOnState: NSOffState;
if (menuItem.tag) {
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:[NSBundle mainBundle].developmentLocalization];
- menuItem.title = [locale displayNameForKey:NSLocaleIdentifier value:self.preferredLanguageCode];
+ NSString *preferredLanguage = [MGLVectorSource preferredMapboxStreetsLanguage];
+ menuItem.enabled = !!preferredLanguage;
+ menuItem.title = [locale displayNameForKey:NSLocaleIdentifier value:preferredLanguage ?: @"Preferred Language"];
}
return YES;
}
diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj
index 5edb4429fb..e68d5f1bf5 100644
--- a/platform/macos/macos.xcodeproj/project.pbxproj
+++ b/platform/macos/macos.xcodeproj/project.pbxproj
@@ -211,6 +211,7 @@
DAEDC4371D606291000224FF /* MGLAttributionButtonTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DAEDC4361D606291000224FF /* MGLAttributionButtonTests.m */; };
DAF0D80E1DFE0E5D00B28378 /* MGLPointCollection_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DAF0D80D1DFE0E5D00B28378 /* MGLPointCollection_Private.h */; };
DAF0D8161DFE6B1800B28378 /* MGLAttributionInfo_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = DAF0D8151DFE6B1800B28378 /* MGLAttributionInfo_Private.h */; };
+ DAF0D81C1DFF567C00B28378 /* MGLVectorSource+MBXAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DAF0D81B1DFF567C00B28378 /* MGLVectorSource+MBXAdditions.m */; };
DD0902B21DB1AC6400C5BDCE /* MGLNetworkConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = DD0902AF1DB1AC6400C5BDCE /* MGLNetworkConfiguration.m */; };
DD0902B31DB1AC6400C5BDCE /* MGLNetworkConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = DD0902B01DB1AC6400C5BDCE /* MGLNetworkConfiguration.h */; };
DD58A4C91D822C6700E1F038 /* MGLExpressionTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DD58A4C71D822C6200E1F038 /* MGLExpressionTests.mm */; };
@@ -475,6 +476,8 @@
DAEDC4361D606291000224FF /* MGLAttributionButtonTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLAttributionButtonTests.m; sourceTree = "<group>"; };
DAF0D80D1DFE0E5D00B28378 /* MGLPointCollection_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLPointCollection_Private.h; sourceTree = "<group>"; };
DAF0D8151DFE6B1800B28378 /* MGLAttributionInfo_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAttributionInfo_Private.h; sourceTree = "<group>"; };
+ DAF0D81A1DFF567C00B28378 /* MGLVectorSource+MBXAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MGLVectorSource+MBXAdditions.h"; sourceTree = "<group>"; };
+ DAF0D81B1DFF567C00B28378 /* MGLVectorSource+MBXAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MGLVectorSource+MBXAdditions.m"; sourceTree = "<group>"; };
DD0902AF1DB1AC6400C5BDCE /* MGLNetworkConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLNetworkConfiguration.m; sourceTree = "<group>"; };
DD0902B01DB1AC6400C5BDCE /* MGLNetworkConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLNetworkConfiguration.h; sourceTree = "<group>"; };
DD58A4C71D822C6200E1F038 /* MGLExpressionTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLExpressionTests.mm; path = ../../darwin/test/MGLExpressionTests.mm; sourceTree = "<group>"; };
@@ -623,6 +626,8 @@
DA839E9B1CC2E3400062CAFB /* MapDocument.h */,
DA839E9C1CC2E3400062CAFB /* MapDocument.m */,
DA839E9E1CC2E3400062CAFB /* MapDocument.xib */,
+ DAF0D81A1DFF567C00B28378 /* MGLVectorSource+MBXAdditions.h */,
+ DAF0D81B1DFF567C00B28378 /* MGLVectorSource+MBXAdditions.m */,
DAE6C2E91CC3050F00DB3429 /* OfflinePackNameValueTransformer.h */,
DAE6C2EA1CC3050F00DB3429 /* OfflinePackNameValueTransformer.m */,
DAA48EFB1D6A4731006A7E36 /* StyleLayerIconTransformer.h */,
@@ -1219,6 +1224,7 @@
DAE6C2F11CC3050F00DB3429 /* TimeIntervalTransformer.m in Sources */,
DA839E9A1CC2E3400062CAFB /* main.m in Sources */,
DA839E971CC2E3400062CAFB /* AppDelegate.m in Sources */,
+ DAF0D81C1DFF567C00B28378 /* MGLVectorSource+MBXAdditions.m in Sources */,
DAE6C2F01CC3050F00DB3429 /* OfflinePackNameValueTransformer.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;