บน 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.h
NSLocalizedString
ที่คุณสามารถดูฉันเก็บ LanguageCode AppDelegate
ของฉันในทรัพย์สินของ สามารถเก็บไว้ที่ใดก็ได้ที่คุณต้องการ
สิ่งเดียวที่ฉันไม่ชอบคือคำเตือนที่NSLocalizedString
marco นิยามใหม่ บางทีบางคนอาจช่วยฉันแก้ไขส่วนนี้
#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