30

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

例如,对于我们使用NSLocalizedString,我知道可以在未初始化时在运行时设置语言main.mAppDelegate但是一旦初始化(特别是创建视图控制器),更改它直到下次重新启动才生效

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

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

4

6 回答 6

6

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

iOS:如何在不重新启动应用程序的情况下以编程方式更改应用程序语言?

在我看来,这里实际上有三个任务:(1)重新本地化从 nib 自动加载的资源。(例如,如果您从 nib 动态实例化另一个自定义 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:并换出加载旧语言资源的对象,其中一个加载了新的语言资源。这是 Mohamed 在本次讨论的最底部提到的一种方法:http: //learning-ios.blogspot.ca/2011/04/advance-localization-in-ios-apps.html. 他声称这会导致问题(未调用 viewDidLoad)。即使它不起作用,尝试一下也可能会为您指明可行的方法。

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

于 2012-09-05T04:59:43.980 回答
2

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

本文中的方法 2准确地解释了如何做到这一点。在这种特殊情况下,作者没有使用新的宏,而是直接.[NSBundle mainBundle]

我希望@holex 能理解阅读本文的问题。

于 2015-02-09T00:05:09.977 回答
1

我一直在使用这种方式,它工作得很好,它也可能对你有帮助。


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

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


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

更新(2013 年 10 月 24 日)

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

于 2012-08-30T09:09:54.573 回答
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

使用上面的类来引用一个字符串文件/图像/视频/等:

// 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"];
于 2015-10-29T17:30:47.573 回答
0

我陷入了同样的问题,我的要求是“用户可以从下拉列表中选择语言,并且应用程序必须根据所选语言(英语或阿拉伯语)工作”我所做的我创建了两个 XIB 并根据所选语言获取 XIB 和文本。这样用户可以选择语言。我也使用了 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;

}
于 2012-09-08T10:44:50.767 回答
-1

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

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

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

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

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

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

于 2015-03-02T15:50:14.100 回答