วิธีการบังคับ NSLocalizedString ให้ใช้ภาษาเฉพาะ


263

บน iPhone NSLocalizedStringส่งคืนสตริงในภาษาของ iPhone เป็นไปได้ไหมที่จะบังคับNSLocalizedStringให้ใช้ภาษาเฉพาะเพื่อให้แอปมีภาษาที่แตกต่างจากอุปกรณ์


โปรดอ้างอิงสิ่งนี้: stackoverflow.com/a/48187049/6665075ทำงานเหมือน
เครื่องราง

คำตอบ:


261

NSLocalizedString()(และตัวแปรต่างๆ) เข้าถึงปุ่ม "AppleLanguage" 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
Denniss; ดูเหมือนว่าจะทำงานได้ดีขึ้นหากคุณตั้งค่าภาษาก่อนที่จะเปิดตัวแอพ ฉันทำมันในฟังก์ชั่น main () ก่อนที่จะเรียก UIApplicationMain () เมื่อมันทำงานจริงมันจะไม่เปลี่ยนภาษาที่ใช้ แต่เพียงแค่ตั้งค่าในครั้งต่อไป
geon

3
คุณต้องตั้งค่าภาษาก่อนที่คุณจะเริ่มต้น UIKit และคุณต้องระบุภาษาที่สมบูรณ์ + ภูมิภาคสถานที่ - ตรวจสอบสิ่งนี้สำหรับตัวอย่างที่สมบูรณ์blog.federicomestrone.com/2010/09/15/…
fedmest

18
การตั้งค่า AppleLanguages ​​จะเปลี่ยนภาษาที่รันไทม์หากทำใน main () - จริง! แต่ ... การติดตั้งแอปครั้งแรก nsuserdefaults จะเริ่มต้นหลังจากเรียกใช้ UIApplicationMain () ซึ่งจะเพิกเฉยต่อแอปเปิ้ลภาษาที่ตั้งค่าไว้ก่อนหน้านี้และจะต้องบังคับให้รีสตาร์ทแอปน่าเกลียดเพื่อดูภาษาที่ต้องการ
JohnPayne

3
สิ่งนี้ไม่ทำงานกับรายการพหูพจน์ที่กำหนดใน Localizable.stringsdict ความคิดใด ๆ หากมีการแก้ไขที่เป็นไปได้?
หมดเวลา Fratu

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"];

หากต้องการรีเซ็ตกลับเป็นค่าเริ่มต้นของระบบเพียงส่งผ่านไม่มี:

[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

7
นี่เป็นทางออกที่ยอดเยี่ยมฉันยังอ้างอิงที่นี่: medium.com/ios-apprentice/905e4052b9de
James Tang

1
สวัสดี @JamesTang ขอบคุณสำหรับการอ้างอิงและโพสต์ของคุณ - ฉันพบข้อมูลที่เป็นประโยชน์มากมายเกี่ยวกับการแปล
Gilad Novik

3
@Gilad วิธีการของคุณทำงานได้อย่างสมบูรณ์แบบสำหรับสตริงแบบไดนามิก (สตริงที่ฉันกำหนดไว้ใน localizable.strings) แต่สำหรับปุ่มสตอรี่บอร์ดและป้ายกำกับมันทำงานได้เฉพาะที่เมธอดหลักเท่านั้น ดังนั้นคุณสามารถขยายคำตอบเพื่อรวมการควบคุมการแปล UI ได้หรือไม่ ฉันหมายถึงวิธีการรีเฟรชกระดานเรื่องราว (โดยไม่ปิด) หลังจากฉันเรียกใช้ [NSBundle setLanguage: @ "??"] ;?
Jawad Al Shaikh

2
สำหรับ XIB / กระดานเรื่องราว: คุณต้องแน่ใจว่าคุณเรียกใช้วิธีนี้ก่อนที่คุณจะโหลดมุมมอง การอัปเดตจำนวนการดูสดๆ: ในกรณีของฉันฉันเพิ่งโหลดตัวควบคุมมุมมองใหม่ (ฉันใส่ไว้ในตัวควบคุมทิศทางและเพิ่งแทนที่ตัวควบคุมเมื่อทำการโหลดใหม่ - มันได้รับการแปลใหม่) ฉันกำลังทำงานกับ cocoapod สำหรับมันฉันอาจจะมีตัวอย่างที่นั่นด้วย คอยติดตาม ...
Gilad Novik

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
สุดยอด Mauro ฉันสังเกตเห็นว่าสามารถใช้งานไฟล์จากโครงการของคุณได้ ถ้าด้วยเหตุผลบางอย่าง (ในกรณีของฉัน) คุณจำเป็นต้องดาวน์โหลดไฟล์สตริงจากเครือข่ายและเก็บไว้ในไดเรกทอรี 'เอกสาร' ของคุณ (ด้วยโครงสร้างโฟลเดอร์ Documents / en.lproj / Localizable.strings, Documents / fr.lproj / Localizable.strings, ... ) คุณสามารถสร้าง NSBundle ได้ เพียงใช้รหัสนี้สำหรับเส้นทาง: NSString * path = [NSHomeDirectory () stringByAppendingPathComponent: [NSString stringWithFormat: @ "/ เอกสาร /% @. lproj", l, nil]];
arnaud del

1
ดูเหมือนว่านี่เป็นวิธีที่ดีที่สุดพร้อมกับการมีส่วนร่วมจาก Alessandro ด้านล่าง มันไม่ได้เป็นการล่วงล้ำและไม่จำเป็นต้องเริ่มต้นใหม่
PKCLsoft

1
ผมทำอะไรผิดหรือเปล่า? ฉันสร้างคลาสภาษาสืบทอด NSObject ใส่สิ่งนี้ไว้ในการติดตั้งใส่ชื่อเมธอดเป็น. h แล้วใส่ [Language setLanguage: @ "es"]; ในปุ่มเปลี่ยนภาษาของฉันใช้รหัส (เรียกใช้วิธีการของปุ่มและไปที่คลาสภาษา) แต่ไม่ทำอะไรเลย ฉันมี localizable.strings (สเปน) ตั้งค่าของฉันด้วย แต่ดูเหมือนว่าจะทำงานให้กับผู้คนจำนวนมาก ได้โปรดใครสักคนทำให้ฉันโง่
SirRupertIII

1
@KKendall คุณเรียกแบบนี้: [ภาษา setLanguage: @ "es"]; NSString * stringToUse = [รับภาษา: @ "ข้อความของคุณ" แก้ไข: ไม่มี];
Mikrasya

41

ห้ามใช้บน 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, @""));

2
@ powerj1984: ไม่มันจะเปลี่ยนเฉพาะสตริงในไฟล์ต้นฉบับของคุณ หากคุณต้องการเปลี่ยนภาษา xib คุณจะต้องโหลด xibs ด้วยตนเองจากชุดภาษาที่คุณเลือก
gklka

@gklka ฉันทำตามขั้นตอนที่กำหนดโดย Tudozier แต่ XIB ของฉันไม่ได้เปลี่ยนภาษาดังที่คุณบอกให้โหลด XIB ด้วยมืออีกครั้งมันหมายถึงอะไรจริง ๆ ในการโหลด XIB ใหม่
Dk Kumar

@DkKumar: คุณต้องทำสิ่งที่คล้ายกับสิ่งนี้: stackoverflow.com/questions/21304988/ …
gklka

@gklka คำตอบของคุณดูเหมือนจะถูกต้องและฉันได้ทำตามขั้นตอนเดียวกับที่คุณบอกในคำตอบของคุณแล้ว แต่สิ่งที่เป็นปัญหาคือถ้าเราเปลี่ยนเส้นทางของบันเดิลมากกว่าที่จะหาทรัพยากรทั้งหมด (เช่นไฟล์. png ที่ใช้ใน XIB) ใน ชุดเดียวกันดังนั้นเราต้องคัดลอกโฟลเดอร์รูปภาพในชุดทั้งหมดเช่น en.lproj, es.lproj และอื่น ๆ .. ดังนั้นจะมีผลต่อการเพิ่มขนาด IPA ดังนั้นจะมีวิธีแก้ไขปัญหานี้หรือไม่? อย่างที่คุณพูดในโพสต์ของคุณขอให้ฉันลองทำสิ่งนี้และให้คุณได้มากกว่านี้ขอบคุณที่ช่วยฉันด้วยเหมือนกัน
Dk Kumar

1
สิ่งนี้หักอย่างน่ากลัวใน iOS 9 คืนค่า null สำหรับสตริงทั้งหมด
Alex Zavatone

32

ดังที่ได้กล่าวไว้ก่อนหน้านี้เพียงทำ:

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

แต่เพื่อหลีกเลี่ยงการรีสตาร์ทแอพให้วางสายในวิธีการหลักmain.mก่อนหน้าUIApplicationMain(... )


2
คำตอบที่เป็นประโยชน์มาก! PS อาจให้เสียงที่ชัดเจนสำหรับผู้ที่ไม่ได้เริ่มต้น แต่คุณควรแทรกบรรทัดนั้นหลังจากนั้นNSAutoreleasePool * pool ..หรือวัตถุออโต้เซลเลอร์บางตัวอาจรั่วไหล
pt2ph8

1
สำคัญ: มันจะไม่ทำงานถ้าคุณโทร[[NSBundle mainBundle] URLForResource:withExtension:]มาก่อน
Kof

3
ถ้าใช้ Swift จะไม่มี main.m
turingtested

@turingtested คุณลองอย่างรวดเร็วและกระดานเรื่องราวแล้วมันใช้งานได้หรือไม่
iDevAmit

สวัสดีวิธีการ จำกัด ข้อความไดนามิกที่มาจากเซิร์ฟเวอร์ในแอปพลิเคชันของฉันทุกข้อความฉันต้องแสดงเป็นภาษาจีนตัวย่อ แต่จะแสดงข้อความเป็นภาษาจีนซึ่งมาเป็นภาษาอังกฤษได้อย่างไร ช่วยฉันด้วย.
Mahesh Narla

31

เคล็ดลับในการใช้ภาษาเฉพาะโดยเลือกจากแอพนี้คือการบังคับNSLocalizedStringให้ใช้กลุ่มเฉพาะขึ้นอยู่กับภาษาที่เลือก

นี่คือโพสต์ที่ฉันได้เขียนสำหรับการแปลล่วงหน้าการเรียนรู้นี้ ในแอป iOS

และนี่คือรหัสของการแปลแอปล่วงหน้าอย่างเดียวในแอป iOS


มันใช้งานได้บน iOS7 เช่นกันฉันต้องเปลี่ยนจากโซลูชันของ Brian ไปเป็นเพราะดูเหมือนว่า iOS จะแทนที่ตัวเลือกภาษาอีกครั้งดังนั้นฉันจึงติดตั้งภาษาเป็นครั้งแรก โซลูชันของคุณใช้งานได้อย่างมีเสน่ห์!
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

คำตอบที่ดีช่วยฉันได้
Dilip Tiwari

13

ตามที่ 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;
}

ฉันขอขอบคุณความคิดเห็นใด ๆ เกี่ยวกับเรื่องนี้


ในการติดตั้งของฉันมันเป็นสิ่งที่ผู้ใช้ตั้งค่าได้ - ดังนั้นฉันเพิ่งเปิดกล่องโต้ตอบเพื่อบอกพวกเขาว่าพวกเขาจะต้องเริ่มต้นใหม่ :)
William Denniss

ใช้งานได้เกือบทั้งหมด - ยกเว้นอิมเมจ Default.png ที่แปลเป็นภาษาท้องถิ่น
Lukasz

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 = [พา ธ มัด forFores ทรัพยากร: imageFileName ofType: @ "png"]; UIImage * imageObj = [[UIImage จัดสรร] initWithContentsOfFile: fullPath]; คืนค่า [imageObj autorelease]; }
Jagie

11

NSLocalizedString()อ่านค่าสำหรับคีย์AppleLanguagesจากค่าเริ่มต้นผู้ใช้มาตรฐาน ( [NSUserDefaults standardUserDefaults]) มันใช้ค่านั้นเพื่อเลือกการแปลที่เหมาะสมระหว่างการแปลที่มีอยู่ทั้งหมดที่รันไทม์ เมื่อ Apple สร้างพจนานุกรมค่าเริ่มต้นของผู้ใช้ในการเปิดตัวแอปพวกเขาจะค้นหาคีย์ภาษาที่ต้องการในการตั้งค่าระบบและคัดลอกค่าจากที่นั่น นอกจากนี้ยังอธิบายได้ว่าทำไมการเปลี่ยนการตั้งค่าภาษาใน OS X จึงไม่มีผลกับแอพที่ใช้งาน เมื่อคัดลอกแล้วค่าจะไม่ได้รับการอัพเดตเพียงเพราะการเปลี่ยนแปลงการตั้งค่า นั่นเป็นสาเหตุที่ iOS รีสตาร์ทแอพทั้งหมดหากคุณเปลี่ยนภาษา

อย่างไรก็ตามค่าทั้งหมดของพจนานุกรมค่าเริ่มต้นของผู้ใช้สามารถเขียนทับโดยอาร์กิวเมนต์บรรทัดคำสั่ง ดูเอกสารบนNSUserDefaults NSArgumentDomainซึ่งรวมถึงค่าเหล่านั้นที่โหลดจากไฟล์การตั้งค่าแอพ (.plist) นี้เป็นสิ่งที่ดีมากที่จะรู้ว่าถ้าคุณต้องการที่จะเปลี่ยนค่าเพียงครั้งเดียวสำหรับการทดสอบ

ดังนั้นหากคุณต้องการเปลี่ยนภาษาสำหรับการทดสอบคุณอาจไม่ต้องการเปลี่ยนรหัสของคุณ (หากคุณลืมที่จะลบรหัสนี้ในภายหลัง ... ) ให้บอก Xcode ให้เริ่มต้นแอปของคุณด้วยพารามิเตอร์บรรทัดคำสั่ง ( เช่นใช้การแปลภาษาสเปน):

ป้อนคำอธิบายรูปภาพที่นี่

ไม่จำเป็นต้องแตะรหัสของคุณเลย เพียงสร้างรูปแบบที่แตกต่างกันสำหรับภาษาที่แตกต่างกันและคุณสามารถเริ่มแอพได้อย่างรวดเร็วหนึ่งครั้งในหนึ่งภาษา


มันใช้งานได้เพียง 1 ครั้งหลังจากนั้นมันจะโหลดเข้าสู่อุปกรณ์ pref อีกครั้ง ภาษา ..
Aks

@Aks ทำงานทุกครั้งสำหรับฉัน ตรวจสอบให้แน่ใจว่าคุณกำลังเริ่มต้นรูปแบบที่ถูกต้องตรวจสอบให้แน่ใจว่าคุณเริ่มต้นจากภายใน Xcode (เปิดใช้งานใหม่ส้อม ฯลฯ จะไม่ได้รับการโต้แย้ง) และตรวจสอบให้แน่ใจว่าคุณไม่ได้แทนที่ภาษาOptionsเช่นเดียวกับรุ่น Xcode รุ่นใหม่ เช่นกัน
Mecki

ขอบคุณสำหรับการตอบกลับของคุณ @Mecki .. สำหรับฉันมันไม่ทำงานใน xcode แต่เมื่อฉันพูดถึงในรหัสมันใช้งานได้ แต่ยังถ้าฉันได้ตั้งค่าอุปกรณ์ของฉันด้วยภาษาที่ต้องการอื่น ๆ มันต้องรีสตาร์ทแอปเพื่อโหลดลงในที่ต้องการ ภาษาที่ฉันผ่านในการขัดแย้ง ....
Aks

@Aks เมื่อใช้สิ่งนั้นกับอุปกรณ์มันจะทำงานได้ก็ต่อเมื่อเริ่มต้นโดยตรงจาก Xcode มันจะไม่ทำงานเมื่อคุณเริ่มต้นแอปอีกครั้งโดยแตะที่ไอคอนในอุปกรณ์บางอย่างและมันจะไม่ทำงานเมื่อแอพถูกฆ่า (เช่น เพราะมันทำงานเป็นแบ็คกราวน์) และได้รับการรีสตาร์ทโดยระบบ (เนื่องจากการรีสตาร์ทนี้ไม่ใช่การรีสตาร์ทโดย Xcode) - ดังนั้นการสลับไปใช้แอพอื่นและกลับมาอาจไม่ทำงานหาก iOS ต้องฆ่าแอปของคุณ ต้องการหน่วยความจำ)
Mecki

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

มากกว่าเพียงแค่การเพิ่มการนำเข้าเป็นไฟล์ที่ใช้งานNSBundle+RunTimeLanguage.hNSLocalizedString

ที่คุณสามารถดูฉันเก็บ LanguageCode AppDelegateของฉันในทรัพย์สินของ สามารถเก็บไว้ที่ใดก็ได้ที่คุณต้องการ

สิ่งเดียวที่ฉันไม่ชอบคือคำเตือนที่NSLocalizedStringmarco นิยามใหม่ บางทีบางคนอาจช่วยฉันแก้ไขส่วนนี้


1
เพิ่ม#undef NSLocalizedStringก่อนที่#defineจะปิดการใช้งานคำเตือน
เบริลเลียม

สิ่งนี้ใช้ได้กับการแปลเป็นภาษาท้องถิ่นสำหรับไฟล์ xib หรือไม่ ฉันมีไฟล์. xib และ. strings เพื่อแปลชื่อ UIs ในภาษาเฉพาะ ฉันพยายามและมันใช้งานไม่ได้กับ XIB แต่ฉันไม่แน่ใจว่าฉันทำสิ่งต่าง ๆ ถูกต้องหรือไม่
Kong Hantrakool

ฮ่องกงขออภัยสำหรับการตอบกลับที่ล่าช้า สิ่งนี้ทำงานได้ทุกเมื่อที่คุณใช้ NSLocalizedString ดังนั้นมันจะไม่ทำงานโดยตรงใน XIB คุณจะต้อง IBOutlets กับสตริงใน XIB และจากนั้นจะต้องตั้งค่าสตริงในโค้ดโดยทางโปรแกรม
qman64

วิธีนี้ใช้ได้ผลสำหรับฉันและฉันสามารถเปลี่ยนภาษาได้ทันที โปรดทราบว่ารหัสภาษาเช่น "es", fr "และ" en "ทำงานได้ดี แต่" zh "(สำหรับภาษาจีนตัวย่อ) ล้มเหลวและทำให้ฉันมีค่า Null กลับมาฉันได้ทำการค้นหาทั่วโลกในระบบของฉันสำหรับ" es.lproj "เพื่อ ดูว่าไฟล์ที่ฉันกำลังเข้าถึงนั้นอยู่ที่ไหนและฉันค้นพบว่า "zh.lproj" เป็นจริง "zh-Hans.lproj"
Gallymon

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ซิงเกิลนี้จะ:

  • ตั้งค่า langage โดยตั้งค่าผู้ใช้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


เราขอให้คุณไม่เพียง แต่เชื่อมโยงไปยังโซลูชันในคำตอบของคุณ ลิงก์อาจหยุดทำงานในบางวัน แม้ว่าคุณจะไม่ต้องลบลิงก์ออกจากคำตอบของคุณ แต่เราขอให้คุณแก้ไขคำตอบของคุณเพื่อรวมบทสรุปของส่วนที่เกี่ยวข้องของบทความที่เชื่อมโยง
Sage หลงลืม

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

ขอบคุณ ทำงานได้ดี
Krunal Nagvadia

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

1
ทางออกที่ง่ายทำทุกอย่างที่ฉันต้องการ สามารถใช้สิ่งนี้เป็นแนวทางในการแก้ปัญหาของฉันได้ ถ้า pathForResource ส่งคืนค่าศูนย์เนื่องจากฉันไม่มีไฟล์การแปลภาษาท้องถิ่นฉันจะใช้ pathForResource: @ "Base" เนื่องจากไม่มีสิ่งอื่นใดที่ฉันได้ลองดึงสตริงจากการแปลพื้นฐาน ขอบคุณ.
GRW

นี่คือแฮ็ค (เป็นคำตอบอื่น ๆ ทั้งหมด) และมันง่ายที่สุดที่จะใช้ในการทดสอบหน่วยที่ฉันเขียน
สูงสุด

4

บางทีคุณควรเติมเต็มด้วย (ในไฟล์. 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]

/Users/pwang/Desktop/Myshinesvn/Myshine/viewController/OrientationReadyPagesView.m:193:31: การใช้ 'bundle' ของตัวระบุที่ไม่ได้ประกาศ
pengwang

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

คุณสามารถสร้างกลุ่มย่อยด้วยชุดของสตริงที่แปลเป็นภาษาท้องถิ่นที่คุณต้องการทำด้วยแล้วใช้NSLocalizedStringFromTableInBundle()ในการโหลดพวกเขา (ฉันสมมติว่านี่เป็นเนื้อหาที่แยกต่างหากจากการแปล UI ปกติที่คุณอาจทำในแอป)


3

สำหรับกรณีของฉันฉันมีสองไฟล์ที่แปลเป็นภาษาท้องถิ่น, 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]));


    }


}

ขอบคุณ @ chings228 มันมีประโยชน์สำหรับฉัน แต่นี่ไม่เปลี่ยนภาพเปิดตัวเริ่มต้น (splash) สำหรับแอพที่ฉันมี splashs ที่แตกต่างกันสำหรับแต่ละภาษา คุณรู้วิธีการสมัครนี้หรือไม่?
JERC

ฉันคิดว่าสแปลชทำงานก่อนที่โปรแกรมหลักจะเริ่มทำงานดังนั้นฉันไม่ทราบวิธีการลบล้างมันอาจจะสามารถช่วยได้ แต่มันอาจใช้ได้ในครั้งต่อไปที่แอปเปิดขึ้น
chings228

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:

    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 ไม่สนับสนุนอย่างเป็นทางการ (ไม่อยู่ในส่วนภาษาภายใต้การตั้งค่าระบบ) ด้วยการทำตาม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 ด้านบนเพื่อดูวิธีการทำ)


ฉันเห็นว่าคุณกำลังประสบปัญหากับภาษาสโลวีเนียด้วยเช่นกัน :) เพื่อปรับปรุงคำตอบสำหรับภาษาที่ iOS ไม่สนับสนุนให้คุณลองคิดดูไหมว่าเราสามารถตั้งค่าสตริงที่แปลได้แบบกำหนดเองซึ่งจะใช้สำหรับการควบคุมระบบในแอป ... )?
miham

1

นี่เป็นวิธีแก้ปัญหาที่เหมาะสมสำหรับปัญหานี้และไม่จำเป็นต้องรีสตาร์ทแอปพลิเคชัน

https://github.com/cmaftuleac/BundleLocalization

การติดตั้งใช้งานได้โดยปรับแต่งภายใน NSBundle แนวคิดคือคุณแทนที่เมธอด localizedStringForKey บนอินสแตนซ์ของออบเจ็กต์ NSBundle จากนั้นเรียกใช้เมธอดนี้บนบันเดิลอื่นด้วยภาษาที่แตกต่างกัน เรียบง่ายและสง่างามเข้ากันได้อย่างสมบูรณ์กับทรัพยากรทุกประเภท


รหัสนี้จากโครงการช่วยฉันได้มาก วิธีค้นหาบันเดิลสำหรับรหัสภาษาที่เฉพาะเจาะจง ---NSString *path = [[NSBundle mainBundle] pathForResource:lang ofType:@"lproj" ];
Eonil

คลาสนี้ทำงานได้ดี แต่หลังจากเปลี่ยนภาษาเป็นอื่นแล้วจะไม่มีผล
Anilkumar iOS ReactNative

0

ทุกสิ่งที่คุณทำวิธีที่ดีที่สุดคือการใช้ short_name สำหรับภาษาที่ระบุเช่น: fr, en, nl, de, it ฯลฯ ... และกำหนดค่าเดียวกันให้กับค่าโกลบอล

ทำให้มุมมองตัวเลือกปรากฏขึ้นเช่นเมนูแบบเลื่อนลง (ปุ่มผสมเมื่อคลิกซึ่งมุมมองตัวเลือกปรากฏขึ้นจากด้านล่างพร้อมกับรายการภาษา) และเลือกภาษาที่คุณต้องการ ปล่อยให้ชื่อย่อถูกเก็บไว้ภายใน ทำให้ไฟล์. h + .m ชื่อ LocalisedString

ตั้งค่าโกลบอลของ 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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.