在iPhone上NSLocalizedString返回iPhone语言的字符串。 是否有可能强制NSLocalizedString使用特定语言来拥有应用程序 用不同的语言吗?
当前回答
我想添加对iOS官方不支持的语言的支持(未在系统设置下的语言部分列出)。通过遵循苹果的国际化教程和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代码。该代码假设用户将有一个选项,手动更改应用程序内的语言稍后。
当然,不要忘记添加适当的故事板翻译和本地化。字符串翻译(见链接到上面的苹果页面如何做到这一点)。
其他回答
我最近也遇到了同样的问题,我不想启动和修补我的整个NSLocalizedString,也不想强迫应用程序重新启动新的语言工作。我希望一切都能按原样工作。
我的解决方案是动态地改变主bundle的类,并在那里加载适当的bundle:
头文件
@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"];
要重置回系统默认值,只需传入nil:
[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)
}
}
这个函数将尝试获取当前语言的本地化字符串,如果没有找到,它将使用英语语言获取它。
- (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;
}
简而言之:
本地化应用程序
你要做的第一件事就是用至少两种语言(本例中是英语和法语)来本地化你的应用程序。
覆盖NSLocalizedString
在你的代码中,不是使用NSLocalizedString(key, comment),而是使用一个宏MYLocalizedString(key, comment),定义如下: #定义MYLocalizedString(key, comment) [[MYLocalizationSystem sharedInstance] localizedStringForKey:(key) value:(comment)];
这个MYLocalizationSystem单例将:
通过设置正确的本地化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];
}
在这个例子中,这个方法将本地化的bundle设置为fr.lproj
返回本地化字符串
一旦你设置了本地化的bundle,你就可以通过下面的方法从他那里得到正确的本地化字符串:
- (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的这篇文章中找到更多详细信息
你可以这样做:
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"Localizable" ofType:@"strings" inDirectory:nil forLocalization:@"es"];
NSBundle *spanishBundle = [[NSBundle alloc] initWithPath:[bundlePath stringByDeletingLastPathComponent]];
NSLocalizedStringFromTableInBundle(@"House", nil, spanishBundle, nil):
正如Brian Webster提到的,语言需要在“应用程序启动初期的某个时候”设置。我认为AppDelegate的applicationDidFinishLaunching:应该是一个合适的地方来做它,因为它是我做所有其他初始化的地方。
但正如威廉·丹尼斯提到的,这似乎只有在应用程序重新启动后才会起作用,这有点没用。
不过,如果我把代码放在main函数中,它似乎工作得很好:
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;
}
如果有任何评论,我将不胜感激。
推荐文章
- 如何删除默认的导航栏空间在SwiftUI导航视图
- 为什么Chrome浏览器不正确地确定页面是在不同的语言,并提供翻译?
- 如何在iOS中使用Swift编程segue
- Swift -整数转换为小时/分钟/秒
- Swift:声明一个空字典
- 为什么ARC仍然需要@autoreleasepool ?
- 在成功提交我的应用程序后,“太多符号文件”
- 首先添加一个UIView,甚至是导航栏
- 我如何改变UIButton标题颜色?
- 在Swift中如何调用GCD主线程上的参数方法?
- NSLayoutConstraints是可动画的吗?
- iOS -构建失败,CocoaPods无法找到头文件
- Xcode 4挂在“附加到(应用程序名称)”
- CFNetwork SSLHandshake iOS 9失败
- 请求失败:不可接受的内容类型:文本/html使用AFNetworking 2.0