How to force NSLocalizedString to use a specific l

2018-12-31 01:34发布

On iPhone NSLocalizedString returns the string in the language of the iPhone. Is it possible to force NSLocalizedString to use a specific language to have the app in a different language than the device ?

25条回答
千与千寻千般痛.
2楼-- · 2018-12-31 02:17

I usually do this in this way, but you MUST have all localization files in your project.

@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
查看更多
骚的不知所云
3楼-- · 2018-12-31 02:18

NSLocalizedString() reads the value for the key AppleLanguages from the standard user defaults ([NSUserDefaults standardUserDefaults]). It uses that value to choose an appropriate localization among all existing localizations at runtime. When Apple builds the user defaults dictionary at app launch, they look up the preferred language(s) key in the system preferences and copy the value from there. This also explains for example why changing the language settings in OS X has no effect on running apps, only on apps started thereafter. Once copied, the value is not updated just because the settings change. That's why iOS restarts all apps if you change then language.

However, all values of the user defaults dictionary can be overwritten by command line arguments. See NSUserDefaults documentation on the NSArgumentDomain. This even includes those values that are loaded from the app preferences (.plist) file. This is really good to know if you want to change a value just once for testing.

So if you want to change the language just for testing, you probably don't want to alter your code (if you forget to remove this code later on ...), instead tell Xcode to start your app with a command line parameters (e.g. use Spanish localization):

enter image description here

No need to touch your code at all. Just create different schemes for different languages and you can quickly start the app once in one language and once in another one by just switching the scheme.

查看更多
梦该遗忘
4楼-- · 2018-12-31 02:19

What do you think about this solution for 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)
    }
}

Simple usage:

"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.
查看更多
ら面具成の殇う
5楼-- · 2018-12-31 02:19

Swift 3 extensions:

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

Usage:

Locale.preferredLanguage = "uk"

label.text = "localizedKey".localized
查看更多
怪性笑人.
6楼-- · 2018-12-31 02:20

I like best Mauro Delrio's method. I also have added the following in my Project_Prefix.pch

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

So if you ever want to use the standard method (that uses NSLocalizedString) you can make a quick syntax substitution in all files.

查看更多
梦寄多情
7楼-- · 2018-12-31 02:22

I came up with a solution that allows you to use NSLocalizedString. I create a category of NSBundle call NSBundle+RunTimeLanguage. The interface is like this.

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

The implementation is like this.

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

Than just add import NSBundle+RunTimeLanguage.h into the files that use NSLocalizedString.

As you can see I store my languageCode in a property of AppDelegate. This could be stored anywhere you'd like.

This only thing I don't like about it is a Warning that NSLocalizedString marco redefined. Perhaps someone could help me fix this part.

查看更多
登录 后发表回答