如何在运行时更改iPhone应用程序语言?

14

有没有办法在运行时更改应用程序语言?

因此,在更改后,NSLocalizedString立即返回新语言的字符串。

我现在正在使用以下代码更改语言:

- (void)onChangeLanguage: (id)sender 
{
    NSArray *lang = [NSArray arrayWithObjects:((InfoWhatever *)sender).language, nil];
    [[NSUserDefaults standardUserDefaults] setObject:lang forKey:@"AppleLanguages"];
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSArray *languages = [defaults objectForKey:@"AppleLanguages"];
    NSString *currentLanguage = [languages objectAtIndex:0];

    NSLog(@"Current language: %@", currentLanguage);
}

应用程序将在重新启动之后更改语言,而非实时更改


顺便说一句,这也适用于桌面版(Mac)。运行的应用程序不会受语言更改的影响。 - Wevah
我刚回答了一个类似的问题,并在这里发布了一些代码链接 - software evolved
我的应用程序有一个带有阿拉伯语和英语的设置页面。一旦我更改了语言,它应该翻转视图控制器和NSLocalizedString。它只有在我重新启动应用程序后才能正常工作。但是,它应该在不关闭应用程序的情况下进行更改,这可能吗? - Arun Kumar P
7个回答

11
NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
NSMutableArray* languages = [userDefaults objectForKey:@"AppleLanguages"];
[languages insertObject:@"de" atIndex:0]; // ISO639-1
[[NSUserDefaults standardUserDefaults] synchronize];

这是正确的做法,但这里有一个更简单的实现:https://dev59.com/X2025IYBdhLWcg3wNTAV - ThomasW
这个实现更好。ThomasW正在替换数组的原始内容。此方法是在已有内容上方插入语言。 - Just a coder
这是如何实现的?至少对于iOS 8.2,"[userDefaults objectForKey:@"AppleLanguages"];"返回不可变数组。 - Fawkes
这会导致崩溃:[__NSArrayI insertObject:atIndex:]:向实例0x60800003c580发送未识别的选择器。 - David Karlsson

7
你可以做到。以下是方法: http://aggressive-mediocrity.blogspot.com/2010/03/custom-localization-system-for-your.html 1.简要下载并将2个文件添加到项目中: http://dl.dropbox.com/u/2917666/LocalizationSystem/LocalizationSystem.h http://dl.dropbox.com/u/2917666/LocalizationSystem/LocalizationSystem.m 2.导入“LocalizationSystem.h”文件。
3.
- (IBAction)btnEnglishClicked:(id)sender {
     LocalizationSetLanguage(@"en");
}

4 在你按照上述设置语言后

AMLocalizedString(@"Key", nil)

就是这样。


1
这听起来像是解决问题的正确方法,但由于您没有直接使用NSLocalizedString(或其变体),因此失去了使用genstrings生成字符串表的能力。不过,您可以使用这个开源的genstrings实现来检测您的函数:https://github.com/Cocoanetics/DTLocalizableStringScanner - Sebastien Martin
但是,图片资源怎么办呢?如果屏幕上有很多图片,我们就必须明确地设置它们。有没有更好的处理图片的方法? - NNikN

7

5
我怀疑你无法做到这一点,即使设置应用程序也无法做到。
(当您在设置应用程序中更改语言时,屏幕会变黑,并显示“设置语言...”和进度轮。经过长时间等待,您回到Springboard。它几乎看起来像手机重新启动了。)

1
我同意你的假设 - 但这不是一个答案。你有关于执行运行时语言更改的任何信息吗? - Brandon
1
@Brandon:那是对不同问题的回答。我的回答措辞明显表明它基于假设和观察,而不是一些第一手信息(如果我有的话,我会引用它)。没有人提供不同(更好)的答案,所以我仍然认为这是正确的答案。 - oefe
1
是的,那是一个不同的问题。看看答案,回答者显然对主题有一些第一手的知识 - 即使问题没有完全解决。你的答案根本没有提供任何有用的信息。除了简单地错误之外,“设置应用程序无法做到这一点”的断言是误导性的。为什么重要的是设置应用程序不能在运行时更改演示语言(而不是不能)?提问者正在追求的用例不需要重新显示本地化图标,甚至不涉及其他应用程序。答案是愚蠢的。 - Brandon
1
@Brandon:为什么不与我们分享你的答案? - oefe
2
我花了很长时间才想出一个解决方案。最终我使用了 'NSLocalizedStringFromTable' 宏和 'AppleLanguages' 设置来设置和检查语言设置。如果有机会的话,我会写一篇实际的答案。或许你应该删除这个答案?看到一个愚蠢但被接受的答案并不能激励任何人去付出更多的努力。 - Brandon
显示剩余4条评论

3

我提出了一种解决方案,允许您使用NSLocalizedString。 我创建了一个名为NSBundle+RunTimeLanguageNSBundle类别。接口如下。

// NSBundle+RunTimeLanguage.h
#import <Foundation/Foundation.h>
@interface NSBundle (RunTimeLanguage)
#define NSLocalizedString(key, comment) [[NSBundle mainBundle] runTimeLocalizedStringForKey:(key) value:@"" table:nil]
- (NSString *)runTimeLocalizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName;
@end

实现方式如下。
// NSBundle+RunTimeLanguage.m
#import "NSBundle+RunTimeLanguage.h"
#import "AppDelegate.h"

@implementation NSBundle (RunTimeLanguage)

- (NSString *)runTimeLocalizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName
{
    AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
    NSString *path= [[NSBundle mainBundle] pathForResource:[appDelegate languageCode] ofType:@"lproj"];
    NSBundle *languageBundle = [NSBundle bundleWithPath:path];
    NSString *localizedString=[languageBundle localizedStringForKey:key value:key table:nil];
    return localizedString;
}
@end

只需将 NSBundle+RunTimeLanguage.h 导入到使用 NSLocalizedString 的文件中即可。

如您所见,我将 languageCode 存储在 AppDelegate 的属性中。这可以存储在任何您想要的地方。

唯一不喜欢的是 Warning 中提到了 NSLocalizedString 宏被重新定义了。或许有人能帮我解决这个问题。


1
你可以在 #define 之前使用 '#undef NSLocalizedString'。这样应该就能消除警告了。 - Jeremy Wiebe
这种方法能否用于本地化Storyboard呢? - Minas

1

只需添加以下几行代码:

 #define currentLanguageBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[[NSLocale preferredLanguages] objectAtIndex:0] ofType:@"lproj"]]   


 1. NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults]; 
            [defaults setObject:@[@"en"] forKey:@"AppleLanguages"];  [defaults
            synchronize];

 2. _label.text = NSLocalizedStringFromTableInBundle(@"Key", nil, currentLanguageBundle, @"");

-1

我在我的项目中尝试了你的解决方案,但是出现了异常:“路径<localisation.lproj路径>中似乎没有有效的编译故事板”。然后我注意到原因是我在故事板中启用了大小类。如果你为你的故事板启用大小类,那么你的项目也会出现同样的问题。有什么想法可以解决这个问题吗? - Kremk
问题是关于“运行时切换”的。您建议重新构建。 - Alexander Volkov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接