Cod*_*kes 261 localization objective-c internationalization nslocalizedstring ios
在iPhone上NSLocalizedString返回iPhone 语言的字符串.是否可以强制NSLocalizedString使用特定语言使应用程序使用与设备不同的语言?
Bri*_*ter 259
NSLocalizedString()(及其变体)访问"AppleLanguages"键NSUserDefaults以确定用户对首选语言的设置.这将返回一组语言代码,第一个是用户为其手机设置的语言代码,如果资源不是首选语言,则后续用作后备.(在桌面上,用户可以在"系统偏好设置"中使用自定义排序指定多种语言)
如果您希望使用setObject:forKey:方法设置自己的语言列表,则可以覆盖自己应用程序的全局设置.这将优先于全局设置值,并返回到应用程序中执行本地化的任何代码.这个代码看起来像这样:
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"de", @"en", @"fr", nil] forKey:@"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize]; //to make the change immediate
这将使德语成为您的应用程序的首选语言,英语和法语作为后备.您可能希望在应用程序启动时的某个时间调用它.您可以在此处阅读有关语言/区域设置首选项的更多信息:国际化编程主题:获取当前语言和区域设置
Gil*_*vik 146
我最近遇到了同样的问题,我不想启动并修补我的整个NSLocalizedString,也不强迫应用程序重启以使新语言工作.我希望一切都按原样运作.
我的解决方案是动态更改主bundle的类并在那里加载适当的bundle:
头文件
@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)
    }
}
Mau*_*rio 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
Tud*_*dor 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, @""));
小智 32
如前所述,只需:
[[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObjects:@"el", nil] forKey:@"AppleLanguages"];
但是为了避免重新启动应用程序,请将行放在main方法main.m之前UIApplicationMain(...).
Bar*_*zyk 13
您对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.
geo*_*eon 12
正如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;
}
我对此表示感谢.
小智 11
我最喜欢Mauro Delrio的方法.我还在Project_Prefix.pch中添加了以下内容
#import "Language.h"    
#define MyLocalizedString(key, alt) [Language get:key alter:alt]
因此,如果您想使用标准方法(使用NSLocalizedString),您可以在所有文件中进行快速语法替换.
Mec*_*cki 11
NSLocalizedString()AppleLanguages从标准用户默认值([NSUserDefaults standardUserDefaults])读取键的值.它使用该值在运行时在所有现有本地化中选择适当的本地化.当Apple在应用程序启动时构建用户默认字典时,他们会在系统首选项中查找首选语言键并从中复制值.这也解释了为什么更改OS X中的语言设置对运行应用程序没有影响,仅限于此后启动的应用程序.复制后,仅因为设置更改而不更新该值.这就是为什么iOS重新启动所有应用程序,如果您更改当时的语言.
但是,用户默认字典的所有值都可以被命令行参数覆盖.请参阅有关的NSUserDefaults文档NSArgumentDomain.这甚至包括从app首选项(.plist)文件加载的值.如果您想要仅为测试更改一次值,这真的很好.
因此,如果您只想更改语言以进行测试,您可能不希望更改代码(如果您以后忘记删除此代码...),而是告诉Xcode使用命令行参数启动您的应用程序(例如使用西班牙本地化):

根本不需要触摸您的代码.只需为不同的语言创建不同的方案,您只需切换方案,就可以用一种语言快速启动应用程序,再用另一种语言启动一次.
小智 10
我想出了一个允许你使用的解决方案NSLocalizedString.我创建了一个NSBundle电话类别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.这可以存储在您喜欢的任何地方.
我唯一不喜欢的是NSLocalizedString马克重新定义的警告.也许有人可以帮我解决这个问题.
Swift版本:
NSUserDefaults.standardUserDefaults().setObject(["fr"], forKey: "AppleLanguages")
NSUserDefaults.standardUserDefaults().synchronize()
您要做的第一件事就是使用至少两种语言(本例中为英语和法语)本地化您的应用程序.
在您的代码中NSLocalizedString(key, comment),使用如下MYLocalizedString(key, comment)定义的宏而不是使用:
#define MYLocalizedString(key, comment) [[MYLocalizationSystem sharedInstance] localizedStringForKey:(key) value:(comment)];
这个MYLocalizationSystem单身人士将:
当用户用法语更改应用程序语言时,请致电 [[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];
}
在此示例中,此方法将本地化的bundle设置为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的这篇文章中找到更多细节
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
小智 6
在 swift 4 中,我已经解决了它而无需重新启动或使用库。
在尝试了很多选项后,我找到了这个函数,在那里你传递了你想翻译的 stringToLocalize(Localizable.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
我不知道这是否是最好的方法,但我发现它非常简单,并且对我有用,希望对您有所帮助!
小智 5
在文件.pch中定义:
#define currentLanguageBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[[NSLocale preferredLanguages] objectAtIndex:0] ofType:@"lproj"]]
#define NSLocalizedString(str,nil) NSLocalizedStringFromTableInBundle(str, nil, currentLanguageBundle, @"")
| 归档时间: | 
 | 
| 查看次数: | 139926 次 | 
| 最近记录: |