บน iPhone NSLocalizedStringส่งคืนสตริงในภาษาของ iPhone เป็นไปได้ไหมที่จะบังคับNSLocalizedStringให้ใช้ภาษาเฉพาะเพื่อให้แอปมีภาษาที่แตกต่างจากอุปกรณ์
บน iPhone NSLocalizedStringส่งคืนสตริงในภาษาของ iPhone เป็นไปได้ไหมที่จะบังคับNSLocalizedStringให้ใช้ภาษาเฉพาะเพื่อให้แอปมีภาษาที่แตกต่างจากอุปกรณ์
คำตอบ:
NSLocalizedString()(และตัวแปรต่างๆ) เข้าถึงปุ่ม "AppleLanguage" NSUserDefaultsเพื่อกำหนดการตั้งค่าของผู้ใช้สำหรับภาษาที่ต้องการ สิ่งนี้จะส่งคืนรหัสภาษาหลายประเภทโดยชุดแรกจะเป็นรหัสภาษาที่ผู้ใช้ตั้งค่าไว้สำหรับโทรศัพท์และรหัสต่อมาจะใช้เป็นทางเลือกหากทรัพยากรไม่พร้อมใช้งานในภาษาที่ต้องการ (บนเดสก์ท็อปผู้ใช้สามารถระบุหลายภาษาด้วยการสั่งซื้อที่กำหนดเองในการตั้งค่าระบบ)
คุณสามารถแทนที่การตั้งค่าส่วนกลางสำหรับแอปพลิเคชันของคุณเองหากคุณต้องการโดยใช้วิธี setObject: forKey: เพื่อตั้งค่ารายการภาษาของคุณเอง สิ่งนี้จะมีความสำคัญมากกว่าค่าที่ตั้งไว้ทั่วโลกและจะถูกส่งกลับไปยังรหัสใด ๆ รหัสสำหรับสิ่งนี้จะมีลักษณะดังนี้:
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"de", @"en", @"fr", nil] forKey:@"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize]; //to make the change immediate
นี่จะทำให้ภาษาเยอรมันเป็นภาษาที่ต้องการสำหรับการสมัครของคุณโดยใช้ภาษาอังกฤษและฝรั่งเศสเป็นทางเลือก คุณต้องการที่จะเรียกสิ่งนี้ในช่วงต้นของการเริ่มต้นแอปพลิเคชันของคุณ คุณสามารถอ่านเพิ่มเติมเกี่ยวกับการตั้งค่าภาษา / สถานที่ได้ที่นี่: หัวข้อการเขียนโปรแกรมเป็นสากล: รับภาษาปัจจุบันและภาษา
ฉันมีปัญหาเดียวกันเมื่อเร็ว ๆ นี้และฉันไม่ต้องการที่จะเริ่มต้นและแก้ไข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"];หากต้องการรีเซ็ตกลับเป็นค่าเริ่มต้นของระบบเพียงส่งผ่านไม่มี:
[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)
    }
}
ฉันมักจะทำเช่นนี้ด้วยวิธีนี้ แต่คุณต้องมีไฟล์การแปลในโครงการของคุณ
@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
ห้ามใช้บน iOS 9 นี่จะส่งคืนศูนย์สำหรับสตริงทั้งหมดที่ส่งผ่าน
ฉันได้พบวิธีแก้ไขปัญหาอื่นที่ช่วยให้คุณอัปเดตสตริงภาษาโดยไม่ต้องรีสตาร์ทแอพและเข้ากันได้กับ 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, @""));
ดังที่ได้กล่าวไว้ก่อนหน้านี้เพียงทำ:
[[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObjects:@"el", nil] forKey:@"AppleLanguages"];แต่เพื่อหลีกเลี่ยงการรีสตาร์ทแอพให้วางสายในวิธีการหลักmain.mก่อนหน้าUIApplicationMain(... )
NSAutoreleasePool * pool ..หรือวัตถุออโต้เซลเลอร์บางตัวอาจรั่วไหล
                    [[NSBundle mainBundle] URLForResource:withExtension:]มาก่อน
                    เคล็ดลับในการใช้ภาษาเฉพาะโดยเลือกจากแอพนี้คือการบังคับNSLocalizedStringให้ใช้กลุ่มเฉพาะขึ้นอยู่กับภาษาที่เลือก
นี่คือโพสต์ที่ฉันได้เขียนสำหรับการแปลล่วงหน้าการเรียนรู้นี้ ในแอป iOS
คุณคิดอย่างไรเกี่ยวกับโซลูชันนี้สำหรับ 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.ตามที่ Brian Webster กล่าวถึงภาษาจะต้องมีการตั้งค่า "บางครั้งในช่วงต้นของการเริ่มต้นแอปพลิเคชันของคุณ" ผมคิดว่าapplicationDidFinishLaunching:ของAppDelegateที่ควรจะเป็นสถานที่ที่เหมาะสมที่จะทำมันเพราะมันคือสิ่งที่ฉันจะเริ่มต้นอื่น ๆ ทั้งหมด
แต่ตามที่ William Denniss กล่าวถึงดูเหมือนว่าจะมีผลหลังจากรีสตาร์ทแอปแล้วเท่านั้นซึ่งไร้ประโยชน์
ดูเหมือนว่าจะทำงานได้ดีถ้าฉันใส่รหัสในฟังก์ชั่นหลักแม้ว่า:
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;
}ฉันขอขอบคุณความคิดเห็นใด ๆ เกี่ยวกับเรื่องนี้
[[NSUserDefaults standardUserDefaults] synchronize];หลังจากโทรsetObject:forKey:
                    ฉันชอบวิธีที่ดีที่สุดของ Mauro Delrio ฉันยังได้เพิ่มสิ่งต่อไปนี้ใน Project_Prefix.pch ของฉัน
#import "Language.h"    
#define MyLocalizedString(key, alt) [Language get:key alter:alt]ดังนั้นหากคุณต้องการใช้วิธีมาตรฐาน (ที่ใช้ NSLocalizedString) คุณสามารถทำการทดแทนไวยากรณ์อย่างรวดเร็วในไฟล์ทั้งหมด
NSLocalizedString()อ่านค่าสำหรับคีย์AppleLanguagesจากค่าเริ่มต้นผู้ใช้มาตรฐาน ( [NSUserDefaults standardUserDefaults]) มันใช้ค่านั้นเพื่อเลือกการแปลที่เหมาะสมระหว่างการแปลที่มีอยู่ทั้งหมดที่รันไทม์ เมื่อ Apple สร้างพจนานุกรมค่าเริ่มต้นของผู้ใช้ในการเปิดตัวแอปพวกเขาจะค้นหาคีย์ภาษาที่ต้องการในการตั้งค่าระบบและคัดลอกค่าจากที่นั่น นอกจากนี้ยังอธิบายได้ว่าทำไมการเปลี่ยนการตั้งค่าภาษาใน OS X จึงไม่มีผลกับแอพที่ใช้งาน เมื่อคัดลอกแล้วค่าจะไม่ได้รับการอัพเดตเพียงเพราะการเปลี่ยนแปลงการตั้งค่า นั่นเป็นสาเหตุที่ iOS รีสตาร์ทแอพทั้งหมดหากคุณเปลี่ยนภาษา
อย่างไรก็ตามค่าทั้งหมดของพจนานุกรมค่าเริ่มต้นของผู้ใช้สามารถเขียนทับโดยอาร์กิวเมนต์บรรทัดคำสั่ง ดูเอกสารบนNSUserDefaults NSArgumentDomainซึ่งรวมถึงค่าเหล่านั้นที่โหลดจากไฟล์การตั้งค่าแอพ (.plist) นี้เป็นสิ่งที่ดีมากที่จะรู้ว่าถ้าคุณต้องการที่จะเปลี่ยนค่าเพียงครั้งเดียวสำหรับการทดสอบ
ดังนั้นหากคุณต้องการเปลี่ยนภาษาสำหรับการทดสอบคุณอาจไม่ต้องการเปลี่ยนรหัสของคุณ (หากคุณลืมที่จะลบรหัสนี้ในภายหลัง ... ) ให้บอก Xcode ให้เริ่มต้นแอปของคุณด้วยพารามิเตอร์บรรทัดคำสั่ง ( เช่นใช้การแปลภาษาสเปน):

ไม่จำเป็นต้องแตะรหัสของคุณเลย เพียงสร้างรูปแบบที่แตกต่างกันสำหรับภาษาที่แตกต่างกันและคุณสามารถเริ่มแอพได้อย่างรวดเร็วหนึ่งครั้งในหนึ่งภาษา
Optionsเช่นเดียวกับรุ่น Xcode รุ่นใหม่ เช่นกัน
                    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มากกว่าเพียงแค่การเพิ่มการนำเข้าเป็นไฟล์ที่ใช้งานNSBundle+RunTimeLanguage.hNSLocalizedString
ที่คุณสามารถดูฉันเก็บ LanguageCode AppDelegateของฉันในทรัพย์สินของ สามารถเก็บไว้ที่ใดก็ได้ที่คุณต้องการ
สิ่งเดียวที่ฉันไม่ชอบคือคำเตือนที่NSLocalizedStringmarco นิยามใหม่ บางทีบางคนอาจช่วยฉันแก้ไขส่วนนี้
#undef NSLocalizedStringก่อนที่#defineจะปิดการใช้งานคำเตือน
                    เวอร์ชั่นสวิฟท์:
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];
}ในตัวอย่างนี้วิธีนี้ตั้งค่าบันเดิลที่แปลเป็น 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ในไฟล์. pch ที่จะกำหนด:
#define currentLanguageBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[[NSLocale preferredLanguages] objectAtIndex:0] ofType:@"lproj"]]
#define NSLocalizedString(str,nil) NSLocalizedStringFromTableInBundle(str, nil, currentLanguageBundle, @"")บางทีคุณควรเติมเต็มด้วย (ในไฟล์. pch หลัง #import):
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]โซลูชัน 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")ให้ตัวอย่างรหัสภาษาที่สามารถใช้ได้ หวังว่านี่จะช่วยได้
คุณสามารถสร้างกลุ่มย่อยด้วยชุดของสตริงที่แปลเป็นภาษาท้องถิ่นที่คุณต้องการทำด้วยแล้วใช้NSLocalizedStringFromTableInBundle()ในการโหลดพวกเขา (ฉันสมมติว่านี่เป็นเนื้อหาที่แยกต่างหากจากการแปล UI ปกติที่คุณอาจทำในแอป)
สำหรับกรณีของฉันฉันมีสองไฟล์ที่แปลเป็นภาษาท้องถิ่น, ja และ en
และฉันต้องการบังคับให้ en หากภาษาที่ต้องการในระบบไม่ใช่ en หรือ ja
ฉันกำลังจะแก้ไขไฟล์ 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]));
    }
}คุณสามารถทำสิ่งนี้:
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"Localizable" ofType:@"strings" inDirectory:nil forLocalization:@"es"];
NSBundle *spanishBundle = [[NSBundle alloc] initWithPath:[bundlePath stringByDeletingLastPathComponent]];
NSLocalizedStringFromTableInBundle(@"House", nil, spanishBundle, nil):ตามคำตอบของ 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"];ใน swift 4 ฉันแก้ไขได้โดยไม่ต้องรีสตาร์ทหรือใช้ไลบรารี
หลังจากลองตัวเลือกมากมายฉันพบฟังก์ชั่นนี้ที่คุณผ่าน stringToLocalize (ของ Localizable.String, ไฟล์สตริง) ที่คุณต้องการแปลและภาษาที่คุณต้องการแปลและสิ่งที่มันส่งกลับคือค่าสำหรับ สตริงนั้นที่คุณมีในไฟล์ Strings:
    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ฉันไม่รู้ว่ามันเป็นวิธีที่ดีที่สุด แต่ฉันคิดว่ามันง่ายมากและใช้งานได้สำหรับฉันฉันหวังว่ามันจะช่วยคุณได้!
ฟังก์ชั่นนี้จะพยายามรับสตริงที่มีการแปลสำหรับภาษาปัจจุบันและหากไม่พบก็จะได้รับโดยใช้ภาษาอังกฤษ
- (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;
}ฉันต้องการเพิ่มการรองรับภาษาที่ iOS ไม่สนับสนุนอย่างเป็นทางการ (ไม่อยู่ในส่วนภาษาภายใต้การตั้งค่าระบบ) ด้วยการทำตามInternationalization Tutorial ของ Appleและคำแนะนำเล็กน้อยที่นี่โดย 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 รหัสสันนิษฐานว่าผู้ใช้จะมีตัวเลือกในการเปลี่ยนภาษาด้วยตนเองภายในแอปภายหลัง
แน่นอนว่าอย่าลืมเพิ่มการแปลสตอรี่บอร์ดและ Localizable.strings ที่เหมาะสม (ดูลิงก์ไปยังหน้า Apple ด้านบนเพื่อดูวิธีการทำ)
นี่เป็นวิธีแก้ปัญหาที่เหมาะสมสำหรับปัญหานี้และไม่จำเป็นต้องรีสตาร์ทแอปพลิเคชัน
https://github.com/cmaftuleac/BundleLocalization
การติดตั้งใช้งานได้โดยปรับแต่งภายใน NSBundle แนวคิดคือคุณแทนที่เมธอด localizedStringForKey บนอินสแตนซ์ของออบเจ็กต์ NSBundle จากนั้นเรียกใช้เมธอดนี้บนบันเดิลอื่นด้วยภาษาที่แตกต่างกัน เรียบง่ายและสง่างามเข้ากันได้อย่างสมบูรณ์กับทรัพยากรทุกประเภท
NSString *path = [[NSBundle mainBundle] pathForResource:lang ofType:@"lproj" ];
                    ทุกสิ่งที่คุณทำวิธีที่ดีที่สุดคือการใช้ short_name สำหรับภาษาที่ระบุเช่น: fr, en, nl, de, it ฯลฯ ... และกำหนดค่าเดียวกันให้กับค่าโกลบอล
ทำให้มุมมองตัวเลือกปรากฏขึ้นเช่นเมนูแบบเลื่อนลง (ปุ่มผสมเมื่อคลิกซึ่งมุมมองตัวเลือกปรากฏขึ้นจากด้านล่างพร้อมกับรายการภาษา) และเลือกภาษาที่คุณต้องการ ปล่อยให้ชื่อย่อถูกเก็บไว้ภายใน ทำให้ไฟล์. h + .m ชื่อ LocalisedString
ตั้งค่าโกลบอลของ short_name ให้เท่ากับค่าที่ได้รับใน LocalisedString.m เมื่อเลือกภาษาที่ต้องการให้กำหนด NSBundlePath เพื่อสร้างโปรเจ็กต์ย่อยไดเรกทอรีสำหรับภาษาที่ต้องการ สำหรับเช่น nl.proj, en.proj
เมื่อเลือกโฟลเดอร์ proj เฉพาะให้เรียกสตริงที่โลคัลไลซ์แล้วสำหรับภาษาที่เกี่ยวข้องและเปลี่ยนภาษาแบบไดนามิก
ไม่มีกฎหัก
สำหรับ 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