如何强制NSLocalizedString使用特定语言


Answers:


261

NSLocalizedString()(及其变体)访问“ AppleLanguages”键NSUserDefaults来确定首选语言的用户设置。这将返回一系列语言代码,其中第一个是用户为其手机设置的语言代码,如果资源不支持首选语言,则随后的语言代码将用作备用。(在桌面上,用户可以在“系统偏好设置”中以自定义顺序指定多种语言)

如果需要,可以使用setObject:forKey:方法设置自己的语言列表来覆盖自己的应用程序的全局设置。这将优先于全局设置值,并返回给应用程序中执行本地化的任何代码。用于此的代码如下所示:

[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"de", @"en", @"fr", nil] forKey:@"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize]; //to make the change immediate

这将使德语成为您的应用程序的首选语言,并以英语和法语为后备。您可能想在应用程序启动的早期调用此函数。您可以在此处阅读有关语言/语言环境首选项的更多信息:国际化编程主题:获取当前的语言和语言环境


4
这对我不起作用,无论如何,它将使用默认语言。
quano

50
丹尼斯 如果启动应用程序之前设置语言首选项效果会更好。我在调用UIApplicationMain()之前在main()函数中进行此操作。一旦实际运行,它将不会更改使用的语言,而只需设置下一次的首选项即可。
geon 2010年

3
您必须在初始化之前的UIKit设置语言,你必须指定一个完整的语言+区区域-检查了这一点对于一个完整的例子blog.federicomestrone.com/2010/09/15/...
fedmest

18
设置AppleLanguages将在运行时更改语言(如果在main()中完成)-是的!但是...第一次安装该应用程序之后,将在调用UIApplicationMain()之后初始化nsuserdefaults,这将忽略先前设置的AppleLanguages,并且需要强制重启该应用程序才能查看所需的语言。
JohnPayne

3
这不适用于Localizable.stringsdict中定义的多个项目。知道是否有可能的解决方法吗?
Mihai Fratu 2015年

147

最近我遇到了相同的问题,我不想启动并修补整个NSLocalizedString,也不想强制应用程序重新启动以使新语言正常工作。我希望一切都按原样工作。

我的解决方案是动态更改主捆绑包的类并在其中加载适当的捆绑包:

头文件

@interface NSBundle (Language)
+(void)setLanguage:(NSString*)language;
@end

实作

#import <objc/runtime.h>

static const char _bundle=0;

@interface BundleEx : NSBundle
@end

@implementation BundleEx
-(NSString*)localizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName
{
    NSBundle* bundle=objc_getAssociatedObject(self, &_bundle);
    return bundle ? [bundle localizedStringForKey:key value:value table:tableName] : [super localizedStringForKey:key value:value table:tableName];
}
@end

@implementation NSBundle (Language)
+(void)setLanguage:(NSString*)language
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^
    {
        object_setClass([NSBundle mainBundle],[BundleEx class]);
    });
    objc_setAssociatedObject([NSBundle mainBundle], &_bundle, language ? [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:language ofType:@"lproj"]] : nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end

因此,基本上,当您的应用启动时以及在加载第一个控制器之前,只需调用:

[NSBundle setLanguage:@"en"];

当用户在设置屏幕中更改其首选语言时,只需再次调用即可:

[NSBundle setLanguage:@"fr"];

要重置为系统默认值,只需传递nil即可:

[NSBundle setLanguage:nil];

请享用...

对于需要Swift版本的用户:

var bundleKey: UInt8 = 0

class AnyLanguageBundle: Bundle {

    override func localizedString(forKey key: String,
                                  value: String?,
                                  table tableName: String?) -> String {

        guard let path = objc_getAssociatedObject(self, &bundleKey) as? String,
              let bundle = Bundle(path: path) else {

            return super.localizedString(forKey: key, value: value, table: tableName)
            }

        return bundle.localizedString(forKey: key, value: value, table: tableName)
    }
}

extension Bundle {

    class func setLanguage(_ language: String) {

        defer {

            object_setClass(Bundle.main, AnyLanguageBundle.self)
        }

        objc_setAssociatedObject(Bundle.main, &bundleKey,    Bundle.main.path(forResource: language, ofType: "lproj"), .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
}

7
嗨@Wirsing,到目前为止,这对我来说非常有用。我什至已经将一个应用程序上载到了商店,Apple也没有抱怨。
Gilad Novik 2014年

7
这是一个很好的解决方案,我在这里也引用了以下内容:medium.com/ios-apprentice/905e4052b9de
James Tang

1
@JamesTang,您好:感谢您提供参考和您的帖子-我在那里找到了许多有关本地化的有用信息。
吉拉德·诺维克

3
@Gilad您的方法非常适合动态字符串(我在localizable.strings中定义的字符串),但对于情节提要按钮和标签,它仅适用于主要方法。所以您可以扩展您的答案以包括UI控件本地化吗?我的意思是我调用[NSBundle setLanguage:@“ ??”];之后如何刷新(不关闭)故事板?
Jawad Al Shaikh

2
至于XIB /故事板:您需要确保在加载视图之前调用此方法。就实时更新视图而言:就我而言,我只是重新加载了视图控制器(我将其放在导航控制器中,只是更换了控制器。重新加载后-它获得了新的翻译字符串)。我正在为此设计一个cocoapod,我可能还会在其中添加一个示例。敬请
期待

137

我通常以这种方式执行此操作,但是您必须在项目中拥有所有本地化文件。

@implementation Language

static NSBundle *bundle = nil;

+(void)initialize 
{
    NSUserDefaults* defs = [NSUserDefaults standardUserDefaults];
    NSArray* languages = [defs objectForKey:@"AppleLanguages"];
    NSString *current = [[languages objectAtIndex:0] retain];
    [self setLanguage:current];
}

/*
  example calls:
    [Language setLanguage:@"it"];
    [Language setLanguage:@"de"];
*/
+(void)setLanguage:(NSString *)l
{
    NSLog(@"preferredLang: %@", l);
    NSString *path = [[ NSBundle mainBundle ] pathForResource:l ofType:@"lproj" ];
    bundle = [[NSBundle bundleWithPath:path] retain];
}

+(NSString *)get:(NSString *)key alter:(NSString *)alternate 
{
    return [bundle localizedStringForKey:key value:alternate table:nil];
}

@end

1
+1。这是一个非常不错的技巧,我在其他任何地方都没有看到过。通过从一个本地化文件夹中创建一个“子捆绑包”,只要将NSLocalizedString包装在此处绕行的东西,就可以使字符串工作正常。
Ben Zotto

4
优秀的毛罗。我注意到它也可以用于项目外的文件。如果出于某种原因(例如我的情况),您需要从网络下载字符串文件,并将其存储在“文档”目录中(文件夹结构为Documents / en.lproj / Localizable.strings,Documents / fr.lproj / Localizable.strings,...)。您甚至可以制作一个NSBundle。只需对路径使用此代码:NSString * path = [NSHomeDirectory()stringByAppendingPathComponent:[NSString stringWithFormat:@“ / Documents /%@。lproj”,l,nil]];
阿诺德德尔。

1
在我看来,这是最好的方法,下面是亚历山德罗的贡献。它不是那么麻烦,不需要重新启动。
PKCLsoft

1
我究竟做错了什么?我做了一个Language类,继承了NSObject,将其放在实现中,将方法名称放在.h中,然后放入[Language setLanguage:@“ es”]; 在我的“更改语言”按钮中,代码运行(调用了按钮方法,并转到“语言”类),但没有执行任何操作。我也设置了localizable.strings(西班牙语)。但这似乎对许多其他人都起作用。请有人为我哑巴吧。
SirRupertIII

1
@KKendall您这样称呼它:[Language setLanguage:@“ es”]; NSString * stringToUse = [语言获取:@“您的文本” alter:nil];
Mikrasya 2013年

41

不要在iOS 9上使用。这将为通过它的所有字符串返回nil。

我找到了另一个解决方案,可让您更新语言字符串,不重启应用程序并与genstrings兼容:

将此宏放在Prefix.pch中:

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

在任何需要本地化字符串的地方使用:

NSLocalizedStringFromTableInBundle(@"GalleryTitleKey", nil, currentLanguageBundle, @"")

设置语言使用:

[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:@"de"] forKey:@"AppleLanguages"];

即使在连续的语言跳跃中也可以使用,例如:

NSLog(@"test %@", NSLocalizedStringFromTableInBundle(@"NewKey", nil, currentLanguageBundle, @""));
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:@"fr"] forKey:@"AppleLanguages"];
NSLog(@"test %@", NSLocalizedStringFromTableInBundle(@"NewKey", nil, currentLanguageBundle, @""));
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:@"it"] forKey:@"AppleLanguages"];
NSLog(@"test %@", NSLocalizedStringFromTableInBundle(@"NewKey", nil, currentLanguageBundle, @""));
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:@"de"] forKey:@"AppleLanguages"];
NSLog(@"test %@", NSLocalizedStringFromTableInBundle(@"NewKey", nil, currentLanguageBundle, @""));

2
@ powerj1984:不,它将仅更改源文件中的字符串。如果要更改xib语言,则必须从所选语言包中手动重新加载xib。
gklka 2014年

@gklka我已经按照了Tudozier给出的步骤,但是我的XIB并没有改变语言,正如您手动告诉重新加载XIB那样,重新加载XIB实际上意味着什么?
Dk Kumar

@DkKumar:你必须做一些与此类似:stackoverflow.com/questions/21304988/...
gklka

@gklka您的答案似乎正确,我已按照您在答案中所述的相同步骤进行操作,但是问题是如果我们更改包路径,则它将在其中找到所有资源(即XIB中使用的.png文件)。相同的包,因此我们必须在所有包中(例如en.lproj,es.lproj等)过度复制images文件夹,这样会影响IPA大小的增加,那么有什么办法可以解决这个问题?如您在帖子中所说,让我尝试一下,让您更多地感谢您的帮助
Dk Kumar 2014年

1
这在iOS 9中被严重破坏,返回所有字符串的null。
Alex Zavatone 2015年

32

如前所述,只需执行以下操作:

[[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObjects:@"el", nil] forKey:@"AppleLanguages"];

但是为避免必须重新启动应用程序,请将行放在(...)main.m之前的main方法中UIApplicationMain


2
很有帮助的答案!PS对于初学者来说可能听起来很明显,但是您应该在该行之后插入该行,NSAutoreleasePool * pool ..否则一些自动释放的对象将泄漏。
pt2ph8 2011年

1
重要提示:如果您[[NSBundle mainBundle] URLForResource:withExtension:]之前致电,此功能将无效。
Kof

3
如果使用Swift,那么没有main.m怎么办?
turingtest

@turingtested您是否尝试过快速和情节提要,是否可行?
iDevAmit

嗨,如何本地化来自服务器的动态文本,在我的应用程序中,我必须以简体中文显示每个文本,但是如何以英语显示中文文本。帮我。
Mahesh Narla

31

通过从应用程序中选择特定语言的技巧是,NSLocalizedString根据选择的语言来强制使用特定语言包,

这是我为ios应用程序中的这种学习提前本地化而写的帖子

这是ios应用中一个示例应用高级本地化的代码


它也可以在iOS7上运行,我必须从Brian的解决方案切换到该解决方案,因为iOS似乎再次覆盖了language选项,因此我坚持使用语言的首次设置。您的解决方案就像一个魅力!
haxpor

14

您如何看待这个Swift 3解决方案?

extension String {

    func localized(forLanguage language: String = Locale.preferredLanguages.first!.components(separatedBy: "-").first!) -> String {

        guard let path = Bundle.main.path(forResource: language == "en" ? "Base" : language, ofType: "lproj") else {

            let basePath = Bundle.main.path(forResource: "Base", ofType: "lproj")!

            return Bundle(path: basePath)!.localizedString(forKey: self, value: "", table: nil)
        }

        return Bundle(path: path)!.localizedString(forKey: self, value: "", table: nil)
    }
}

简单用法:

"report".localized(forLanguage: "pl") //forced language
"report".localized() //default language selected by user in settings, in case when your app doesnt support selected lanaguage, the default one is selected, here is an english.

嗨,如何本地化来自服务器的动态文本,在我的应用程序中,我必须以简体中文显示每个文本,但是如何以英语显示中文文本。帮我。
Mahesh Narla

这是一个绝妙的答案;)
BartłomiejSemańczyk,19年

很好的答案。对我有帮助
Dilip Tiwari

13

正如Brian Webster所提到的,需要在“应用程序启动初期”设置语言。我想到applicationDidFinishLaunching:AppDelegate应该是一个合适的地方做,因为这就是我做的所有其他初始化。

但是正如William Denniss提到的那样,这似乎只有重新启动应用程序才会生效,这是没有用的。

但是,如果我将代码放入main函数中,似乎可以正常工作:

int main(int argc, char *argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    // Force language to Swedish.
    [[NSUserDefaults standardUserDefaults]
     setObject:[NSArray arrayWithObject:@"sv"]
     forKey:@"AppleLanguages"];

    int retVal = UIApplicationMain(argc, argv, nil, nil);
    [pool release];
    return retVal;
}

我对此表示感谢。


在我的实现中,这是用户可设置的事情–所以我只是弹出一个对话框,告诉他们他们需要重新启动:)
William Denniss

它几乎适用于所有-除了本地化的Default.png图像。
卢卡斯(Lukasz),2010年

2
如果要让用户设置一种语言然后告诉他们重新启动应用程序,请记住,如果他们重新启动的速度过快,则可能不会保存NSUserDefaults。大多数用户的运行速度并不快,但是当您测试应用程序时,您可能会过快并看到不一致的行为。我花了几个小时才意识到为什么我的语言切换有时会起作用而有时却没有起作用!
arlomedia

3
这不是问题,只需[[NSUserDefaults standardUserDefaults] synchronize];在致电后使用setObject:forKey:
Ben Baron

11

我最喜欢Mauro Delrio的方法。我还在Project_Prefix.pch中添加了以下内容

#import "Language.h"    
#define MyLocalizedString(key, alt) [Language get:key alter:alt]

因此,如果您想使用标准方法(使用NSLocalizedString),则可以在所有文件中进行快速的语法替换。


1
我也喜欢他的方法,并添加了一种方法来加载png图像:+(UIImage )imageNamed:(NSString *)imageFileName {NSString fullPath = [bundle pathForResource:imageFileName ofType:@“ png”]; UIImage * imageObj = [[UIImage alloc] initWithContentsOfFile:fullPath]; 返回[imageObj自动发布];}
Jagie 2011年

11

NSLocalizedString()AppleLanguages从标准用户默认值([NSUserDefaults standardUserDefaults])中读取密钥的值。它使用该值在运行时在所有现有本地化中选择合适的本地化。当Apple在应用启动时构建用户默认词典时,他们会在系统偏好设置中查找首选语言键,然后从中复制值。例如,这也解释了为什么在OS X中更改语言设置对运行的应用程序无效,而仅对之后启动的应用程序无效。一旦复制,就不会仅因为设置更改而更新值。因此,如果更改语言,iOS会重新启动所有应用程序。

但是,用户默认字典的所有值都可以由命令行参数覆盖。请参阅NSUserDefaults上的文档NSArgumentDomain。这甚至包括从应用程序首选项(.plist)文件中加载的那些值。如果您只想一次更改一个值以进行测试,这真是一件好事。

因此,如果您只想更改语言以进行测试,则可能不想更改代码(如果以后忘记删除此代码...),而是告诉Xcode使用命令行参数启动应用程序(例如,使用西班牙语本地化):

在此处输入图片说明

完全不需要触摸您的代码。只需为不同的语言创建不同的方案,就可以通过切换方案快速以一种语言启动应用程序,然后以另一种语言快速启动应用程序。


此功能仅在第一次后才能再次加载到设备偏好设置中。语言..
Aks

@Aks每次都为我工作。确保您启动了正确的方案,确保您从Xcode内部开始(重新启动,派生等),并且确保您不会Options像Apple提供的较新Xcode版本那样覆盖该语言。也一样
Mecki '17

感谢您的回复@Mecki ..对我来说,它不能在xcode中工作,但是当我在代码中提及时,它可以工作。我在争论中传递的语言
。...– Aks

@Aks在设备上使用时,它仅在直接从Xcode启动时才起作用,当您通过在某些设备上点击其图标再次启动应用程序时,它将不起作用,并且在应用程序被终止时也将不起作用(例如, (因为它进入后台)并由系统重新启动(因为此重新启动不是Xcode进行的重新启动)-因此,如果iOS必须在两者之间杀死您的应用程序,则切换到其他应用程序并返回可能不起作用需要内存)。
梅基'17

10

我想出了一个可以让您使用的解决方案NSLocalizedString。我创建了NSBundlecall 的类别NSBundle+RunTimeLanguage。界面是这样的。

// 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

比只是将import添加NSBundle+RunTimeLanguage.h到使用的文件中NSLocalizedString

如您所见,我将languageCode存储在的属性中AppDelegate。它可以存储在您想要的任何位置。

我唯一不喜欢的是NSLocalizedStringmarco重新定义的警告。也许有人可以帮助我修复此部分。


1
#undef NSLocalizedString在此之前添加#define以禁用该警告

这对xib文件的本地化有效吗?我有.xib文件和.strings以特定语言翻译UI名称。我尝试过,但它不能与XIB一起使用,但是我不确定自己做的是否正确
Kong Hantrakool 2015年

孔先生对您的回复延迟表示抱歉。在您使用NSLocalizedString的任何地方都可以使用。因此它不能直接在XIB中工作。您将需要IBOutlets到XIB中的字符串,然后必须以编程方式在代码中设置字符串值。
qman64

这种方法对我有用,并且我能够即时更改语言。请注意,诸如“ es”,“ fr”和“ en”之类的语言代码可以正常工作,但“ zh”(简体中文)失败并给了我空字符串。我在系统上全局搜索了“ es.lproj”看到我正在访问的文件在哪里,我发现“ zh.lproj”实际上是“ zh-Hans.lproj”
Gallymon '18

9

迅捷版:

NSUserDefaults.standardUserDefaults().setObject(["fr"], forKey: "AppleLanguages")
NSUserDefaults.standardUserDefaults().synchronize()

8

简而言之 :

本地化您的应用程序

您要做的第一件事是使用至少两种语言(在此示例中为英语和法语)对应用程序进行本地化。

覆盖NSLocalizedString

在您的代码中,不要使用,而是使用如下定义NSLocalizedString(key, comment)的宏MYLocalizedString(key, comment)#define MYLocalizedString(key, comment) [[MYLocalizationSystem sharedInstance] localizedStringForKey:(key) value:(comment)];

这个MYLocalizationSystem单身人士将:

  • 通过设置正确的本地化NSBundle用户要求来设置语言
  • 根据此先前设置的语言返回本地化的NSString

设定使用者语言

当用户以法语更改应用程序语言时,请致电 [[MYLocalizationSystem sharedInstance] setLanguage:@"fr"];

- (void)setLanguage:(NSString *)lang
{
    NSString *path = [[NSBundle mainBundle] pathForResource:lang ofType:@"lproj"];
    if (!path)
    {
        _bundle = [NSBundle mainBundle];
        NSLog(@"Warning: No lproj for %@, system default set instead !", lang);
        return;
    }

    _bundle = [NSBundle bundleWithPath:path];
}

在此示例中,此方法将本地化包设置为fr.lproj

返回本地化的字符串

设置了本地化的包之后,您可以使用以下方法从他那里获取正确的本地化字符串:

- (NSString *)localizedStringForKey:(NSString *)key value:(NSString *)value
{
    // bundle was initialized with [NSBundle mainBundle] as default and modified in setLanguage method
    return [self.bundle localizedStringForKey:key value:value table:nil];
}

希望这会帮助你。

您可以从NSWinery.io的这篇文章中找到更多详细信息。


我们要求您不仅在答案中链接到解决方案;该链接可能有一天会停止工作。虽然您不必从答案中删除链接,但我们确实要求您编辑答案以包括链接文章相关部分的摘要。
遗忘的贤者

7

Swift 3扩展:

extension Locale {
    static var preferredLanguage: String {
        get {
            return self.preferredLanguages.first ?? "en"
        }
        set {
            UserDefaults.standard.set([newValue], forKey: "AppleLanguages")
            UserDefaults.standard.synchronize()
        }
    }
}

extension String {
    var localized: String {

    var result: String

    let languageCode = Locale.preferredLanguage //en-US

    var path = Bundle.main.path(forResource: languageCode, ofType: "lproj")

    if path == nil, let hyphenRange = languageCode.range(of: "-") {
        let languageCodeShort = languageCode.substring(to: hyphenRange.lowerBound) // en
        path = Bundle.main.path(forResource: languageCodeShort, ofType: "lproj")
    }

    if let path = path, let locBundle = Bundle(path: path) {
        result = locBundle.localizedString(forKey: self, value: nil, table: nil)
    } else {
        result = NSLocalizedString(self, comment: "")
    }
        return result
    }
}

用法:

Locale.preferredLanguage = "uk"

label.text = "localizedKey".localized

谢谢。工作正常。
克鲁纳尔·纳格瓦迪亚

5

在文件.pch中定义:

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


#define NSLocalizedString(str,nil) NSLocalizedStringFromTableInBundle(str, nil, currentLanguageBundle, @"")

如何摆脱警告“ ovverride ...”?
Idan Moshe 2014年

1
简单的解决方案可以满足我的所有需求。能够以此为指导来解决我的问题。如果pathForResource因为没有本地化文件而返回nil,则我使用pathForResource:@“ Base”,因为我尝试过的其他操作都没有从基本本地化中提取字符串。谢谢。
GRW 2014年

这很hacky(其他所有答案也是如此),并且在我正在编写的单元测试中最容易实现。
最多

4

也许您应该对此进行补充(在#import之后的.pch文件上):

extern NSBundle* bundle; // Declared on Language.m

#ifdef NSLocalizedString
    #undef NSLocalizedString
    // Delete this line to avoid warning
    #warning "Undefining NSLocalizedString"
#endif

#define NSLocalizedString(key, comment) \
    [bundle localizedStringForKey:(key) value:@"" table:nil]

/Users/pwang/Desktop/Myshinesvn/Myshine/viewController/OrientationReadyPagesView.m:193:31:使用未声明的标识符“ bundle”
pengwang 2013年

4

Swift 3解决方案:

let languages = ["bs", "zh-Hant", "en", "fi", "ko", "lv", "ms", "pl", "pt-BR", "ru", "sr-Latn", "sk", "es", "tr"]
UserDefaults.standard.set([languages[0]], forKey: "AppleLanguages")

提供了一些可以使用的语言代码示例。希望这可以帮助



3

就我而言,我有两个本地化文件ja和en

如果系统中的首选语言既不是en也不是ja,我想将其强制为en

我将编辑main.m文件

我将检查第一个首选语言是en还是ja,否则,我将第二个首选语言更改为en。

int main(int argc, char *argv[])
{

    [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"AppleLanguages"];
    [[NSUserDefaults standardUserDefaults] synchronize];

    NSString *lang = [[NSLocale preferredLanguages] objectAtIndex:0];

    if (![lang isEqualToString:@"en"]  &&  ![lang isEqualToString:@"ja"]){

        NSMutableArray *array = [[NSMutableArray alloc] initWithArray:[NSLocale preferredLanguages]];
        [array replaceObjectAtIndex:1 withObject:@"en"];

        [[NSUserDefaults standardUserDefaults] setObject:array forKey:@"AppleLanguages"];
        [[NSUserDefaults standardUserDefaults] synchronize];


    }

    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));


    }


}

感谢@ chings228这对我来说很有用,但这不会更改我对每种语言都有不同启动符的应用程序的默认启动图像(启动符)。你知道如何申请吗?
JERC

我认为启动程序会在主程序开始运行之前运行,所以我不知道如何重写它,也许plist可以提供帮助,但它可能在下次打开应用程序时
起作用

2

您可以执行以下操作:

NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"Localizable" ofType:@"strings" inDirectory:nil forLocalization:@"es"];


NSBundle *spanishBundle = [[NSBundle alloc] initWithPath:[bundlePath stringByDeletingLastPathComponent]];

NSLocalizedStringFromTableInBundle(@"House", nil, spanishBundle, nil):

2

基于Tudorizer的回答,无需离开或重新启动应用程序即可更改语言。

代替宏,使用类来访问首选语言,以便检查是否存在特定的语言代码。

以下是用于获取适用于iOS 9的当前语言包的类:

@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”方法以采用引用新语言的字符串参数。

[[NSUserDefaults standardUserDefaults] setObject:@[@"es"] forKey:@"AppleLanguages"];

2

在Swift 4中,我无需重新启动或使用库即可解决该问题。

在尝试了许多选项之后,我发现了该函数,在此传递您要翻译的stringToLocalize(属于Localizable.String,字符串文件),要翻译的语言以及返回的值是您在Strings文件中拥有的String:

    func localizeString (stringToLocalize: String, language: String) -> String
    {
        let path = Bundle.main.path (forResource: language, ofType: "lproj")
        let languageBundle = Bundle (path: path!)
        return languageBundle! .localizedString (forKey: stringToLocalize, value: "", table: nil)
    }

考虑到此功能,我在Swift文件中创建了此功能:

struct CustomLanguage {

    func createBundlePath () -> Bundle {
        let selectedLanguage = //recover the language chosen by the user (in my case, from UserDefaults)
        let path = Bundle.main.path(forResource: selectedLanguage, ofType: "lproj")
        return Bundle(path: path!)!
    }
}

要从整个应用程序以及其余ViewControllers的每个字符串中进行访问,而不是放置:

NSLocalizedString ("StringToLocalize", comment: ")

我已将其替换为

let customLang = CustomLanguage() //declare at top
let bundleLanguage = customLang.createBundle()

NSLocalizedString("StringToLocalize", tableName: nil, bundle: bundleLanguage, value: "", comment: “”) //use in each String

我不知道这是否是最好的方法,但是我发现它非常简单,并且对我有用,希望对您有所帮助!


1

此函数将尝试获取当前语言的本地化字符串,如果找不到,则将使用英语获取它。

- (NSString*)L:(NSString*)key
{
    static NSString* valueNotFound = @"VALUE_NOT_FOUND";
    static NSBundle* enBundle = nil;

    NSString* pl = [NSLocale preferredLanguages][0];
    NSString* bp = [[NSBundle mainBundle] pathForResource:pl ofType:@"lproj"];
    NSBundle* b = [NSBundle bundleWithPath:bp];

    NSString* s = [b localizedStringForKey:key value:valueNotFound table:nil];
    if ( [s isEqualToString:valueNotFound] ) {
        if ( !enBundle ) {
            bp = [[NSBundle mainBundle] pathForResource:@"en" ofType:@"lproj"];
            enBundle = [NSBundle bundleWithPath:bp];
        }
        s = [enBundle localizedStringForKey:key value:key table:nil];
    }

    return s;
}

1

我想添加对iOS官方不支持的语言(系统设置下“语言”部分未列出)的支持。通过遵循苹果的国际化教程以及Brian Webster和geon的一些提示,我想到了这段代码(将其放在main.m中):

int main(int argc, char * argv[]) {
    @autoreleasepool {
        // Grab regional settings locale, for Slovenian this is either sl_SI or en_SI
        NSLocale *locale = [NSLocale currentLocale];
        NSString *ll = [locale localeIdentifier]; // sl_SI

        // Grab the first part of language identifier
        NSArray *comp = [ll componentsSeparatedByString:@"_"];
        NSString *ll1 = @"en";
        if (comp.count > 0) {
            ll1 = comp[0]; // sl, en, ...
        }
        // Check if we already saved language (user can manually change it inside app for example)
        if (![[NSUserDefaults standardUserDefaults] objectForKey:@"SelectedLanguage"]) {
            //   Slovenian (Slovenia),            Slovenia
            if ([ll isEqualToString:@"sl_SI"] || [ll isEqualToString:@"en_SI"]) {
                ll1 = @"sl-SI"; // This is the part of localized path for Slovenian language that Xcode generates
            }
            // Add more unsupported languages here...

            [[NSUserDefaults standardUserDefaults] setObject:ll1 forKey:@"SelectedLanguage"]; // Save language
        }
        else {
            // Restore language as we have previously saved it
            ll1 = [[NSUserDefaults standardUserDefaults] objectForKey:@"SelectedLanguage"];
        }
        // Overwrite NSLocalizedString and StoryBoard language preference
        [[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:ll1, @"en", @"fr", nil] forKey:@"AppleLanguages"];
        // Make sure settings are stored to disk
        [[NSUserDefaults standardUserDefaults] synchronize];

        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

这对于Storyboard和NSLocalizedString代码均适用。该代码假定用户以后可以选择在应用内手动更改语言。

当然,不要忘了添加正确的Storyboard翻译和Localizable.strings翻译(有关操作方法,请参见上面的Apple页面链接)。


我看到您也遇到了斯洛文尼亚语的问题:)为了改善iOS不支持的语言的答案,您是否想知道我们是否可以设置自定义可本地化的字符串,这些字符串将用于应用程序中的系统控件(编辑,完成,更多, ...)?
miham

1

这是解决此问题的一种不错的方法,它不需要重新启动应用程序。

https://github.com/cmaftuleac/BundleLocalization

此实现通过在NSBundle内部进行调整来起作用。这个想法是,您要覆盖NSBundle对象实例上的localizedStringForKey方法,然后在使用不同语言的另一个包中调用此方法。简单优雅完全与所有类型的资源兼容。


该项目中的这段代码对我帮助很大。如何查找特定语言代码的捆绑软件---NSString *path = [[NSBundle mainBundle] pathForResource:lang ofType:@"lproj" ];
Eonil '16

此类运行良好,但是将语言更改为另一种语言后,它没有效果。
Anilkumar iOS ReactNative

0

无论您做什么,最好的方法是采用指定语言的short_name,即:fr,en,nl,de,it等,然后将其分配给全局值。

使选择器视图像下拉菜单一样弹出(单击时会从下面显示选择器视图的按钮与语言列表结合在一起),然后选择所需的语言。让短名称在内部存储。制作一个名为LocalisedString的.h + .m文件。

将short_name的全局值设置为等于LocalisedString.m中获得的值。选择所需的语言后,分配NSBundlePath来为所需的语言创建项目子目录。例如,nl.proj,en.proj。

选择特定的proj文件夹后,调用相应语言的本地化字符串并动态更改语言。

没有违反规则。


0

对于Swift,您可以覆盖main.swift文件并在应用运行之前在其中设置UserDefaults字符串。这样,您无需重新启动应用程序即可看到所需的效果。

import Foundation
import UIKit

// Your initialisation code here
let langCultureCode: String = "LANGUAGE_CODE"

UserDefaults.standard.set([langCultureCode], forKey: "AppleLanguages")
UserDefaults.standard.synchronize()

UIApplicationMain(CommandLine.argc, CommandLine.unsafeArgv, nil, NSStringFromClass(AppDelegate.self))

与取消的配对一起@UIApplicationMain在你的AppDelegate.swift文件中。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.