Почему приложение iOS только правильно определяет текущий язык при первом запуске?
Я локализую свое приложение iOS, и в Симуляторе он работает правильно на моем выбранном языке каждый раз.
При тестировании на моем iPhone 5 он только правильно определяет язык при первом запуске приложения. Каждый раз, когда я перекомпилирую и запускаю свое приложение на устройстве, он обнаруживает "en" в качестве языка, хотя я тестирую с выбранным вами "Español".
Я определяю язык, используя:
[[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0]
Я также использовал:
[[NSLocale preferredLanguages] objectAtIndex:0]
Тот же результат.
Если я убил приложение после первого запуска и перезапустил его на устройстве, он продолжает правильно распознавать язык.
Но если я убью приложение, а затем перекомпилирую/перезапустим через Xcode после первого запуска, он будет загружаться с помощью "en" (англ.), обнаруженного вместо этого.
После этого убийство и повторное начало приложения постоянно обнаруживаются как английский, если я полностью не удалю приложение и не перекомпилирую/не переустановить/запустить приложение с помощью Xcode. Затем цикл повторяется... последующая перестройка/перезапуск без предварительного удаления приложения из устройства приводит к неправильному определению.
Все остальные приложения на моем устройстве отображаются на испанском языке все время. Весь пользовательский интерфейс отображается на испанском языке.
ОБНОВЛЕНИЕ: Я тестировал на своем iPad (3rd gen), также работающем на iOS 6, и испытываю то же поведение.
ОБНОВЛЕНИЕ 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 (МЕСЯЦЫ ПОЗЖЕ): К сожалению, я снова столкнулся с этой проблемой после временного ее разрешения (по-видимому) путем тщательного воссоздания моего проекта. При первой загрузке язык правильно отображается, но при последующих нагрузках он возвращается на английский.
SOLVED Посмотрите мое окончательное решение ниже. Спасибо всем за помощь. Я могу получить часть щедрости, так как она все равно пропадет.
Ответы
Ответ 1
Я НАСТОЯЩИМ решил эту проблему через много месяцев! Спасибо всем за помощь (у меня также было неплохо взад и вперед с разработчиком Apple через dev-каналы).
TL; DR: Я случайно менял языковые предпочтения (среди многих других неожиданных вещей) между устройствами, используя мое хранилище ключей iCloud моего приложения (через MKiCloudSync)! Читайте дальше...
Я использую сторонний класс под названием MKiCloudSync, который помогает синхронизировать [NSUserDefaults standardUserDefaults]
с моим хранилищем значений ключа iCloud. Мое намерение, когда я начал использовать его, было позволить ему обрабатывать некоторые пользовательские фавориты, синхронизирующиеся в фоновом режиме.
Однако, не понимая, как работает standardUserDefaults
, я не понял, что в standardUserDefaults
есть еще много других вещей, кроме только моих собственных настроек приложения!
Итак, что произошло, это:
-
Запустите приложение в первый раз. Свежий standardUserDefaults
на месте, а внутренний ключ "AppleLanguages", который хранит упорядоченный список языковых настроек, корректен на основе текущих вариантов устройства.
-
Приложение отображается правильно на указанном языке.
-
В фоновом режиме MKiCloudSync синхронизирует ALL standardUserDefaults
с iCloud. И наоборот, если вы запустили это приложение в другом месте, скажем, с помощью английского набора устройств, это устройство также синхронизировало бы его настройки языка до iCloud. Итак, теперь это текущее приложение на самом деле переписывает языковые настройки.
-
BOOM... в следующий раз, когда приложение будет запущено, независимо от того, что вы выбрали на устройстве, все, что было снято с iCloud, которое будет использоваться в качестве языка по умолчанию!
Что я планирую сделать для решения проблемы с моим следующим обновлением приложения:
-
Используйте разветвленную версию MKiCloudSync, которая позволяет синхронизировать только имена белых списков.
-
Добавьте код, который будет выполнять одноразовую очистку, сначала очистив хранилище iCloud для моего приложения, затем (на основе этого SO-ответа) вызывая этот код до reset по умолчанию пользователя:
NSString * appDomain = [[NSBundle mainBundle] bundleIdentifier];
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName: appDomain];
В моем тестировании до сих пор этот вид решает проблему... к сожалению, пользователю придется перезапустить приложение для исправления языка, чтобы использовать его. Однако, по моему мнению, большинство пользователей не испытывают этой проблемы, поскольку они вряд ли будут использовать несколько устройств с разными языками по умолчанию.
Ответ 2
В настройках- > general- > international есть возможность указать язык местоположения и т.д., если вы установите его на язык, который вы пытаетесь проверить, он будет работать, если ваш код верен.
Ответ 3
Я протестировал ваши шаги на своем iPhone 5 без проблем. Это заставляет меня думать, что здесь есть что-то другое: скорее всего, там что-то мешает тому, как вы читаете значение локали.
Действия, которые я рекомендую вам предпринять, чтобы помочь вам отладить эту проблему:
- Вывести полный код метода, в котором вы получаете предпочтительное значение языка. Убедитесь, что метод выполняется каждый раз, когда приложение запускается.
- Убедитесь, что введенный вами код содержит расположение директивы NSLog, которое вы используете, для проверки языка.
- Сохраняете ли вы предпочтительный язык где-то еще после первого запуска?
Ответ 4
Попробуйте со следующим кодом:
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).
Ответ 5
Вы случайно используете NSUserDefaults для сохранения связанного языка?
Посмотрите на каталог своего приложения Simulator → Library → Настройки → <YourAppBundleName>.plist
Смотрите: Как заставить NSLocalizedString использовать определенный язык для описания метода NSUserDefaults для установки языка.
Возможно, вы просто сохранили свой язык, и поэтому обнаружение просто возвращает сохраненное значение.