程序化语言本地化,无需重启

时间:2013-01-13 07:26:53

标签: ios objective-c internationalization

我想用英语和阿拉伯语创建一个iPhone应用程序。我检查了国际化文档的语言切换器,但要实现这一点,我必须手动去改变iPhone设置。我不想那样做。所以我计划在主屏幕上我将有两个按钮作为英语和阿拉伯语。如果用户单击阿拉伯语,我将使用阿拉伯语文本,如果用户选择英语,应用程序将使用英语。

有任何想法/建议如何完成这项工作?

注意:我不想手动去更改语言。


编辑1

根据@Jano,我在下面做了。

创建了新项目。在本地化中添加阿拉伯语。现在我有两个故事板和两个InfoPlist.strings文件。

添加了Localization.h和.m文件,如答案所示。

目录结构为MyProject-ar.lproj& MyProject-en.lproj

Plist的内容为"myButton01" = "Back";& "myButton01" = "ظهر";

First View Controller有两个按钮,分别是英文和阿拉伯文。对这些按钮调用动作。

- (IBAction)pressedEnglish:(id)sender {
    [Localization sharedInstance].fallbackLanguage = @"ar";
    [Localization sharedInstance].preferredLanguage = @"en";
    NSLog(@"pressed english");
}

- (IBAction)pressedArabic:(id)sender {
    [Localization sharedInstance].fallbackLanguage = @"en";
    [Localization sharedInstance].preferredLanguage = @"ar";
    NSLog(@"pressed arabic");
}

在第二个视图控制器中,我添加了一个按钮,名称为myButton。现在在viewDidLoad,我有

[self.myButton setTitle:localize(@"myButton01") forState:UIControlStateNormal];

我希望这应该有效,但是当我运行项目时,我看到按钮为 myButton01

为什么会发生这种情况?


编辑2

我遇到Edit 1问题。我将InfoPlist.strings重命名为Localizable.strings并且有效。但是,但是,无论我按什么按钮,我仍然会收到阿拉伯语文本。

在找到原因时,我发现这是因为我们在Localization.m

中有以下陈述
static Localization *shared = nil;
dispatch_once(&pred, ^{
    shared = [[Localization alloc] init];
    shared.fallbackLanguage = @"en";
    shared.preferredLanguage = @"ar";

问题在于最后两行。由于我们将阿拉伯语设为首选语言,因此我总是看到阿拉伯语文本。

我需要做哪些更改才能按照按下的按钮更改它。

1 个答案:

答案 0 :(得分:4)

您想要从应用UI设置应用的语言,忽略设备上的用户首选项。这很不寻常,但是你走了......

首先在目录结构上写下所有语言字符串,如下所示:

i18n/en.lproj/Localizable.strings
i18n/ar.lproj/Localizable.strings

为支持的每种其他语言创建一个带有相应双字母代码的附加目录。

如果文件被识别为i18n资源,它们将显示如下: enter image description here

文件将具有key =值,格式如下:

"button.back" = "ظهر";

在您的代码中,用密钥替换任何可本地化的字符串。例如:

[self.stateBtn setTitle:localize(@"button.back") forState:UIControlStateNormal];

通常你会使用NSLocalizedString(@"key",@"fallback"),但由于你想忽略iPhone设置,我在上面写了一个localize(@"key")宏,它将具有以下实现:

Localization.h

#ifndef localize
#define localize(key) [[Localization sharedInstance] localizedStringForKey:key]
#endif

@interface Localization : NSObject

@property (nonatomic, retain) NSBundle* fallbackBundle;
@property (nonatomic, retain) NSBundle* preferredBundle;

@property (nonatomic, copy) NSString* fallbackLanguage;
@property (nonatomic, copy) NSString* preferredLanguage;

-(NSString*) localizedStringForKey:(NSString*)key;

-(NSString*) pathForFilename:(NSString*)filename type:(NSString*)type;

+(Localization*)sharedInstance;

@end

Localization.m

#import "Localization.h"

@implementation Localization

+(Localization *)sharedInstance
{
    static dispatch_once_t pred;
    static Localization *shared = nil;
    dispatch_once(&pred, ^{
        shared = [[Localization alloc] init];
        [shared setPreferred:@"en" fallback:@"ar"];
    });
    return shared;
}

-(void) setPreferred:(NSString*)preferred fallback:(NSString*)fallback 
{
    self.fallbackLanguage = fallback;
    self.preferredLanguage = preferred;
    NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"Localizable" ofType:@"strings" inDirectory:nil forLocalization:self.fallbackLanguage];
    self.fallbackBundle = [[NSBundle alloc] initWithPath:[bundlePath stringByDeletingLastPathComponent]];
    bundlePath = [[NSBundle mainBundle] pathForResource:@"Localizable" ofType:@"strings" inDirectory:nil forLocalization:self.preferredLanguage];
    self.preferredBundle = [[NSBundle alloc] initWithPath:[bundlePath stringByDeletingLastPathComponent]];
}

-(NSString*) pathForFilename:(NSString*)filename type:(NSString*)type
{
    NSString *path = [self.preferredBundle pathForResource:filename ofType:type inDirectory:nil forLocalization:self.preferredLanguage];
    if (!path) path = [self.fallbackBundle pathForResource:filename ofType:type inDirectory:nil forLocalization:self.fallbackLanguage];
    if (!path) NSLog(@"Missing file: %@.%@", filename, type);
    return path;
}

-(NSString*) localizedStringForKey:(NSString*)key
{
    NSString* result = nil;
    if (_preferredBundle!=nil) {
        result = [_preferredBundle localizedStringForKey:key value:nil table:nil];
    }
    if (result == nil) {
        result = [_fallbackBundle localizedStringForKey:key value:nil table:nil];
    }
    if (result == nil) {
        result = key;
    }
    return result;
}

@end

这将使用查找阿拉伯语文件中的键字符串,如果键丢失,它将查看阿拉伯语文件。如果您想要另一种方式,请从按钮处理程序执行以下操作:

[[Localization sharedInstance] setPreferred:@"ar" fallback:@"en"];

Sample project at Github

如果本地化不起作用

如果本地化不起作用,请使用plutil命令行工具验证文件的格式。它应输出:Localizable.strings: OK。例如:

$ plutil -lint Localizable.strings
Localizable.strings: OK

此格式在国际化编程主题>中描述。 Localizing String Resources。您可以选择添加// single-line/* multi-line */条评论。对于非拉丁语言,建议使用UTF-16编码Localized.strings。您可以在XCode的检查器窗格中转换编码。

如果仍然无效,请检查您是否正在复制目标的“复制文件”阶段中的Localizable.strings文件。请注意,当你在那里添加Localizable.strings文件时,有时它们会显示为红色,继续执行,直到文件显示为黑色,然后删除红色文件(hacky我知道,责备Xcode)。

copy files