在 iOS 应用程序(iPhone 和 iPad)中手动选择语言

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9939885/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 17:38:04  来源:igfitidea点击:

manual language selection in an iOS-App (iPhone and iPad)

ioslocalizationselectionappsettings

提问by Hubert Sch?lnast

My question:

我的问题:

How can my iPhone-app tell the iOS, that the user did select a language in the apps preferences, that is different from the language set in the general settings?

我的 iPhone 应用程序如何告诉 iOS,用户确实在应用程序首选项中选择了一种与常规设置中设置的语言不同的语言?

Other formulation of the same question:

同一问题的其他表述:

How can i tell the system, that NSLocalizedString (@"text", @"comment");should not access the systemwide selected language, but the in-app-selected language?

我怎么能告诉系统,它NSLocalizedString (@"text", @"comment");不应该访问系统范围内选择的语言,而是应用程序内选择的语言?

background, example:

背景,例如:

Please take this situation as an example: A son of german immigrants is living in the north-east of France next to Luxemburg and Germany. His native language is French, so he did set the user-interfaces language of his iPhone to French (Settings -> General -> International -> Language -> Fran?ais). But due to his cultural background and because the region where he is living is bilingual, he also speaks German very well. But he doesn't speak ten words of English. On an iPhone (and iPad as well) he has no chance to select a second language, so the phone only knows that he spreaks french. It has no knowledge of the users skills in other languages.

请以这种情况为例:一个德国移民的儿子住在法国东北部,紧邻卢森堡和德国。他的母语是法语,因此他确实将 iPhone 的用户界面语言设置为法语(设置 -> 通用 -> 国际 -> 语言 -> Fran?ais)。但由于他的文化背景以及他所居住的地区是双语的,他的德语也说得很好。但他不会说十个英语单词。在iPhone(和iPad一样),他已经没有机会选择第二语言,因此手机只知道他spreaks法语。它不了解其他语言的用户技能。

Now comes my app: I did develop it in English and German (German is my native language and English is standard-language in IT). I did develop it according to all rules and best practices for mulilingual iOS-Apps. "First" Language (default language) of my app is English.

现在是我的应用程序:我确实用英语和德语开发了它(德语是我的母语,英语是 IT 的标准语言)。我确实根据多语言 iOS 应用程序的所有规则和最佳实践开发了它。我的应用程序的“第一”语言(默认语言)是英语。

This means:

这意味着:

If somebody has chosen English or German in his Settings, the apps user-interface automatically will use the selected language. The user will not even notice that there are other languages available.

如果有人在其设置中选择了英语或德语,则应用程序用户界面将自动使用所选语言。用户甚至不会注意到还有其他语言可用。

But if he did select any other language (like Chinese, Polish or French) in the general settings, he will get the apps default-language, which, in my case, is English. But for my french-german friend this is not the best choice. He would like to use the existing german version, but there seems to be no way to let the user select this version.

但是如果他在一般设置中选择了任何其他语言(如中文、波兰语或法语),他将获得应用程序的默认语言,在我的情况下,它是英语。但对于我的法德朋友来说,这不是最好的选择。他想使用现有的德语版本,但似乎没有办法让用户选择这个版本。

Adding a french translation would solve the problem for our french-german friend, but not for people speaking two other languages (such as italian and german), and I can not support my app with all languages spoken on this planet. Setting the default-language to German is also not optimal, because this would rise the same problem for people speaking french (an native language) and English (as second language).

添加法语翻译可以解决我们的法德朋友的问题,但不能解决说其他两种语言(例如意大利语和德语)的人的问题,而且我无法支持我的应用程序使用这个星球上使用的所有语言。将默认语言设置为德语也不是最佳选择,因为对于说法语(母语)和英语(作为第二语言)的人来说,这会引起同样的问题。

So I think my app must have the possibility to manually select a language that is different from the pre-selected language. Adding a language-selection to the apps settings-panel ist not the problem. But how can i tell the system, that NSLocalizedString (@"text", @"comment");should not access the systemwide selected language, but the in-app-selected language?

所以我认为我的应用程序必须有可能手动选择与预选语言不同的语言。向应用程序设置面板添加语言选择不是问题。但是我怎么能告诉系统,它NSLocalizedString (@"text", @"comment");不应该访问系统范围内选择的语言,而是应用程序内选择的语言?

回答by Hubert Sch?lnast

In the meantime I did find a solution for my problem on myself:

与此同时,我确实为自己的问题找到了解决方案:

I created a new class "LocalizeHelper":

我创建了一个新类“LocalizeHelper”:



Header LocalizeHelper.h

标题 LocalizeHelper.h

//LocalizeHelper.h

#import <Foundation/Foundation.h>

// some macros (optional, but makes life easy)

// Use "LocalizedString(key)" the same way you would use "NSLocalizedString(key,comment)"
#define LocalizedString(key) [[LocalizeHelper sharedLocalSystem] localizedStringForKey:(key)]

// "language" can be (for american english): "en", "en-US", "english". Analogous for other languages.
#define LocalizationSetLanguage(language) [[LocalizeHelper sharedLocalSystem] setLanguage:(language)]

@interface LocalizeHelper : NSObject

// a singleton:
+ (LocalizeHelper*) sharedLocalSystem;

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

//set a new language:
- (void) setLanguage:(NSString*) lang;              

@end


iMplementation LocalizeHelper.m

实施 LocalizeHelper.m

// LocalizeHelper.m
#import "LocalizeHelper.h"

// Singleton
static LocalizeHelper* SingleLocalSystem = nil;

// my Bundle (not the main bundle!)
static NSBundle* myBundle = nil;


@implementation LocalizeHelper


//-------------------------------------------------------------
// allways return the same singleton
//-------------------------------------------------------------
+ (LocalizeHelper*) sharedLocalSystem {
    // lazy instantiation
    if (SingleLocalSystem == nil) {
        SingleLocalSystem = [[LocalizeHelper alloc] init];
    }
    return SingleLocalSystem;
}


//-------------------------------------------------------------
// initiating
//-------------------------------------------------------------
- (id) init {
    self = [super init];
    if (self) {
        // use systems main bundle as default bundle
        myBundle = [NSBundle mainBundle];
    }
    return self;
}


//-------------------------------------------------------------
// translate a string
//-------------------------------------------------------------
// you can use this macro:
// LocalizedString(@"Text");
- (NSString*) localizedStringForKey:(NSString*) key {
    // this is almost exactly what is done when calling the macro NSLocalizedString(@"Text",@"comment")
    // the difference is: here we do not use the systems main bundle, but a bundle
    // we selected manually before (see "setLanguage")
    return [myBundle localizedStringForKey:key value:@"" table:nil];
}


//-------------------------------------------------------------
// set a new language
//-------------------------------------------------------------
// you can use this macro:
// LocalizationSetLanguage(@"German") or LocalizationSetLanguage(@"de");
- (void) setLanguage:(NSString*) lang {

    // path to this languages bundle
    NSString *path = [[NSBundle mainBundle] pathForResource:lang ofType:@"lproj" ];
    if (path == nil) {
        // there is no bundle for that language
        // use main bundle instead
        myBundle = [NSBundle mainBundle];
    } else {

        // use this bundle as my bundle from now on:
        myBundle = [NSBundle bundleWithPath:path];

        // to be absolutely shure (this is probably unnecessary):
        if (myBundle == nil) {
            myBundle = [NSBundle mainBundle];
        }
    }
}


@end


For each language you want to support you need a file named Localizable.strings. This works exactly as described in Apples documentation for localization. The only difference: Now you even can use languages like hindi or esperanto, that are not supported by Apple.

对于您想要支持的每种语言,您都需要一个名为Localizable.strings. 这与 Apples 本地化文档中描述的完全一样。唯一的区别:现在您甚至可以使用 Apple 不支持的语言,如印地语或世界语。

To give you an example, here are the first lines of my english and german versions of Localizable.strings:

举个例子,这里是我的 Localizable.strings 的英文和德文版本的第一行:

English

英语

/* English - English */

/* for debugging */
"languageOfBundle" = "English - English";

/* Header-Title of the Table displaying all lists and projects */
"summary" = "Summary";

/* Section-Titles in table "summary" */
"help" = "Help";
"lists" = "Lists";
"projects" = "Projects";
"listTemplates" = "List Templates";
"projectTemplates" = "Project Templates";

German

德语

/* German - Deutsch */

/* for debugging */
"languageOfBundle" = "German - Deutsch";

/* Header-Title of the Table displaying all lists and projects */
"summary" = "überblick";

/* Section-Titles in table "summary" */
"help" = "Hilfe";
"lists" = "Listen";
"projects" = "Projekte";
"listTemplates" = "Vorlagen für Listen";
"projectTemplates" = "Vorlagen für Projekte";


To use localizing, you must have some settings-routines in your app, and in the language-selection you call the macro:

要使用本地化,您的应用程序中必须有一些设置例程,并在语言选择中调用宏:

LocalizationSetLanguage(selectedLanguage);

After that you must enshure, that everything that was displayed in the old language, gets redrawn in the new language right now (hidden texts must be redrawn as soon as they get visible again).

之后,您必须确保以旧语言显示的所有内容现在都以新语言重新绘制(隐藏文本一旦再次可见就必须重新绘制)。

To have localized texts available for every situation, you NEVER must write fix texts to the objects titles. ALWAYS use the macro LocalizedString(keyword).

要在每种情况下都可以使用本地化文本,您永远不必为对象标题编写固定文本。始终使用宏LocalizedString(keyword)

don't:

别:

cell.textLabel.text = @"nice title";

do:

做:

cell.textLabel.text = LocalizedString(@"nice title");

and have a "nice title" entry in every version of Localizable.strings!

并且在每个版本的 Localizable.strings 中都有一个“不错的标题”条目!

回答by Novarg

Simply add the following to the screen with language choice:

只需将以下内容添加到带有语言选择的屏幕上:

    NSString *tempValue = //user chosen language. Can be picker view/button/segmented control/whatever. Just get the text out of it
    NSString *currentLanguage = @"";
    if ([tempValue rangeOfString:NSLocalizedString(@"English", nil)].location != NSNotFound) {
        currentLanguage = @"en";
    } else if ([tempValue rangeOfString:NSLocalizedString(@"German", nil)].location != NSNotFound) {
        currentLanguage = @"de";
    } else if ([tempValue rangeOfString:NSLocalizedString(@"Russian", nil)].location != NSNotFound) {
        currentLanguage = @"ru";
    }
    [[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:currentLanguage, nil] forKey:@"AppleLanguages"];
    [[NSUserDefaults standardUserDefaults]synchronize];

Then ask them to restart the app and the app will be in other language.

然后让他们重新启动应用程序,应用程序将使用其他语言。

Hope it helps

希望能帮助到你

回答by Jeehut

Here's a ready-to-useand step-by-step guideon how to use Novarg's approach in Swift 3:

这里有一个现成的使用一步一步的指导,就如何使用诺维格的做法,斯威夫特3



Step #1: Implement a language chooser

第 1 步:实现语言选择器

How to best do this is up to you and depends on the project. But use

如何最好地做到这一点取决于您,并取决于项目。但是使用

Bundle.main.localizations.filter({ 
Locale.current.localizedString(forLanguageCode: "en") // replace "en" with your variable
!= "Base" }) // => ["en", "de", "tr"]

to get a list of all your supported localeslanguage codes programmatically. Also you can use

以编程方式获取所有支持的区域设置语言代码的列表。你也可以使用

@IBOutlet var changeLanguageButton: UIButton!

@IBAction func didPressChangeLanguageButton() {
    let message = "Change language of this app including its content."
    let sheetCtrl = UIAlertController(title: "Choose language", message: message, preferredStyle: .actionSheet)

    for languageCode in Bundle.main.localizations.filter({ 
private func changeToLanguage(_ langCode: String) {
    if Bundle.main.preferredLocalizations.first != langCode {
        let message = "In order to change the language, the App must be closed and reopened by you."
        let confirmAlertCtrl = UIAlertController(title: "App restart required", message: message, preferredStyle: .alert)

        let confirmAction = UIAlertAction(title: "Close now", style: .destructive) { _ in
            UserDefaults.standard.set([langCode], forKey: "AppleLanguages")
            UserDefaults.standard.synchronize()
            exit(EXIT_SUCCESS)
        }
        confirmAlertCtrl.addAction(confirmAction)

        let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
        confirmAlertCtrl.addAction(cancelAction)

        present(confirmAlertCtrl, animated: true, completion: nil)
    }
}
!= "Base" }) { let langName = Locale.current.localizedString(forLanguageCode: languageCode) let action = UIAlertAction(title: langName, style: .default) { _ in self.changeToLanguage(languageCode) // see step #2 } sheetCtrl.addAction(action) } let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil) sheetCtrl.addAction(cancelAction) sheetCtrl.popoverPresentationController?.sourceView = self.view sheetCtrl.popoverPresentationController?.sourceRect = self.changeLanguageButton.frame present(sheetCtrl, animated: true, completion: nil) }

to present the language name inthe apps current language.

以应用程序当前语言显示语言名称

As a complete example you could present a popover action sheetafter clicking a button like this:

作为一个完整的示例,您可以在单击这样的按钮后显示一个弹出操作表

UserDefaults.standard.set([langCode], forKey: "AppleLanguages")
UserDefaults.standard.synchronize() // required on real device


Step #2: Explain user what to do + Change language with restart

第 2 步:解释用户要做什么 + 重新启动更改语言

You might have noticed that the code in step #1 calls a method named changeToLanguage(langCode:). That's what you should do, toowhen the user chooses a new language to change to, no matter how you designed your chooser. Here's its implementation, just copy it to your project:

您可能已经注意到,第 1 步中的代码调用了一个名为 的方法changeToLanguage(langCode:)。无论您如何设计选择器当用户选择要更改的新语言时这也是您应该做的。这是它的实现,只需将其复制到您的项目中即可:

UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"App restart required", @"App restart required") message:NSLocalizedString(@"In order to change the language, the App must be closed and reopened by you.", @"In order to change the language, the App must be closed and reopened by you.") preferredStyle:UIAlertControllerStyleActionSheet];

    [actionSheet addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", @"Cancel") style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {


        [self dismissViewControllerAnimated:YES completion:^{


        }];
    }]];

    [actionSheet addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Restart", @"Restart") style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) {

        [[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"ar", nil] forKey:@"AppleLanguages"];
        [[NSUserDefaults standardUserDefaults]synchronize];

        exit(EXIT_SUCCESS);


    }]];


    [self presentViewController:actionSheet animated:YES completion:nil];
}

This will both ask and inform the user about if he wants to do the change and how to do it. Also it sets the apps language on the next start using:

这将询问并告知用户他是否想要进行更改以及如何进行。它还在下次开始时使用以下方法设置应用程序语言:

##代码##

Step #3 (optional): Localize the Strings

第 3 步(可选):本地化字符串

You might want to localize the strings like "Close now" by using the NSLocalizedStringmacro (or any other enhanced method).

您可能希望使用NSLocalizedString宏(或任何其他增强方法)本地化诸如“立即关闭”之类的字符串。



Real World Example

真实世界示例

I'm using this exact implementation in an app targeted for iOS 10, I can confirm it worksfor me both on simulator and device. The app is actually open source, so you can find the above code distributed into different classes here.

我在针对iOS 10的应用程序中使用了这个确切的实现,我可以确认它在模拟器和设备上都适用于我。该应用程序实际上是开源的,因此您可以在此处找到分发到不同类中的上述代码。

回答by fishinear

Starting with iOS 13, there is now a way to set an individual language for each app, supported by iOS itself. In the Apple Settings app, open the settings of the specific app, and select the language under "Preferred Language". You can select from the languages that the app supports.

从 iOS 13 开始,现在有一种方法可以为每个应用程序设置单独的语言,由 iOS 本身支持。在 Apple 设置应用程序中,打开特定应用程序的设置,然后在“首选语言”下选择语言。您可以从应用程序支持的语言中进行选择。

回答by Tomek Cejner

My answer may be a matter of preference since I would disdain manual language selection in the app: you will have to override all system-provided buttons and make sure not to use them. It also adds another layer of complexity and may lead the user to confusion.

我的回答可能是一个偏好问题,因为我不屑在应用程序中手动选择语言:您必须覆盖所有系统提供的按钮并确保不使用它们。它还增加了另一层复杂性,并可能导致用户混淆。

However, since this has to be an answer, I think your use case is solved without hacking language selection.

但是,由于这必须是一个答案,我认为您的用例无需黑客语言选择即可解决。

In iOS preferences, you may set additional languages:

在 iOS 首选项中,您可以设置其他语言:

iOS language selection preferences

iOS 语言选择首选项

Your example son of immigrants could have set French as main language and German as an additional language.

您的移民之子本可以将法语设为主要语言,将德语设为附加语言。

Then, when your app is localized to English and German, that young man's iPhone would pick German resources.

然后,当您的应用本地化为英语和德语时,那个年轻人的 iPhone 会选择德语资源。

Would that solve the problem?

那能解决问题吗?

回答by AlessandroDP

Localize-Swift- Swift friendly localization and i18n with in-app language switching

Localize-Swift- Swift 友好的本地化和具有应用内语言切换的 i18n

回答by Gastón Antonio Montes

I had a similar issue in my current work project. I figured out a simple way to do this and I had to explain it to my partners in order to discuss the solution. I made a simple app with 2 buttons (English||Spanish) to select the language inside the app, the code is in Objective-C (Because our current app is in Objective-C) here is the code: https://bitbucket.org/gastonmontes/gmlanguageselectiondemo

我在当前的工作项目中遇到了类似的问题。我想出了一个简单的方法来做到这一点,我不得不向我的合作伙伴解释,以便讨论解决方案。我制作了一个带有 2 个按钮(英语||西班牙语)的简单应用程序来选择应用程序内的语言,代码是 Objective-C(因为我们当前的应用程序是 Objective-C)这里是代码:https://bitbucket .org/gastonmontes/gmlanguageselectiondemo

回答by Spydy

Its very simple and easy to change language manually. First of all you need to localize your app, then you can use below code to change language manually in your app.

手动更改语言非常简单和容易。首先,您需要本地化您的应用程序,然后您可以使用以下代码在您的应用程序中手动更改语言。

##代码##