Trên iPhone NSLocalizedString
trả về chuỗi bằng ngôn ngữ của iPhone. Có thể buộc NSLocalizedString
phải sử dụng một ngôn ngữ cụ thể để ứng dụng có ngôn ngữ khác với thiết bị không?
Trên iPhone NSLocalizedString
trả về chuỗi bằng ngôn ngữ của iPhone. Có thể buộc NSLocalizedString
phải sử dụng một ngôn ngữ cụ thể để ứng dụng có ngôn ngữ khác với thiết bị không?
Câu trả lời:
NSLocalizedString()
(và các biến thể của chúng) truy cập khóa "AppleLacular" NSUserDefaults
để xác định cài đặt của người dùng cho các ngôn ngữ ưa thích là gì. Điều này trả về một mảng mã ngôn ngữ, với mã đầu tiên là mã do người dùng đặt cho điện thoại của họ và mã tiếp theo được sử dụng làm dự phòng nếu tài nguyên không có sẵn trong ngôn ngữ ưa thích. (trên máy tính để bàn, người dùng có thể chỉ định nhiều ngôn ngữ với thứ tự tùy chỉnh trong Tùy chọn hệ thống)
Bạn có thể ghi đè cài đặt chung cho ứng dụng của riêng bạn nếu bạn muốn bằng cách sử dụng phương thức setObject: forKey: để đặt danh sách ngôn ngữ của riêng bạn. Điều này sẽ được ưu tiên hơn giá trị được đặt trên toàn cầu và được trả lại cho bất kỳ mã nào trong ứng dụng của bạn đang thực hiện nội địa hóa. Mã cho điều này sẽ trông giống như:
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"de", @"en", @"fr", nil] forKey:@"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize]; //to make the change immediate
Điều này sẽ làm cho tiếng Đức trở thành ngôn ngữ ưa thích cho ứng dụng của bạn, với tiếng Anh và tiếng Pháp là dự phòng. Bạn sẽ muốn gọi điều này đôi khi sớm khi khởi động ứng dụng của bạn. Bạn có thể đọc thêm về sở thích ngôn ngữ / ngôn ngữ tại đây: Chủ đề lập trình quốc tế hóa: Lấy ngôn ngữ và ngôn ngữ hiện tại
Gần đây tôi đã gặp vấn đề tương tự và tôi không muốn bắt đầu và vá toàn bộ NSLocalizedString của mình cũng như không buộc ứng dụng khởi động lại để ngôn ngữ mới hoạt động. Tôi muốn mọi thứ để làm việc như vốn có.
Giải pháp của tôi là thay đổi linh hoạt lớp của gói chính và tải gói phù hợp ở đó:
Tập tin tiêu đề
@interface NSBundle (Language)
+(void)setLanguage:(NSString*)language;
@end
Thực hiện
#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
Về cơ bản, khi ứng dụng của bạn khởi động và trước khi bạn tải bộ điều khiển đầu tiên, chỉ cần gọi:
[NSBundle setLanguage:@"en"];
Khi người dùng của bạn thay đổi ngôn ngữ ưa thích trong màn hình cài đặt của bạn, chỉ cần gọi lại:
[NSBundle setLanguage:@"fr"];
Để đặt lại về mặc định hệ thống, chỉ cần chuyển nil:
[NSBundle setLanguage:nil];
Thưởng thức...
Đối với những người cần một phiên bản 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)
}
}
Tôi thường làm điều này theo cách này, nhưng bạn PHẢI có tất cả các tệp bản địa hóa trong dự án của bạn.
@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
Không sử dụng trên iOS 9. Điều này trả về con số không cho tất cả các chuỗi được truyền qua nó.
Tôi đã tìm thấy một giải pháp khác cho phép bạn cập nhật các chuỗi ngôn ngữ, không khởi động lại ứng dụng và tương thích với các genstrings:
Đặt macro này trong Prefix.pch:
#define currentLanguageBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[[NSLocale preferredLanguages] objectAtIndex:0] ofType:@"lproj"]]
và bất cứ khi nào bạn cần một chuỗi sử dụng cục bộ:
NSLocalizedStringFromTableInBundle(@"GalleryTitleKey", nil, currentLanguageBundle, @"")
Để đặt ngôn ngữ, hãy sử dụng:
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:@"de"] forKey:@"AppleLanguages"];
Hoạt động ngay cả với việc nhảy ngôn ngữ liên tiếp như:
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, @""));
Như đã nói trước đó, chỉ cần làm:
[[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObjects:@"el", nil] forKey:@"AppleLanguages"];
Nhưng để tránh phải khởi động lại ứng dụng, hãy đặt dòng này vào phương thức chính main.m
, ngay trước đó UIApplicationMain
(...).
NSAutoreleasePool * pool ..
hoặc một vài đối tượng tự động sẽ bị rò rỉ.
[[NSBundle mainBundle] URLForResource:withExtension:]
trước.
Mẹo để sử dụng ngôn ngữ cụ thể bằng cách chọn nó từ ứng dụng là buộc NSLocalizedString
sử dụng gói cụ thể tùy thuộc vào ngôn ngữ đã chọn,
đây là bài viết tôi đã viết cho việc học nội địa hóa nâng cao này trong các ứng dụng ios
và đây là mã của một bản địa hóa ứng dụng mẫu trong ứng dụng ios
Bạn nghĩ gì về giải pháp này cho 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)
}
}
Cách sử dụng đơn giản:
"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.
Như Brian Webster đã đề cập, ngôn ngữ cần được đặt "đôi khi sớm trong quá trình khởi động ứng dụng của bạn". Tôi nghĩ applicationDidFinishLaunching:
trong những AppDelegate
phải là một nơi thích hợp để làm điều đó, vì nó là nơi tôi làm tất cả khởi khác.
Nhưng như William Denniss đề cập, điều đó dường như chỉ có tác dụng sau khi ứng dụng được khởi động lại, điều này là vô ích.
Nó dường như hoạt động tốt nếu tôi đặt mã vào hàm chính:
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;
}
Tôi đánh giá cao bất kỳ ý kiến về điều này.
[[NSUserDefaults standardUserDefaults] synchronize];
sau khi gọisetObject:forKey:
Tôi thích phương pháp tốt nhất của Mauro Delrio. Tôi cũng đã thêm các mục sau trong Project_Prefix.pch của mình
#import "Language.h"
#define MyLocalizedString(key, alt) [Language get:key alter:alt]
Vì vậy, nếu bạn muốn sử dụng phương thức chuẩn (sử dụng NSLocalizedString), bạn có thể thực hiện thay thế cú pháp nhanh trong tất cả các tệp.
NSLocalizedString()
đọc giá trị của khóa AppleLanguages
từ mặc định của người dùng chuẩn ( [NSUserDefaults standardUserDefaults]
). Nó sử dụng giá trị đó để chọn một bản địa hóa phù hợp trong số tất cả các bản địa hóa hiện có trong thời gian chạy. Khi Apple xây dựng từ điển mặc định của người dùng khi khởi chạy ứng dụng, họ sẽ tra cứu (các) ngôn ngữ ưa thích trong tùy chọn hệ thống và sao chép giá trị từ đó. Điều này cũng giải thích ví dụ tại sao việc thay đổi cài đặt ngôn ngữ trong OS X không có tác dụng đối với các ứng dụng đang chạy, chỉ trên các ứng dụng bắt đầu sau đó. Sau khi sao chép, giá trị không được cập nhật chỉ vì cài đặt thay đổi. Đó là lý do iOS khởi động lại tất cả các ứng dụng nếu bạn thay đổi ngôn ngữ.
Tuy nhiên, tất cả các giá trị của từ điển mặc định của người dùng có thể được ghi đè bằng các đối số dòng lệnh. Xem NSUserDefaults
tài liệu trên NSArgumentDomain
. Điều này thậm chí bao gồm những giá trị được tải từ tệp tùy chọn ứng dụng (.plist). Điều này thực sự tốt để biết nếu bạn muốn thay đổi một giá trị chỉ một lần để thử nghiệm .
Vì vậy, nếu bạn muốn thay đổi ngôn ngữ chỉ để thử nghiệm, có lẽ bạn không muốn thay đổi mã của mình (nếu bạn quên xóa mã này sau ...), thay vào đó hãy nói với Xcode để khởi động ứng dụng của bạn bằng tham số dòng lệnh ( ví dụ: sử dụng bản địa hóa tiếng Tây Ban Nha):
Không cần phải chạm vào mã của bạn cả. Chỉ cần tạo các lược đồ khác nhau cho các ngôn ngữ khác nhau và bạn có thể nhanh chóng khởi động ứng dụng một lần bằng một ngôn ngữ và một lần bằng ngôn ngữ khác bằng cách chuyển đổi lược đồ.
Options
như với các phiên bản Xcode mới hơn mà Apple cung cấp cũng.
Tôi đã đưa ra một giải pháp cho phép bạn sử dụng NSLocalizedString
. Tôi tạo một thể loại của NSBundle
cuộc gọi NSBundle+RunTimeLanguage
. Giao diện là như thế này.
// 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
Việc thực hiện là như thế này.
// 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
Hơn chỉ cần thêm nhập NSBundle+RunTimeLanguage.h
vào các tập tin sử dụng NSLocalizedString
.
Như bạn có thể thấy tôi lưu trữ mã ngôn ngữ của mình trong một thuộc tính của AppDelegate
. Điều này có thể được lưu trữ bất cứ nơi nào bạn muốn.
Điều duy nhất tôi không thích về nó là một Cảnh báo mà NSLocalizedString
marco đã định nghĩa lại. Có lẽ ai đó có thể giúp tôi sửa phần này.
#undef NSLocalizedString
ngay trước #define
để vô hiệu hóa cảnh báo
Đó là điều đầu tiên bạn phải làm là bản địa hóa ứng dụng của bạn với ít nhất hai ngôn ngữ (tiếng Anh và tiếng Pháp trong ví dụ này).
Trong mã của bạn, thay vì sử dụng NSLocalizedString(key, comment)
, hãy sử dụng macro MYLocalizedString(key, comment)
được xác định như sau:
#define MYLocalizedString(key, comment) [[MYLocalizationSystem sharedInstance] localizedStringForKey:(key) value:(comment)];
Người MYLocalizationSystem
độc thân này sẽ:
Khi người dùng thay đổi ngôn ngữ ứng dụng bằng tiếng Pháp, hãy gọi [[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];
}
Trong ví dụ này, phương thức này đặt gói cục bộ thành fr.lproj
Khi bạn đã đặt gói được bản địa hóa, bạn sẽ có thể nhận được chuỗi địa phương hóa chính xác từ anh ấy bằng phương pháp này:
- (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];
}
Hy vọng điều này sẽ giúp bạn.
Bạn sẽ tìm thấy nhiều thông tin chi tiết hơn trong bài viết này từ NSWeries.io
Tiện ích mở rộng 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
}
}
Sử dụng:
Locale.preferredLanguage = "uk"
label.text = "localizedKey".localized
Trong tệp .pch để xác định:
#define currentLanguageBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[[NSLocale preferredLanguages] objectAtIndex:0] ofType:@"lproj"]]
#define NSLocalizedString(str,nil) NSLocalizedStringFromTableInBundle(str, nil, currentLanguageBundle, @"")
Có lẽ bạn nên bổ sung với điều này (trên tệp .pch sau #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]
Giải pháp 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")
Đã cho một số ví dụ về mã ngôn ngữ có thể được sử dụng. Hi vọng điêu nay co ich
Bạn có thể xây dựng một gói phụ với tập hợp các chuỗi được bản địa hóa mà bạn muốn thực hiện điều này với, sau đó sử dụng NSLocalizedStringFromTableInBundle()
để tải chúng. (Tôi cho rằng đây là nội dung tách biệt với nội địa hóa UI thông thường mà bạn có thể đang thực hiện trên ứng dụng.)
đối với trường hợp của tôi, tôi có hai tệp cục bộ, ja và en
và tôi muốn buộc nó thành en nếu ngôn ngữ ưa thích trong hệ thống không en hoặc ja
Tôi sẽ chỉnh sửa tập tin main.m
Tôi sẽ kiểm tra xem ưu tiên thứ nhất là en hay ja, nếu không thì tôi sẽ thay đổi ngôn ngữ ưa thích thứ hai thành 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]));
}
}
Bạn có thể làm một cái gì đó như thế này:
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"Localizable" ofType:@"strings" inDirectory:nil forLocalization:@"es"];
NSBundle *spanishBundle = [[NSBundle alloc] initWithPath:[bundlePath stringByDeletingLastPathComponent]];
NSLocalizedStringFromTableInBundle(@"House", nil, spanishBundle, nil):
Dựa trên câu trả lời của Tudorizer để thay đổi ngôn ngữ mà không cần rời khỏi hoặc khởi động lại ứng dụng.
Thay vì macro, sử dụng một lớp để truy cập ngôn ngữ ưa thích để kiểm tra xem có mã ngôn ngữ cụ thể không.
Dưới đây là một lớp được sử dụng để có được gói ngôn ngữ hiện tại đang hoạt động cho 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
Sử dụng lớp ở trên để tham chiếu tệp chuỗi / hình ảnh / video / vv:
// 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")
Thay đổi ngôn ngữ nội tuyến như bên dưới hoặc cập nhật phương thức "changeCiverseL Language" trong lớp ở trên để lấy tham số chuỗi tham chiếu ngôn ngữ mới.
[[NSUserDefaults standardUserDefaults] setObject:@[@"es"] forKey:@"AppleLanguages"];
Trong swift 4, tôi đã giải quyết nó mà không cần phải khởi động lại hoặc sử dụng các thư viện.
Sau khi thử nhiều tùy chọn, tôi đã tìm thấy hàm này, nơi bạn truyền chuỗi StringToLocalize (của Localizable.String, tệp chuỗi) mà bạn muốn dịch và ngôn ngữ mà bạn muốn dịch và giá trị mà nó trả về là giá trị cho Chuỗi mà bạn có trong tệp Chuỗi:
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)
}
Có tính đến chức năng này, tôi đã tạo chức năng này trong tệp 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!)!
}
}
Để truy cập từ toàn bộ ứng dụng và trong từng chuỗi của phần còn lại của ViewControllers, thay vì đặt:
NSLocalizedString ("StringToLocalize", comment: “")
Tôi đã thay thế nó bằng
let customLang = CustomLanguage() //declare at top
let bundleLanguage = customLang.createBundle()
NSLocalizedString("StringToLocalize", tableName: nil, bundle: bundleLanguage, value: "", comment: “”) //use in each String
Tôi không biết đó có phải là cách tốt nhất không, nhưng tôi thấy nó rất đơn giản và nó hiệu quả với tôi, tôi hy vọng nó sẽ giúp bạn!
Hàm này sẽ cố gắng lấy chuỗi địa phương hóa cho ngôn ngữ hiện tại và nếu không tìm thấy, nó sẽ lấy chuỗi đó bằng ngôn ngữ tiếng Anh.
- (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;
}
Tôi muốn thêm hỗ trợ cho một ngôn ngữ không được iOS hỗ trợ chính thức (không được liệt kê trong phần Ngôn ngữ trong cài đặt hệ thống). Bằng cách làm theo Hướng dẫn quốc tế hóa của Apple và một vài gợi ý ở đây của Brian Webster và geon, tôi đã đưa ra đoạn mã này (đặt nó vào 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]));
}
}
Điều này hoạt động tốt cho cả mã Storyboard và NSLocalizedString. Mã này giả định rằng người dùng sẽ có tùy chọn thay đổi ngôn ngữ bên trong ứng dụng theo cách thủ công sau này.
Tất nhiên, đừng quên thêm các bản dịch Storyboard và bản dịch Localizable.strings thích hợp (xem liên kết đến trang Apple ở trên để biết cách làm điều đó).
Đây là một giải pháp tốt cho vấn đề này và nó không yêu cầu khởi động lại ứng dụng.
https://github.com/cmaftuleac/BundleLocalization
Việc thực hiện này hoạt động bằng cách điều chỉnh bên trong NSBundle. Ý tưởng là bạn ghi đè phương thức localizedStringForKey trên thể hiện của đối tượng NSBundle, sau đó gọi phương thức này trên một gói khác với một ngôn ngữ khác. Đơn giản và thanh lịch hoàn toàn tương thích với tất cả các loại tài nguyên.
NSString *path = [[NSBundle mainBundle] pathForResource:lang ofType:@"lproj" ];
bất cứ điều gì bạn làm, cách tốt nhất là lấy short_name cho ngôn ngữ đã chỉ định, ví dụ: fr, en, nl, de, it, v.v ... và gán cùng một giá trị toàn cầu.
tạo chế độ xem bộ chọn để bật lên như trình đơn thả xuống (kết hợp một nút khi nhấp vào chế độ xem bộ chọn xuất hiện từ bên dưới với danh sách các ngôn ngữ) và chọn ngôn ngữ bạn muốn. hãy để tên ngắn được lưu trữ nội bộ tạo một tệp .h + .m có tên LocalisedString.
Đặt giá trị toàn cầu của short_name bằng với giá trị thu được trong LocalisedString.m Khi ngôn ngữ được yêu cầu được chọn, gán NSBundlePath để tạo thư mục con dự án cho ngôn ngữ cần thiết. ví dụ: nl.proj, en.proj.
Khi thư mục proj cụ thể được chọn, hãy gọi chuỗi cục bộ cho ngôn ngữ tương ứng và thay đổi ngôn ngữ một cách linh hoạt.
không có quy tắc bị phá vỡ.
Đối với Swift, bạn có thể ghi đè main.swift
tệp và đặt chuỗi UserDefaults ở đó trước khi ứng dụng chạy. Bằng cách này, bạn không phải khởi động lại Ứng dụng để thấy hiệu quả mong muốn.
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))
kết hợp với việc loại bỏ @UIApplicationMain
trong AppDelegate.swift
tập tin của bạn .