Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I had a similar requirement for a Kiosk mode iPad app with tabbed navigation. Not only did the app need to support on-the-fly language changes, but had to do so knowing that most of the tabs were already loaded from the nibs since the app was only restarted (on average) about once a week when a new version was loaded.</p> <p>I tried several suggestions to leverage the existing Apple localization mechanisms and they all had serious drawbacks, including wonky support in XCode 4.2 for localized nibs -- my IBoutlet connection variables would appear to be set correctly in IB, but at runtime they would often be null!?</p> <p>I wound up implementing a class that mimicked the Apple NSLocalizedString class but which could handle runtime changes, and whenever a language change was made by a user my class posted a notification. Screens that needed localized strings (and images) to change declared a handleLocaleChange method, which was called at viewDidLoad, and whenever the LocaleChangedNotification was posted. </p> <p>All of my buttons and graphics were designed to be language independent, although the title text and label text was typically updated in response to locale changes. If I had to change images, I could have done so in the handleLocaleChange methods for each screen, I suppose. </p> <p>Here is the code. It includes some support for nib/bundle paths which I actually don't use in the final project.</p> <p>MyLanguage.h // // MyLanguage.h // //</p> <pre><code>#import &lt;Foundation/Foundation.h&gt; #define DEFAULT_DICTIONARY_FOR_STRINGS @"" #define ACCESSING_ALTERNATE_DICTIONARY_SETS_DEFAULT 1 #define LANGUAGE_ENGLISH_INT 0 #define LANGUAGE_SPANISH_INT 1 #define LANGUAGE_ENGLISH_SHORT_ID @"en" #define LANGUAGE_SPANISH_SHORT_ID @"es" #define LANGUAGE_CHANGED_NOTIFICATION @"LANGUAGE_CHANGED" @interface MyLanguage : NSObject { NSString *currentLanguage; NSDictionary *currentDictionary; NSBundle *currentLanguageBundle; } +(void) setLanguage:(NSString *)languageName; +(NSString *)stringFor:(NSString *)srcString forLanguage:(NSString *)languageName; +(NSString *)stringFor:(NSString *)srcString; + (MyLanguage *)singleton; @property (nonatomic, retain) NSBundle *currentLanguageBundle; @property (nonatomic, retain) NSString *currentLanguage; @property (nonatomic, retain) NSDictionary *currentDictionary; @end </code></pre> <p>MyLanguage.m: // // MyLanguage.m</p> <pre><code>#import "MyLanguage.h" #import "Valet.h" #define GUI_STRING_FILE_POSTFIX @"GUIStrings.plist" @implementation MyLanguage @synthesize currentLanguage; @synthesize currentDictionary; @synthesize currentLanguageBundle; +(NSDictionary *)getDictionaryNamed:(NSString *)languageName { NSDictionary *results = nil; // for now, we store dictionaries in a PLIST with the same name. NSString *dictionaryPlistFile = [languageName stringByAppendingString:GUI_STRING_FILE_POSTFIX]; NSString *plistBundlePath = [Valet getBundlePathForFileName:dictionaryPlistFile]; if ( [[NSFileManager defaultManager] fileExistsAtPath:plistBundlePath] ) { // read it into a dictionary NSDictionary *newDict = [NSDictionary dictionaryWithContentsOfFile:plistBundlePath]; results = [newDict valueForKey:@"languageDictionary"]; }// end if return results; } +(NSString *)stringFor:(NSString *)srcString forDictionary:(NSString *)languageName; { MyLanguage *gsObject = [MyLanguage singleton]; // if default dictionary matches the requested one, use it. if ([gsObject.currentLanguage isEqualToString:languageName]) { // use default return [MyLanguage stringFor:srcString]; }// end if else { // get the desired dictionary NSDictionary *newDict = [MyLanguage getDictionaryNamed:languageName]; // default is not desired! if (ACCESSING_ALTERNATE_DICTIONARY_SETS_DEFAULT) { gsObject.currentDictionary = newDict; gsObject.currentLanguage = languageName; return [MyLanguage stringFor:srcString]; }// end if else { // use current dictionary for translation. NSString *results = [gsObject.currentDictionary valueForKey:srcString]; if (results == nil) { return srcString; }// end if return results; } } } +(void) setLanguage:(NSString *)languageName; { MyLanguage *gsObject = [MyLanguage singleton]; // for now, we store dictionaries in a PLIST with the same name. // get the desired dictionary NSDictionary *newDict = [MyLanguage getDictionaryNamed:languageName]; gsObject.currentDictionary = newDict; gsObject.currentLanguage = languageName; // now set up the bundle for nibs NSString *shortLanguageIdentifier = @"en"; if ([languageName contains:@"spanish"] || [languageName contains:@"espanol"] || [languageName isEqualToString:LANGUAGE_SPANISH_SHORT_ID]) { shortLanguageIdentifier = LANGUAGE_SPANISH_SHORT_ID; }// end if else shortLanguageIdentifier = LANGUAGE_ENGLISH_SHORT_ID; // NSArray *languages = [NSArray arrayWithObject:shortLanguageIdentifier]; // [[NSUserDefaults standardUserDefaults] setObject:languages forKey:@"AppleLanguages"]; // NSString *path= [[NSBundle mainBundle] pathForResource:shortLanguageIdentifier ofType:@"lproj"]; NSBundle *languageBundle = [NSBundle bundleWithPath:path]; gsObject.currentLanguageBundle = languageBundle; [[NSNotificationCenter defaultCenter] postNotificationName:LANGUAGE_CHANGED_NOTIFICATION object:nil]; } +(NSString *)stringFor:(NSString *)srcString; { MyLanguage *gsObject = [MyLanguage singleton]; // default is to do nothing. if (gsObject.currentDictionary == nil || gsObject.currentLanguage == nil || [gsObject.currentLanguage isEqualToString:DEFAULT_DICTIONARY_FOR_STRINGS] ) { return srcString; }// end if // use current dictionary for translation. NSString *results = [gsObject.currentDictionary valueForKey:srcString]; if (results == nil) { return srcString; }// end if return results; } #pragma mark - #pragma mark Singleton methods static MyLanguage *mySharedSingleton = nil; -(void) lateInit; { } // PUT THIS METHOD DECLARATION INTO THE HEADER + (MyLanguage *)singleton; { if (mySharedSingleton == nil) { mySharedSingleton = [[super allocWithZone:NULL] init]; [mySharedSingleton lateInit]; } return mySharedSingleton; } + (id)allocWithZone:(NSZone *)zone { return [[self singleton] retain]; } - (id)copyWithZone:(NSZone *)zone { return self; } - (id)retain { return self; } - (NSUInteger)retainCount //denotes an object that cannot be released { return NSUIntegerMax; } - (oneway void)release //do nothing { } - (id)autorelease { return self; } @end </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload