iOS:如何以编程方式更改应用程序语言而不重新启动应用程序? [英] iOS: How to change app language programmatically WITHOUT restarting the app?
问题描述
当我在设备语言上单独更改应用程序使用的语言时,只有关闭应用程序并重新启动它才会生效。如何不重新启动应用程序,以便根据所选语言再次加载所有nib文件和.strings文件?
When I change the app used language independently on the device language it doesn't take effect until I close the app and restart it. How to not require app to be restarted for loading all nib files and .strings files again depending on the selected language?
我在运行时使用它来更改语言:
I use this to change language at runtime:
NSArray* languages = [NSArray arrayWithObjects:@"ar", @"en", nil];
[[NSUserDefaults standardUserDefaults] setObject:languages forKey:@"AppleLanguages"];
推荐答案
我对Kiosk模式iPad应用程序有类似的要求使用选项卡式导航。该应用程序不仅需要支持即时语言更改,而且还必须这样做,因为知道大多数选项卡已经从笔尖加载,因为应用程序仅在每周一次重新启动(平均)时大约一次版本已加载。
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.
我尝试了几个建议来利用现有的Apple本地化机制,它们都有严重的缺点,包括在XCode 4.2中对本地化笔尖的支持 - 我的IBoutlet连接变量似乎在IB中正确设置,但在运行时它们通常为空!?
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!?
我最终实现了一个模仿Apple NSLocalizedString类的类,但是可以处理运行时更改,每当用户进行语言更改时,我的类都会发布通知。需要本地化字符串(和图像)更改的屏幕声明了一个handleLocaleChange方法,该方法在viewDidLoad中调用,并且每当发布LocaleChangedNotification时。
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.
我的所有按钮和图形都设计为与语言无关,但标题文本和标签文本通常会根据区域设置更改进行更新。如果我必须更改图像,我可以在每个屏幕的handleLocaleChange方法中完成,我想。
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.
这是代码。它包括对nib / bundle路径的一些支持,我实际上在最终项目中没有使用它。
Here is the code. It includes some support for nib/bundle paths which I actually don't use in the final project.
MyLanguage.h
//
/ / MyLanguage.h
//
//
MyLanguage.h // // MyLanguage.h // //
#import <Foundation/Foundation.h>
#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
MyLanguage.m:
//
// MyLanguage.m
MyLanguage.m: // // MyLanguage.m
#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
这篇关于iOS:如何以编程方式更改应用程序语言而不重新启动应用程序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!