为什么我的iOS应用程序仅在首次运行时正确检测当前语言?

时间:2012-11-27 07:52:46

标签: ios xcode4 localization

我正在本地化我的iOS应用程序,并且在模拟器中,它每次都以我选择的语言正确运行。

在我的iPhone 5上进行测试时,它只会在应用首次运行时正确检测语言。每次我在设备上重新编译并运行我的应用程序时,它会检测到“en”作为语言,即使我选择了Español(“es”)进行测试。

我使用以下方法检测语言:

[[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0]

我也用过:

[[NSLocale preferredLanguages] objectAtIndex:0]

同样的结果。

如果我在第一次运行后终止应用程序,并在设备上重新启动它,它会继续正确检测语言。

但是如果我杀了应用程序然后在初始运行后通过Xcode重新编译/重新启动,它将加载“en”(英语)而不是。

之后,杀死并重新启动应用程序会持续检测为英语,除非我完全删除该应用程序,并通过Xcode重新编译/重新安装/运行该应用程序。然后循环重复......后续重建/重启而不首先从设备中删除应用程序会导致误检测。

我的设备上的所有其他应用程序一直显示西班牙语。整个用户界面以西班牙语显示。

更新:我现在已经在运行iOS 6的iPad(第3代)上进行了测试,并且遇到了相同的行为。

更新2:

在didFinishLaunchingWithOptions中,我有这段代码来检测语言:(语言是NSString *):

language = [[NSLocale preferredLanguages] objectAtIndex:0];

接下来是这个调试语句,比较我得到的值,以及稍微不同的检测方法,仅用于调试:

NSLog(@"Detected language: %@ / %@", language, [[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0]);

当应用程序在西班牙语模式下正常工作时,输出显示为“检测到的语言:es / es”,然后在不显示时显示为“检测到的语言:en / en”。仍然不知道为什么它决定有时加载英语...

更新4:我感谢大家的回答,并尝试了各种建议。不幸的是,我无法授予 +100赏金,因为这些建议似乎没有解决问题。如果有人确实找到了适用于我的解决方案,那么我当时会给予他们额外的+50赏金。

更新5:我已从Xcode 4.5更新到4.5.2,并遇到同样的问题。

更新6:我现在已经从头开始创建了一个新的测试项目,它运行得非常好!显然,我的项目布局方式或者可能是其中一个数据文件中的某些内容必定是错误的。我想我的下一个旅程将是从头开始重新创建项目,逐个复制文件数据......

更新7(稍后):可悲的是,在通过精心重建我的项目暂时解决它(看似)后,我再次面临这个问题。在第一次加载时,语言被正确呈现,但在后续加载时,它将恢复为英语。

已解决请参阅我的最终解决方案below。感谢大家的帮助。我可能会拿出一些赏金,因为无论如何它都会浪费掉。

5 个答案:

答案 0 :(得分:8)

几个月后我终于彻底解决了这个问题!感谢所有人的帮助(我也通过开发渠道与Apple开发人员进行了一些良好的反复)。

TL; DR:我使用我的应用程序的iCloud密钥值存储(通过MKiCloudSync)意外地在设备之间同步语言首选项(以及许多其他意想不到的事情)!请继续阅读...

我正在使用名为MKiCloudSync的第三方类,它有助于将[NSUserDefaults standardUserDefaults]同步到我应用的iCloud密钥值存储区。我开始使用它的目的是让它在后台处理一些用户收藏夹同步。

但是,不了解standardUserDefaults的工作方式,我没有意识到除了我自己的自定义应用设置外,还有很多其他内容写入standardUserDefaults

所以发生了什么事:

  1. 首次启动应用。新的standardUserDefaults到位,以及存储有序语言首选项列表的内部“AppleLanguages”键根据当前设备选择是正确的。

  2. 应用程序以指定语言正确显示。

  3. 在后台,MKiCloudSync将所有standardUserDefaults同步到iCloud。相反,如果您在其他地方运行此应用程序,例如使用英语设置设备,该设备也会将其语言设置同步到iCloud。所以现在这个当前运行的应用程序实际上已经覆盖了它的语言首选项。

  4. BOOM ......下次运行应用程序时,无论您在设备上选择了什么,都是从iCloud中下载的任何内容都将用作默认语言!

  5. 我计划通过下一次应用更新来解决问题:

    1. 使用仅允许同步列入白名单的密钥名称的forked version of MKiCloudSync

    2. 添加将进行一次性清理的代码,首先清理我的应用程序的iCloud密钥库,然后(based on this SO answer),调用此代码重置用户默认值:

      NSString * appDomain = [[NSBundle mainBundle] bundleIdentifier]; [[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];

    3. 在我的测试中,到目前为止,这种解决了这个问题...不幸的是,用户必须重新启动应用程序以启动语言修复。但是,我的猜测是大多数用户没有遇到此问题,因为他们不太可能使用具有不同默认语言的多个设备。

答案 1 :(得分:3)

在settings-> general-> international中,如果您将其设置为您要测试的语言,则可以选择设置位置语言等。如果您的代码正确,它将会起作用。

答案 2 :(得分:2)

我在iPhone 5上测试了你的步骤没有问题。这让我觉得这里还有其他的东西在起作用:最有可能的是干扰你读取语言环境价值的方式。

我建议您采取的步骤来帮助您调试此问题:

  1. 发布您获取首选语言值的方法的完整代码。确保每次运行应用程序时都执行该方法。
  2. 确保您发布的代码包含您用于测试语言设置的NSLog指令的位置。
  3. 您是否在首次运行后将首选语言存储在其他位置?

答案 3 :(得分:2)

尝试使用以下代码:

LocalizationSystem.h ===

#import <Foundation/Foundation.h>

#define AMLocalizedString(key, comment) \
[[LocalizationSystem sharedLocalSystem] localizedStringForKey:(key) value:(comment)]

#define LocalizationSetLanguage(language) \
[[LocalizationSystem sharedLocalSystem] setLanguage:(language)]

#define LocalizationGetLanguage \
[[LocalizationSystem sharedLocalSystem] getLanguage]

#define LocalizationReset \
[[LocalizationSystem sharedLocalSystem] resetLocalization]

@interface LocalizationSystem : NSObject {
    NSString *language;
}


+ (LocalizationSystem *)sharedLocalSystem;

//gets the string localized
- (NSString *)localizedStringForKey:(NSString *)key value:(NSString *)comment;

//sets the language
- (void) setLanguage:(NSString*) language;

//gets the current language
- (NSString*) getLanguage;

//resets this system.
- (void) resetLocalization;

@end

LocalizationSystem.m ===

#import "LocalizationSystem.h"

@implementation LocalizationSystem

//Singleton instance
static LocalizationSystem *_sharedLocalSystem = nil;

//Current application bundle to get the languages.
static NSBundle *bundle = nil;

+ (LocalizationSystem *)sharedLocalSystem{
    @synchronized([LocalizationSystem class])
    {
        if (!_sharedLocalSystem){
            [[self alloc] init];
        }
        return _sharedLocalSystem;
    }
    // to avoid compiler warning
    return nil;
}

+(id)alloc{
    @synchronized([LocalizationSystem class])
    {
        NSAssert(_sharedLocalSystem == nil, @"Attempted to allocate a second instance of a singleton.");
        _sharedLocalSystem = [super alloc];
        return _sharedLocalSystem;
    }
    // to avoid compiler warning
    return nil;
}

- (id)init{
    if ((self = [super init])) 
    {
        //empty.
        bundle = [NSBundle mainBundle];
    }
    return self;
}

// Gets the current localized string as in NSLocalizedString.

- (NSString *)localizedStringForKey:(NSString *)key value:(NSString *)comment{
    return [bundle localizedStringForKey:key value:comment table:nil];
}

// If this function is not called it will use the default OS language.
// If the language does not exists y returns the default OS language.
- (void) setLanguage:(NSString*) l{
    NSLog(@"preferredLang: %@", l);

    NSString *path = [[ NSBundle mainBundle ] pathForResource:l ofType:@"lproj" ];


    if (path == nil)
        //in case the language does not exists
        [self resetLocalization];
    else
        bundle = [[NSBundle bundleWithPath:path] retain];

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

// Just gets the current setted up language.
// returns "es","fr",...
//
// example call:
// NSString * currentL = LocalizationGetLanguage;
- (NSString*) getLanguage{

    NSArray* languages = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleLanguages"];

    NSString *preferredLang = [languages objectAtIndex:0];

    return preferredLang;
}

// Resets the localization system, so it uses the OS default language.
//
// example call:
// LocalizationReset;
- (void) resetLocalization{
    bundle = [NSBundle mainBundle];
}


@end

如您所述,此代码完美无缺。 如果你想检查(HueShapes),它对我有用,那个游戏现在是实时应用商店。

答案 4 :(得分:0)

您是否偶然使用NSUserDefaults保存与语言相关的内容?

查看您的Simulator App目录 - &gt;图书馆 - &gt;偏好 - &gt; <YourAppBundleName>.plist

有关设置语言的NSUserDefaults方法的说明,请参阅:How to force NSLocalizedString to use a specific language

也许你只是保存你的语言,因此检测只返回保存的值。