// // GTMUILocalizer.m // // Copyright 2011 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy // of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. // #import "GTMDefines.h" #import "GTMUILocalizer.h" @interface GTMUILocalizer (GTMUILocalizerPrivate) - (void)localizeAccessibility:(id)object; // Never recursively call any of these methods. Always call // -[self localizeObject:recursively:]. - (void)localizeToolbar:(UIToolbar *)toolbar; - (void)localizeSegmentedControl:(UISegmentedControl *)segmentedControl; - (void)localizeView:(UIView *)view recursively:(BOOL)recursive; - (void)localizeButton:(UIButton *)button; @end @implementation GTMUILocalizer @synthesize owner = owner_; @synthesize otherObjectToLocalize = otherObjectToLocalize_; @synthesize yetAnotherObjectToLocalize = yetAnotherObjectToLocalize_; - (id)initWithBundle:(NSBundle *)bundle { if ((self = [super init])) { bundle_ = [bundle retain]; } return self; } - (void)dealloc { [bundle_ release]; [super dealloc]; } - (void)awakeFromNib { [super awakeFromNib]; id owner = self.owner; if (owner) { NSBundle *newBundle = [[self class] bundleForOwner:owner]; bundle_ = [newBundle retain]; [self localizeObject:self.owner recursively:YES]; [self localizeObject:self.otherObjectToLocalize recursively:YES]; [self localizeObject:self.yetAnotherObjectToLocalize recursively:YES]; } else { _GTMDevLog(@"Expected an owner set for %@", self); } // Clear the outlets. self.owner = nil; self.otherObjectToLocalize = nil; self.yetAnotherObjectToLocalize = nil; } + (NSBundle *)bundleForOwner:(id)owner { NSBundle *newBundle = nil; if (owner) { if ([owner isKindOfClass:[UIViewController class]]) { newBundle = [(UIViewController *)owner nibBundle]; } if (!newBundle) { newBundle = [NSBundle mainBundle]; } } return newBundle; } - (NSString *)localizedStringForString:(NSString *)string { NSString *localized = nil; if (bundle_ && [string hasPrefix:@"^"]) { NSString *notFoundValue = @"__GTM_NOT_FOUND__"; NSString *key = [string substringFromIndex:1]; localized = [bundle_ localizedStringForKey:key value:notFoundValue table:nil]; if ([localized isEqualToString:notFoundValue]) { localized = nil; } } return localized; } - (void)localizeObject:(id)object recursively:(BOOL)recursive { if (object) { if ([object isKindOfClass:[UIViewController class]]) { UIView *view = [object view]; [self localizeView:view recursively:recursive]; } else if ([object isKindOfClass:[UIToolbar class]]) { [self localizeToolbar:(UIToolbar*)object]; } else if ([object isKindOfClass:[UISegmentedControl class]]) { [self localizeSegmentedControl:(UISegmentedControl*)object]; } else if ([object isKindOfClass:[UIView class]]) { [self localizeView:(UIView *)object recursively:recursive]; } } } - (void)localizeToolbar:(UIToolbar *)toolbar { // NOTE: Like the header says, -items only gives us what is in the toolbar // which is usually the default items, if the toolbar supports customization // there is no way to fetch those possible items to tweak their contents. for (UIBarItem* item in [toolbar items]) { NSString *title = [item title]; if (title) { title = [self localizedStringForString:title]; if (title) { [item setTitle:title]; } } } } - (void)localizeSegmentedControl:(UISegmentedControl *)segmentedControl { // A UISegmentedControl uses a few objects as subviews, but they aren't // documented. It happened to work out that their inherritance was right // with the selectors they implemented that things localized, but iOS 6 // changed some of that, so they are now directly handled. NSUInteger numberOfSegments = segmentedControl.numberOfSegments; for (NSUInteger i = 0; i < numberOfSegments; ++i) { NSString *title = [segmentedControl titleForSegmentAtIndex:i]; if (title) { title = [self localizedStringForString:title]; if (title) { [segmentedControl setTitle:title forSegmentAtIndex:i]; } } } } - (void)localizeView:(UIView *)view recursively:(BOOL)recursive { if (view) { // Do accessibility on views. [self localizeAccessibility:view]; if (recursive) { for (UIView *subview in [view subviews]) { [self localizeObject:subview recursively:recursive]; } } // Specific types if ([view isKindOfClass:[UIButton class]]) { [self localizeButton:(UIButton *)view]; } // Then do all possible strings. if ([view respondsToSelector:@selector(title)] && [view respondsToSelector:@selector(setTitle:)]) { NSString *title = [view performSelector:@selector(title)]; if (title) { NSString *localizedTitle = [self localizedStringForString:title]; if (localizedTitle) { [view performSelector:@selector(setTitle:) withObject:localizedTitle]; } } } if ([view respondsToSelector:@selector(text)] && [view respondsToSelector:@selector(setText:)]) { NSString *text = [view performSelector:@selector(text)]; if (text) { NSString *localizedText = [self localizedStringForString:text]; if (localizedText) { [view performSelector:@selector(setText:) withObject:localizedText]; } } } if ([view respondsToSelector:@selector(placeholder)] && [view respondsToSelector:@selector(setPlaceholder:)]) { NSString *placeholder = [view performSelector:@selector(placeholder)]; if (placeholder) { NSString *localizedPlaceholder = [self localizedStringForString:placeholder]; if (localizedPlaceholder) { [view performSelector:@selector(setPlaceholder:) withObject:localizedPlaceholder]; } } } } } - (void)localizeAccessibility:(id)object { if ([object respondsToSelector:@selector(accessibilityHint)] && [object respondsToSelector:@selector(setAccessibilityHint:)]) { NSString *accessibilityHint = [object performSelector:@selector(accessibilityHint)]; if (accessibilityHint) { NSString *localizedAccessibilityHint = [self localizedStringForString:accessibilityHint]; if (localizedAccessibilityHint) { [object performSelector:@selector(setAccessibilityHint:) withObject:localizedAccessibilityHint]; } } } if ([object respondsToSelector:@selector(accessibilityLabel)] && [object respondsToSelector:@selector(setAccessibilityLabel:)]) { NSString *accessibilityLabel = [object performSelector:@selector(accessibilityLabel)]; if (accessibilityLabel) { NSString *localizedAccessibilityLabel = [self localizedStringForString:accessibilityLabel]; if (localizedAccessibilityLabel) { [object performSelector:@selector(setAccessibilityLabel:) withObject:localizedAccessibilityLabel]; } } } if ([object respondsToSelector:@selector(accessibilityValue)] && [object respondsToSelector:@selector(setAccessibilityValue:)]) { NSString *accessibilityValue = [object performSelector:@selector(accessibilityValue)]; if (accessibilityValue) { NSString *localizedAccessibilityValue = [self localizedStringForString:accessibilityValue]; if (localizedAccessibilityValue) { [object performSelector:@selector(setAccessibilityValue:) withObject:localizedAccessibilityValue]; } } } } - (void)localizeButton:(UIButton *)button { UIControlState allStates[] = { UIControlStateNormal, UIControlStateHighlighted, UIControlStateDisabled, UIControlStateSelected }; for (size_t idx = 0; idx < (sizeof(allStates)/sizeof(allStates[0])); ++idx) { UIControlState state = allStates[idx]; NSString *value = [button titleForState:state]; if (value) { NSString* localizedValue = [self localizedStringForString:value]; if (localizedValue) { [button setTitle:localizedValue forState:state]; } } } } @end