在iOS中更改应用程序语言,无需重新启动应用程序

我似乎有些应用程序可以在应用程序内部更改语言,而无需重新启动应用程序,我想知道它们是如何实现的。

例如,对于我们使用NSLocalizedString ,我知道可以在运行时在main.m设置语言,当你的AppDelegate没有初始化,但是一旦它被初始化(特别是你的视图控制器被创build),改变它不会下次重启

 [[NSUserDefaults standardUserDefaults] setObject:[NSMutableArray arrayWithObjects:language, nil] forKey:@"AppleLanguages"]; 

任何人都知道如何在不重新启动应用程序的情况下完成这些dynamic语言更改?

这里有一些关于其他方法的讨论,特别是基于通知的方法:

iOS:如何以编程方式更改应用程序语言无需重新启动应用程序?

在我看来,这里真的有三个任务:(1)从nibs自动加载资源的重新定位。 (例如,如果您从一个笔尖dynamic实例化另一个自定义的UIView,那么“旧”的语言string和设置(图像,文本方向)仍将被加载)(2)重新定位当前显示在屏幕上的string。 (3)开发者(你)插入的string在程序代码中的重新定位。

我们从(3)开始。 如果你看这个定义,你会注意到NSLocalizedString是一个macros。 所以,如果你不想改变现有的代码太多,你可以通过创build一个新的头文件来解决(3)的问题。 在这个头文件中,# #undef ,然后重新#define NSLocalizedString从适当的地方select本地化的string – 不是iOS默认的那个,而是一个你在一些全局variables(例如,在一个应用程序代表伊娃)。 如果你不想重新定义NSLocalizedString,但是你仍然可以自己select,如果你不想让未来的开发者不小心调用它,而不是你用它来代替macros,你应该仍然可以#undef NSLocalizedString 。 不是一个理想的解决scheme,但也许是最实用的。

至于(1),如果你还没有在界面生成器中完成你的本地化,而是你在viewDidLoad中dynamic地执行它,那么没问题。 你可以使用刚刚讨论过的相同的行为(即修改后的NSLocalizedString等)。 否则,您可以(a)实现上述链接中描述的通知系统(复杂),或者(b)考虑将本地化从IB移动到viewDidLoad,或者(c)尝试覆盖initWithNibName:并将旧对象语言资源,一个载入新的语言资源。 穆罕默德在这个讨论的最底层提到了这个方法: http : //learning-ios.blogspot.ca/2011/04/advance-localization-in-ios-apps.html 。 他声称这会导致问题(viewDidLoad不会被调用)。 即使不起作用,尝试一下也可能会使你指向某些事情。

最后,(2)大概是最简单的任务:删除并重新添加当前视图(或者在某些情况下,重新绘制它)。

这个想法是写一个像NSLocalizedString这样的新macros,它应该检查是否从另一个特定的包中获取翻译。

本文中的方法2正确地解释了如何做到这一点。 在这种情况下,作者不使用新的macros,而是直接为[NSBundle mainBundle] 设置一个自定义类

我希望@ Holex能够理解这个问题。

我总是使用这种方式,它完美的作品,它也可以帮助你。


您应该在每个UIViewController-viewWillAppear:方法中为当前语言的UI设置NSLocalizableString(...)所有文本。

使用这种方式,您(我的意思是用户) 不需要设置中更改iOS的语言后重新启动应用程序。


当然,我正在使用苹果的标准本地化架构。

更新date(2013年10月24日)

我已经经历了–viewWillAppear:当应用程序进入前台时,不会为实际视图执行方法; 为了解决这个问题,我也提交过程(见上文),当我在视图中收到UIApplicationWillEnterForegroundNotification通知。

我被困在同样的问题,我的要求是“用户可以从下拉select语言和应用程序必须根据选定的语言(英语或阿拉伯语)工作”我做了什么,我创build两个XIB,并根据选定的语言获取XIB和文本。 这样用户可以select语言。 我用同样的NSBundle。 喜欢

对于XIB

 self.homeScreen = [[HomeScreen alloc] initWithNibName:@"HomeScreen" bundle:[CommonData sharedCommonData].languageBundle]; 

对于文本

 _lblHeading.text = [self languageSelectedStringForKey:@"ViewHeadingInfo"]; /** This method is responsible for selecting language bundle according to user's selection. @param: the string which is to be converted in selected language. @return: the converted string. @throws: */ -(NSString*) languageSelectedStringForKey:(NSString*) key { NSString* str=[[CommonData sharedCommonData].languageBundle localizedStringForKey:key value:@"" table:nil]; return str; } 

我的实现使用一个类来改变语言,并访问当前的语言包。 这是一个例子,如果你要使用不同的语言比我更改然后更改方法使用您的确切的语言代码。

该类将从NSLocale中访问首选语言,并获取所使用语言的第一个对象。

 @implementation OSLocalization + (NSBundle *)currentLanguageBundle { // Default language incase an unsupported language is found NSString *language = @"en"; if ([NSLocale preferredLanguages].count) { // Check first object to be of type "en","es" etc // Codes seen by my eyes: "en-US","en","es-US","es" etc NSString *letterCode = [[NSLocale preferredLanguages] objectAtIndex:0]; if ([letterCode rangeOfString:@"en"].location != NSNotFound) { // English language = @"en"; } else if ([letterCode rangeOfString:@"es"].location != NSNotFound) { // Spanish language = @"es"; } else if ([letterCode rangeOfString:@"fr"].location != NSNotFound) { // French language = @"fr"; } // Add more if needed } return [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:language ofType:@"lproj"]]; } /// Check if preferred language is English + (BOOL)isCurrentLanguageEnglish { if (![NSLocale preferredLanguages].count) { // Just incase check for no items in array return YES; } if ([[[NSLocale preferredLanguages] objectAtIndex:0] rangeOfString:@"en"].location == NSNotFound) { // No letter code for english found return NO; } else { // Tis English return YES; } } /* Swap language between English & Spanish * Could send a string argument to directly pass the new language */ + (void)changeCurrentLanguage { if ([self isCurrentLanguageEnglish]) { [[NSUserDefaults standardUserDefaults] setObject:@[@"es"] forKey:@"AppleLanguages"]; } else { [[NSUserDefaults standardUserDefaults] setObject:@[@"en"] forKey:@"AppleLanguages"]; } } @end 

使用上面的类来引用一个string文件/图像/video/等:

 // Access a localized image [[OSLocalization currentLanguageBundle] pathForResource:@"my_image_name.png" ofType:nil] // Access a localized string from Localizable.strings file NSLocalizedStringFromTableInBundle(@"StringKey", nil, [OSLocalization currentLanguageBundle], @"comment") 

像下面这样在线更改语言,或更新上面的类中的“changeCurrentLanguage”方法,以获取引用新语言代码的string参数。

 // Change the preferred language to Spanish [[NSUserDefaults standardUserDefaults] setObject:@[@"es"] forKey:@"AppleLanguages"]; 

您需要像这样加载另一个包(其中@“en”可以是您需要的语言环境):

 NSString *path = [[NSBundle mainBundle] pathForResource:@"en" ofType:@"lproj"]; NSBundle *languageBundle = [NSBundle bundleWithPath:path]; 

并像这样使用你的加载的bundle或使用这个bundle上的方法来制作像NSLocalizedString这样的macros/函数

 [languageBundle localizedStringForKey:key value:value table:tableName]; 

[[NSBundle mainBundle] localizations]列出所有的应用程序本地化(包括“基地”)。

此外,我写了这样做的助手类 (请注意,它具有ReactiveCocoa作为依赖)。 它允许在不重新启动应用程序的情况下更改语言,并在每次更改时发送当前语言环境