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

时间:2012-08-30 07:43:26

标签: ios objective-c xcode cocoa localization

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

例如,对于我们使用NSLocalizedString,我知道当main.m未初始化时,可以在AppDelegate运行时设置语言,但一旦初始化(特别是您的视图控制器已创建),在下一次重新启动

之前更改它无效
[[NSUserDefaults standardUserDefaults] 
    setObject:[NSMutableArray arrayWithObjects:language, nil] 
    forKey:@"AppleLanguages"];

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

6 个答案:

答案 0 :(得分:5)

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

iOS: How to change app language programmatically WITHOUT restarting the app?

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

让我们从(3)开始。如果您查找定义,您会注意到NSLocalizedString是一个宏。因此,如果您不想过多地更改现有代码,则可以通过创建新的头文件来解决(3)的问题。在该头文件中,#undef然后重新#define NSLocalizedString从适当的位置选择本地化字符串 - 不是iOS默认的那个,而是在某个全局变量中跟踪的那个(例如,在应用程序代表ivar)。如果您不想重新定义NSLocalizedString,但仍然可以自己选择,那么如果您不希望将来的开发人员意外地调用它而不是您替换它的宏,那么您应该仍然#undef NSLocalizedString。不是一个理想的解决方案,但可能是最实用的。

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

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

答案 1 :(得分:2)

我的想法是编写一个像NSLocalizedString这样的新宏,它应该检查是否从另一个特定的包中转换。

this article中的 方法2 解释了如何做到这一点。 在这种特殊情况下,作者不使用新的宏,而是直接[NSBundle mainBundle]设置自定义类

我希望@holex能理解读这个问题。

答案 2 :(得分:1)

我总是以这种方式使用它,它可以很好地工作,它也可以帮到你。


您应该在NSLocalizableString(...) UI的{​​{1}}方法中为当前语言-viewWillAppear:设置UIViewController的所有文字。

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


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

更新日期(2013年10月24日)

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

答案 3 :(得分:1)

我的实现使用类来更改语言并访问当前语言包。这是一个例子,如果您使用的语言不同于我,那么请更改方法以使用您的确切语言代码。

此类将从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

使用上面的类来引用字符串文件/ image / video / etc:

// 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”方法,以获取引用新语言代码的字符串参数。

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

答案 4 :(得分:0)

我遇到了同样的问题,我的要求是“用户可以从下拉菜单中选择语言并且应用程序必须按照选定的语言(英语或阿拉伯语)工作”我做了什么我创建两个XIB并获取XIB和文本根据选定的语言。通过这种方式,用户可以选择语言。我也使用了NSBundle。喜欢

对于XIB

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

For Text

_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;

}

答案 5 :(得分:-1)

你需要加载另一个这样的包(其中@" en"可能是你需要的语言环境):

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

并制作像NSLocalizedString这样的宏/函数,它使用你加载的bundle或直接使用该bundle上的方法

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

[[NSBundle mainBundle] localizations]列出了所有应用本地化版本(包括" Base")。

我也写了helper class这样做(注意它有ReactiveCocoa作为依赖)。它允许在不重新启动应用程序的情况下更改语言,并在每次更改时发送当前区域设置。