web-dev-qa-db-fra.com

sélection manuelle de la langue dans une application iOS (iPhone et iPad)

Ma question:

Comment mon application iPhone peut-elle indiquer à iOS que l'utilisateur a sélectionné une langue dans les préférences de l'application, différente de celle définie dans les paramètres généraux?

Autre formulation de la même question:

Comment puis-je dire au système que NSLocalizedString (@"text", @"comment"); ne doit pas accéder à la langue sélectionnée dans tout le système, mais à la langue sélectionnée dans l'application?

background, example:

Veuillez prendre cette situation comme exemple: un fils d'immigrants allemands vit dans le nord-est de la France, à côté du Luxembourg et de l'Allemagne. Sa langue maternelle est le français, il a donc défini la langue d'interface utilisateur de son iPhone en français (Paramètres -> Général -> International -> Langue -> Français). Mais en raison de sa culture et de sa bilinguisme, il parle très bien allemand. Mais il ne parle pas dix mots d'anglais. Sur un iPhone (et un iPad également), il n'a aucune chance de choisir une deuxième langue. Le téléphone sait seulement qu'il parle français. Il n'a aucune connaissance des compétences des utilisateurs dans d'autres langues.

Vient maintenant mon application: je l’ai développée en anglais et en allemand (l’allemand est ma langue maternelle et l’anglais est la langue standard en informatique). Je l'ai développé conformément à toutes les règles et aux meilleures pratiques pour les applications iOS multilingues. "Première" langue (langue par défaut) de mon application est l'anglais.

Cela signifie:

Si quelqu'un a choisi l'anglais ou l'allemand dans ses paramètres, l'interface utilisateur de l'application utilisera automatiquement la langue sélectionnée. L'utilisateur ne remarquera même pas qu'il existe d'autres langues disponibles.

Mais s'il a sélectionné une autre langue (comme le chinois, le polonais ou le français) dans les paramètres généraux, il obtiendra la langue par défaut de l'application, qui, dans mon cas, est l'anglais. Mais pour mon ami franco-allemand, ce n'est pas le meilleur choix. Il aimerait utiliser la version allemande existante, mais il semble n'y avoir aucun moyen de laisser l'utilisateur sélectionner cette version.

Ajouter une traduction en français résoudrait le problème pour notre ami franco-allemand, mais pas pour les personnes parlant deux autres langues (comme l'italien et l'allemand), et je ne peux pas supporter mon application avec toutes les langues parlées sur cette planète. La définition de la langue par défaut en allemand n’est pas non plus optimale, car cela poserait le même problème aux personnes parlant français (une langue maternelle) et anglais (langue seconde).

Je pense donc que mon application doit avoir la possibilité de sélectionner manuellement une langue différente de la langue présélectionnée. Ajouter une sélection de langue au panneau de configuration des applications n'est pas le problème. Mais comment puis-je dire au système que NSLocalizedString (@"text", @"comment"); ne doit pas accéder à la langue sélectionnée dans tout le système, mais à la langue sélectionnée dans l'application?

68
Hubert Schölnast

Entre temps, j'ai trouvé une solution à mon problème:

J'ai créé une nouvelle classe "LocalizeHelper":


Header 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
#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

Pour chaque langue que vous souhaitez prendre en charge, vous avez besoin d'un fichier nommé Localizable.strings. Cela fonctionne exactement comme décrit dans la documentation d'Apple pour la localisation. La seule différence: maintenant, vous pouvez même utiliser des langages tels que l'hindi ou l'espéranto, qui ne sont pas pris en charge par Apple.

Pour vous donner un exemple, voici les premières lignes de mes versions anglaise et allemande de Localizable.strings:

Anglais

/* 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";

allemand

/* 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";

Pour utiliser la localisation, vous devez avoir des routines de paramètres dans votre application, et dans la sélection de langue, vous appelez la macro:

LocalizationSetLanguage(selectedLanguage);

Après cela, vous devez vous assurer que tout ce qui était affiché dans l'ancienne langue est maintenant redessiné dans la nouvelle langue (les textes masqués doivent être redessinés dès qu'ils sont à nouveau visibles).

Pour avoir des textes localisés disponibles pour chaque situation, vous ne devez JAMAIS écrire des textes fixes sur les titres des objets. Utilisez TOUJOURS la macro LocalizedString(keyword).

ne pas:

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

do:

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

et avoir une entrée "Nice title" dans chaque version de Localizable.strings!

83
Hubert Schölnast

Ajoutez simplement les éléments suivants à l'écran avec le choix de langue:

    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];

Puis demandez-leur de redémarrer l'application et celle-ci sera dans une autre langue.

J'espère que ça aide

39
Novarg

Voici un prêt à l'emploi et guide étape par étape sur la façon d'utiliser l'approche de Novarg dans Swift 3 :


Étape n ° 1: implémenter un sélecteur de langue

La meilleure façon de le faire est à vous et dépend du projet. Mais utiliser

Bundle.main.localizations.filter({ $0 != "Base" }) // => ["en", "de", "tr"]

pour obtenir une liste de tous vos codes de langue locaux pris en charge par programmation. Aussi, vous pouvez utiliser

Locale.current.localizedString(forLanguageCode: "en") // replace "en" with your variable

présenter le nom de la langue en dans les applications langue actuelle .

A titre d'exemple complet, vous pouvez présenter une fiche d'action contextuelle après avoir cliqué sur un bouton tel que:

@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({ $0 != "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)
}

Étape 2: Expliquez aux utilisateurs quoi faire + Changer de langue avec redémarrage

Vous avez peut-être remarqué que le code de l'étape 1 appelle une méthode nommée changeToLanguage(langCode:). C'est ce que vous devez faire également lorsque l'utilisateur choisit une nouvelle langue, quelle que soit la manière dont vous avez conçu votre sélecteur. Voici son implémentation , copiez-la simplement dans votre projet:

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)
    }
}

Cela demandera et informera l'utilisateur s'il souhaite effectuer le changement et comment le faire. En outre, il définit la langue des applications au prochain démarrage en utilisant:

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

Étape n ° 3 (facultatif): localiser les chaînes

Vous voudrez peut-être localiser les chaînes telles que "Fermer maintenant" à l'aide de la macro NSLocalizedString (ou de toute autre méthode améliorée).


Exemple du monde réel

J'utilise cette implémentation exacte dans une application ciblée pour iOS 10, je peux confirmer que cela fonctionne pour moi, à la fois sur le simulateur et sur l'appareil. L’application est en fait open source , vous pouvez donc trouver le code ci-dessus distribué dans différentes classes ici .

19
Dschee

Ma réponse peut être une question de préférence, car je dédaignerais la sélection manuelle de la langue dans l'application: vous devrez remplacer tous les boutons fournis par le système et vous assurer de ne pas les utiliser. Cela ajoute également une autre couche de complexité et peut conduire à la confusion.

Cependant, comme cela doit être une réponse, je pense que votre cas d'utilisation est résolu sans piratage informatique.

Dans les préférences iOS, vous pouvez définir des langues supplémentaires:

iOS language selection preferences

Votre exemple de fils d'immigrants aurait pu définir le français comme langue principale et l'allemand comme langue supplémentaire.

Ensuite, lorsque votre application est localisée en anglais et en allemand, l'iPhone de ce jeune homme choisit des ressources en allemand.

Cela résoudrait-il le problème?

3
Tomek Cejner

Localize-Swift - Swift et i18n avec changement de langue in-app

2
AlessandroDP

J'ai eu un problème similaire dans mon projet de travail actuel. J'ai trouvé un moyen simple de le faire et je devais l'expliquer à mes partenaires afin de discuter de la solution. J'ai fait une application simple avec 2 boutons (anglais || espagnol) pour sélectionner la langue dans l'application, le code est en Objective-C (car notre application actuelle est en Objective-C), voici le code: https : //bitbucket.org/gastonmontes/gmlanguageselectiondemo

0

C'est très simple et facile de changer de langue manuellement. Tout d’abord, vous devez localiser votre application, puis vous pouvez utiliser le code ci-dessous pour changer de langue manuellement dans votre application.

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];
}
0
Spydy