当我在设备语言中单独更改应用程序使用的语言时,在我关闭应用程序并重新启动它之前它不会生效。如何根据所选语言不再要求重新启动应用程序以再次加载所有nib文件和.strings文件?
我用它来改变运行时的语言:
NSArray* languages = [NSArray arrayWithObjects:@"ar", @"en", nil];
[[NSUserDefaults standardUserDefaults] setObject:languages forKey:@"AppleLanguages"];
答案 0 :(得分:11)
我对带有标签式导航的Kiosk模式iPad应用程序有类似的要求。该应用程序不仅需要支持即时语言更改,而且还必须知道大多数选项卡已经从笔尖加载,因为应用程序仅在每周一次重新启动(平均)时大约一次版本已加载。
我尝试了几个建议来利用现有的Apple本地化机制,它们都有严重的缺点,包括XCode 4.2对本地化nib的支持 - 我的IBoutlet连接变量似乎在IB中正确设置,但在运行时它们会经常是空的!?
我最终实现了一个模仿Apple NSLocalizedString类但可以处理运行时更改的类,每当用户进行语言更改时,我的类都会发布通知。需要本地化字符串(和图像)更改的屏幕声明了一个handleLocaleChange方法,该方法在viewDidLoad中调用,并且每当发布LocaleChangedNotification时。
我的所有按钮和图形都设计为与语言无关,但标题文本和标签文本通常会根据区域设置更改进行更新。如果我必须更改图像,我可以在每个屏幕的handleLocaleChange方法中完成,我想。
这是代码。它包括对nib / bundle路径的一些支持,我实际上并没有在最终项目中使用它。
MyLanguage.h // // MyLanguage.h // //
#import <Foundation/Foundation.h>
#define DEFAULT_DICTIONARY_FOR_STRINGS @""
#define ACCESSING_ALTERNATE_DICTIONARY_SETS_DEFAULT 1
#define LANGUAGE_ENGLISH_INT 0
#define LANGUAGE_SPANISH_INT 1
#define LANGUAGE_ENGLISH_SHORT_ID @"en"
#define LANGUAGE_SPANISH_SHORT_ID @"es"
#define LANGUAGE_CHANGED_NOTIFICATION @"LANGUAGE_CHANGED"
@interface MyLanguage : NSObject
{
NSString *currentLanguage;
NSDictionary *currentDictionary;
NSBundle *currentLanguageBundle;
}
+(void) setLanguage:(NSString *)languageName;
+(NSString *)stringFor:(NSString *)srcString forLanguage:(NSString *)languageName;
+(NSString *)stringFor:(NSString *)srcString;
+ (MyLanguage *)singleton;
@property (nonatomic, retain) NSBundle *currentLanguageBundle;
@property (nonatomic, retain) NSString *currentLanguage;
@property (nonatomic, retain) NSDictionary *currentDictionary;
@end
MyLanguage.m: // // MyLanguage.m
#import "MyLanguage.h"
#import "Valet.h"
#define GUI_STRING_FILE_POSTFIX @"GUIStrings.plist"
@implementation MyLanguage
@synthesize currentLanguage;
@synthesize currentDictionary;
@synthesize currentLanguageBundle;
+(NSDictionary *)getDictionaryNamed:(NSString *)languageName
{
NSDictionary *results = nil;
// for now, we store dictionaries in a PLIST with the same name.
NSString *dictionaryPlistFile = [languageName stringByAppendingString:GUI_STRING_FILE_POSTFIX];
NSString *plistBundlePath = [Valet getBundlePathForFileName:dictionaryPlistFile];
if ( [[NSFileManager defaultManager] fileExistsAtPath:plistBundlePath] )
{
// read it into a dictionary
NSDictionary *newDict = [NSDictionary dictionaryWithContentsOfFile:plistBundlePath];
results = [newDict valueForKey:@"languageDictionary"];
}// end if
return results;
}
+(NSString *)stringFor:(NSString *)srcString forDictionary:(NSString *)languageName;
{
MyLanguage *gsObject = [MyLanguage singleton];
// if default dictionary matches the requested one, use it.
if ([gsObject.currentLanguage isEqualToString:languageName])
{
// use default
return [MyLanguage stringFor:srcString];
}// end if
else
{
// get the desired dictionary
NSDictionary *newDict = [MyLanguage getDictionaryNamed:languageName];
// default is not desired!
if (ACCESSING_ALTERNATE_DICTIONARY_SETS_DEFAULT)
{
gsObject.currentDictionary = newDict;
gsObject.currentLanguage = languageName;
return [MyLanguage stringFor:srcString];
}// end if
else
{
// use current dictionary for translation.
NSString *results = [gsObject.currentDictionary valueForKey:srcString];
if (results == nil)
{
return srcString;
}// end if
return results;
}
}
}
+(void) setLanguage:(NSString *)languageName;
{
MyLanguage *gsObject = [MyLanguage singleton];
// for now, we store dictionaries in a PLIST with the same name.
// get the desired dictionary
NSDictionary *newDict = [MyLanguage getDictionaryNamed:languageName];
gsObject.currentDictionary = newDict;
gsObject.currentLanguage = languageName;
// now set up the bundle for nibs
NSString *shortLanguageIdentifier = @"en";
if ([languageName contains:@"spanish"] || [languageName contains:@"espanol"] || [languageName isEqualToString:LANGUAGE_SPANISH_SHORT_ID])
{
shortLanguageIdentifier = LANGUAGE_SPANISH_SHORT_ID;
}// end if
else
shortLanguageIdentifier = LANGUAGE_ENGLISH_SHORT_ID;
// NSArray *languages = [NSArray arrayWithObject:shortLanguageIdentifier];
// [[NSUserDefaults standardUserDefaults] setObject:languages forKey:@"AppleLanguages"];
//
NSString *path= [[NSBundle mainBundle] pathForResource:shortLanguageIdentifier ofType:@"lproj"];
NSBundle *languageBundle = [NSBundle bundleWithPath:path];
gsObject.currentLanguageBundle = languageBundle;
[[NSNotificationCenter defaultCenter] postNotificationName:LANGUAGE_CHANGED_NOTIFICATION object:nil];
}
+(NSString *)stringFor:(NSString *)srcString;
{
MyLanguage *gsObject = [MyLanguage singleton];
// default is to do nothing.
if (gsObject.currentDictionary == nil || gsObject.currentLanguage == nil || [gsObject.currentLanguage isEqualToString:DEFAULT_DICTIONARY_FOR_STRINGS] )
{
return srcString;
}// end if
// use current dictionary for translation.
NSString *results = [gsObject.currentDictionary valueForKey:srcString];
if (results == nil)
{
return srcString;
}// end if
return results;
}
#pragma mark -
#pragma mark Singleton methods
static MyLanguage *mySharedSingleton = nil;
-(void) lateInit;
{
}
// PUT THIS METHOD DECLARATION INTO THE HEADER
+ (MyLanguage *)singleton;
{
if (mySharedSingleton == nil) {
mySharedSingleton = [[super allocWithZone:NULL] init];
[mySharedSingleton lateInit];
}
return mySharedSingleton;
}
+ (id)allocWithZone:(NSZone *)zone
{ return [[self singleton] retain]; }
- (id)copyWithZone:(NSZone *)zone
{ return self; }
- (id)retain
{ return self; }
- (NSUInteger)retainCount //denotes an object that cannot be released
{ return NSUIntegerMax; }
- (oneway void)release //do nothing
{ }
- (id)autorelease
{ return self; }
@end
答案 1 :(得分:8)
只需使用此库, https://github.com/Baglan/MCLocalization 你可以随时轻松改变选定的语言:)
答案 2 :(得分:7)
不要依赖您在nib文件中设置的字符串。使用你的笔尖只用于布局&amp;设置视图。显示给用户的任何字符串(按钮文本等)都需要在Localizable.strings文件中,当您加载笔尖时,需要相应地在相应的视图/控件上设置文本。
获取当前语言的包:
NSString *path = [[NSBundle mainBundle] pathForResource:currentLanguage ofType:@"lproj"];
if (path) {
NSBundle *localeBundle = [NSBundle bundleWithPath:path];
}
使用bundle获取本地化字符串:
NSLocalizedStringFromTableInBundle(stringThatNeedsToBeLocalized, nil, localeBundle, nil);
同样对于日期格式化,您可能需要查看
[NSDateFormatter dateFormatFromTemplate:@"HH:mm:ss"" options:0 locale:locale];
要使用它,您需要为您希望使用的相应语言/国家/地区创建NSLocale。
答案 3 :(得分:5)
继承人我的所作所为。我想诀窍是使用NSLocalizedStringFromTableInBundle而不是NSLocalizedString。
对于所有字符串,请使用此
someLabel.text = NSLocalizedStringFromTableInBundle(@"Your String to be localized, %@",nil,self.localeBundle,@"some context for translators");
要更改语言,请运行此代码
NSString * language = @"zh-Hans"; //or whatever language you want
NSString *path = [[NSBundle mainBundle] pathForResource:language ofType:@"lproj"];
if (path) {
self.localeBundle = [NSBundle bundleWithPath:path];
}
else {
self.localeBundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"en" ofType:@"lproj"] ];
}
在此之后,您可能希望调用任何更新代码来将字符串更新为新语言,例如再次运行
someLabel.text = NSLocalizedStringFromTableInBundle(@"Your String to be localized, %@",nil,self.localeBundle,@"some context for translators");
多数民众赞成。无需重启应用。兼容系统设置(如果您通过iOS设置设置语言,它也会起作用)。不需要外部库。不需要越狱。它也适用于genstrings。
当然,您应该仍然按照惯例继续使用您的应用设置:
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"zh-Hans", nil] forKey:@"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize];
(并检查你的viewDidLoad或其他东西)
NSString * language = [[NSLocale preferredLanguages] objectAtIndex:0];
NSString *path = [[NSBundle mainBundle] pathForResource:language ofType:@"lproj"];
if (path) {
self.localeBundle = [NSBundle bundleWithPath:path];
}
else {
self.localeBundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"en" ofType:@"lproj"] ];
}
答案 4 :(得分:4)
这对我有用: 斯威夫特4:
创建一个名为BundleExtension.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)
}
}
现在,无论何时需要更改语言,都可以调用此方法:
func languageButtonAction() {
// This is done so that network calls now have the Accept-Language as "hi" (Using Alamofire) Check if you can remove these
UserDefaults.standard.set(["hi"], forKey: "AppleLanguages")
UserDefaults.standard.synchronize()
// Update the language by swaping bundle
Bundle.setLanguage("hi")
// Done to reintantiate the storyboards instantly
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
UIApplication.shared.keyWindow?.rootViewController = storyboard.instantiateInitialViewController()
}
答案 5 :(得分:2)
你应该创建一个类似于NSLocalizedString的自己的宏,但是根据你设置的NSUserDefaults值来选择一个字符串的束(即不要担心apple语言默认值的值是什么)
当您更改语言时,您应该发出通知,视图控制器,视图等应该监听并刷新自己