diff --git a/platform/macos/app/Base.lproj/MainMenu.xib b/platform/macos/app/Base.lproj/MainMenu.xib index 4efb8d4c46f..cb9905d4a1c 100644 --- a/platform/macos/app/Base.lproj/MainMenu.xib +++ b/platform/macos/app/Base.lproj/MainMenu.xib @@ -434,6 +434,27 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/platform/macos/app/MapDocument.m b/platform/macos/app/MapDocument.m index c05a85f9601..d2e6a0f810c 100644 --- a/platform/macos/app/MapDocument.m +++ b/platform/macos/app/MapDocument.m @@ -64,6 +64,7 @@ @implementation MapDocument { NSUInteger _droppedPinCounter; NSNumberFormatter *_spellOutNumberFormatter; + BOOL _isLocalizingLabels; BOOL _showsToolTipsOnDroppedPins; BOOL _randomizesCursorsOnDroppedPins; BOOL _isTouringWorld; @@ -123,10 +124,12 @@ - (void)userDefaultsDidChange:(NSNotification *)notification { - (void)window:(NSWindow *)window willEncodeRestorableState:(NSCoder *)state { [state encodeObject:self.mapView.styleURL forKey:@"MBXMapViewStyleURL"]; + [state encodeBool:_isLocalizingLabels forKey:@"MBXLocalizeLabels"]; } - (void)window:(NSWindow *)window didDecodeRestorableState:(NSCoder *)state { self.mapView.styleURL = [state decodeObjectForKey:@"MBXMapViewStyleURL"]; + _isLocalizingLabels = [state decodeBoolForKey:@"MBXLocalizeLabels"]; } #pragma mark Services @@ -325,6 +328,60 @@ - (void)deleteStyleLayersAtArrangedObjectIndexes:(NSIndexSet *)indices { [self.styleLayersArrayController removeObjectsAtArrangedObjectIndexes:indices]; } +- (IBAction)setLabelLanguage:(NSMenuItem *)sender { + _isLocalizingLabels = sender.tag; + [self updateLabels]; +} + +- (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) { + if (![layer isKindOfClass:[MGLSymbolStyleLayer class]]) { + continue; + } + + if ([layer.textField isKindOfClass:[MGLStyleConstantValue class]]) { + NSString *textField = [(MGLStyleConstantValue *)layer.textField rawValue]; + textField = [nameTokenExpression stringByReplacingMatchesInString:textField + options:0 + range:NSMakeRange(0, textField.length) + withTemplate:preferredNameToken]; + layer.textField = [MGLStyleValue valueWithRawValue:textField]; + } else if ([layer.textField isKindOfClass:[MGLStyleFunction class]]) { + MGLStyleFunction *function = (MGLStyleFunction *)layer.textField; + NSMutableDictionary *stops = function.stops.mutableCopy; + [stops enumerateKeysAndObjectsUsingBlock:^(NSNumber *zoomLevel, MGLStyleConstantValue *stop, BOOL *done) { + NSString *textField = stop.rawValue; + textField = [nameTokenExpression stringByReplacingMatchesInString:textField + options:0 + range:NSMakeRange(0, textField.length) + withTemplate:preferredNameToken]; + stops[zoomLevel] = [MGLStyleValue valueWithRawValue:textField]; + }]; + function.stops = stops; + layer.textField = function; + } + } +} + +- (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; @@ -736,6 +793,14 @@ - (BOOL)validateMenuItem:(NSMenuItem *)menuItem { if (menuItem.action == @selector(deleteStyleLayers:)) { return self.styleLayersTableView.clickedRow >= 0 || self.styleLayersTableView.selectedRow >= 0; } + if (menuItem.action == @selector(setLabelLanguage:)) { + 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]; + } + return YES; + } if (menuItem.action == @selector(manipulateStyle:)) { return YES; } @@ -922,6 +987,10 @@ - (BOOL)splitView:(NSSplitView *)splitView shouldCollapseSubview:(NSView *)subvi #pragma mark MGLMapViewDelegate methods +- (void)mapView:(MGLMapView *)mapView didFinishLoadingStyle:(MGLStyle *)style { + [self updateLabels]; +} + - (BOOL)mapView:(MGLMapView *)mapView annotationCanShowCallout:(id )annotation { return YES; }