Meilleure pratique en utilisant NSLocalizedString

Je suis (comme tous les autres) en utilisant NSLocalizedString pour Localiser mon application.

Malheureusement, il y a plusieurs "inconvénients" (pas nécessairement la faute de NSLocalizedString lui-même), y compris

  • Pas d'autocomplétition pour les chaînes dans Xcode. Cela rend le travail non seulement sujet aux erreurs, mais aussi fastidieux.
  • vous pourriez finir par redéfinir une chaîne simplement parce que vous ne saviez pas qu'une chaîne équivalente existait déjà (c'est-à-dire "please enter password" vs. " Enter password en premier")
  • de la même manière que le problème de complétion automatique, vous devez "mémoriser" / copier les chaînes de commentaire, sinon genstring se retrouvera avec plusieurs commentaires pour une chaîne
  • Si vous voulez utiliser genstring Après avoir déjà localisé certaines chaînes, vous devez faire attention à ne pas perdre vos anciennes localisations.
  • les mêmes chaînes sont dispersées dans tout votre projet. Par exemple, vous avez utilisé NSLocalizedString(@"Abort", @"Cancel action") partout, puis Code Review vous demande de renommer la chaîne en NSLocalizedString(@"Cancel", @"Cancel action") pour faire le code plus cohérent.

Ce que je fais (et après quelques recherches sur donc j'ai pensé que beaucoup de gens le font) est d'avoir un fichier strings.h séparé où je #define tout le code de localisation. Par exemple

// In strings.h
#define NSLS_COMMON_CANCEL NSLocalizedString(@"Cancel", nil)
// Somewhere else
NSLog(@"%@", NSLS_COMMON_CANCEL);

Cela fournit essentiellement la complétion de code,un seul endroit pour changer les noms de variables (donc plus besoin de genstring), et un mot-clé unique pour l'auto-refactor. Cependant, cela se fait au prix de se retrouver avec tout un tas d'instructions #define qui ne sont pas intrinsèquement structurées (c'est-à-dire comme LocString.Commun.Annuler ou quelque chose comme ça).

Donc, bien que cela fonctionne un peu bien, je me demandais comment vous le faites dans vos projets. Existe-t-il d'autres approches pour simplifier L'utilisation de NSLocalizedString? Est-il peut-être même un cadre qui encapsule il?

127
demandé sur JiaYow 2012-03-27 22:43:44

9 réponses

NSLocalizedString a quelques limitations, mais il est tellement au centre de Cacao qu'il est déraisonnable d'écrire du code personnalisé pour gérer localisation, ce qui signifie que vous aurez à l'utiliser. Cela dit, un peu d'outillage peut aider, voici comment je procède:

Mise à Jour du fichier de chaînes

genstrings écrase vos fichiers de chaîne, en supprimant toutes vos traductions précédentes. J'ai écrit update_strings.py pour analyser l'ancien fichier de chaînes, exécutez genstrings et remplissez les blancs afin de ne pas avoir à le faire manuellement restaurez vos traductions existantes. Le script essaie de faire correspondre les fichiers de chaîne existants aussi étroitement que possible pour éviter d'avoir un diff trop important lors de leur mise à jour.

Nommer vos chaînes

Si vous utilisez NSLocalizedString comme annoncé:

NSLocalizedString(@"Cancel or continue?", @"Cancel notice message when a download takes too long to proceed");

Vous pouvez finir par définir la même chaîne dans une autre partie de votre code, ce qui peut entrer en conflit car le même terme anglais peut avoir une signification différente dans différents contextes (OK et Cancel viennent à l'esprit). C'est pourquoi j'utilise toujours des majuscules insignifiantes chaîne avec un préfixe spécifique au module, et une description très précise:

NSLocalizedString(@"DOWNLOAD_CANCEL_OR_CONTINUE", @"Cancel notice window title when a download takes too long to proceed");

Utiliser la même chaîne à différents endroits

Si vous utilisez la même chaîne plusieurs fois, vous pouvez soit utiliser une macro comme vous l'avez fait, soit la mettre en cache en tant que variable d'instance dans votre contrôleur de vue ou votre source de données. De cette façon, vous n'aurez pas à répéter la description qui peut devenir obsolète et devenir incohérente entre les instances de la même localisation, ce qui est toujours déroutant. Comme les variables d'instance sont Symboles, vous serez en mesure d'utiliser l'auto-complétion sur ces traductions les plus courantes, et utiliser des chaînes "manuelles" pour les spécifiques, qui ne se produiraient qu'une seule fois de toute façon.

J'espère que vous serez plus productif avec la localisation de cacao avec ces conseils!

89
répondu ndfred 2013-10-03 13:30:39

Comme pour l'autocomplétition pour les chaînes dans Xcode, vous pouvez essayer http://questbe.at/lin/.

30
répondu hiroshi 2013-09-28 02:22:32

D'Accord avec ndfred, mais je voudrais ajouter ceci:

Deuxième paramètre peut être utilisé comme ... valeur par défaut!!

(NSLocalizedStringWithDefaultValue ne fonctionne pas correctement avec genstring, c'est pourquoi j'ai proposé cette solution)

Voici mon implémentation personnalisée qui utilise NSLocalizedString qui utilise comment comme valeur par défaut:

1 . Dans votre pré compilé en-tête (.fichier pch), redéfinissez la macro' nslocalizedstring':

// cutom NSLocalizedString that use macro comment as default value
#import "LocalizationHandlerUtil.h"

#undef NSLocalizedString
#define NSLocalizedString(key,_comment) [[LocalizationHandlerUtil singleton] localizedString:key  comment:_comment]

2. créer une classe pour implémenter le gestionnaire de localisation

#import "LocalizationHandlerUtil.h"

@implementation LocalizationHandlerUtil

static LocalizationHandlerUtil * singleton = nil;

+ (LocalizationHandlerUtil *)singleton
{
    return singleton;
}

__attribute__((constructor))
static void staticInit_singleton()
{
    singleton = [[LocalizationHandlerUtil alloc] init];
}

- (NSString *)localizedString:(NSString *)key comment:(NSString *)comment
{
    // default localized string loading
    NSString * localizedString = [[NSBundle mainBundle] localizedStringForKey:key value:key table:nil];

    // if (value == key) and comment is not nil -> returns comment
    if([localizedString isEqualToString:key] && comment !=nil)
        return comment;

    return localizedString;
}

@end

3. L'utiliser!

Assurez-vous d'ajouter un script D'exécution dans les Phases de construction de votre application afin que vous soyez localisable.le fichier strings sera mis à jour à chaque build, c'est-à-dire qu'une nouvelle chaîne localisée sera ajoutée dans votre localisée.fichier de Chaînes:

Mon Script de phase de construction est un script shell:

Shell: /bin/sh
Shell script content: find . -name \*.m | xargs genstrings -o MyClassesFolder

Donc, lorsque vous ajoutez cette nouvelle ligne dans votre code:

self.title = NSLocalizedString(@"view_settings_title", @"Settings");

Ensuite, effectuez une construction, votre ./Localisable.le fichier scripts contiendra ce nouveau ligne:

/* Settings */
"view_settings_title" = "view_settings_title";

Et puisque key = = value pour 'view_settings_title' , le LocalizedStringHandler personnalisé renvoie le commentaire, c'est-à-dire 'Settings"

Voilà : -)

22
répondu Pascal 2012-05-22 12:04:35

J'ai écrit un script pour aider à maintenir localisable.chaînes en plusieurs langues. Bien que cela n'aide pas à l'auto-complétion, il aide à fusionner .fichiers de chaînes utilisant la commande:

merge_strings.rb ja.lproj/Localizable.strings en.lproj/Localizable.strings

Pour plus d'informations, voir: https://github.com/hiroshi/merge_strings

Certains d'entre vous le trouvent utile, j'espère.

2
répondu hiroshi 2015-07-25 18:15:32

Dans Swift, j'utilise ce qui suit, par exemple pour le bouton "Oui" dans ce cas:

NSLocalizedString("btn_yes", value: "Yes", comment: "Yes button")

Notez l'utilisation de value: pour la valeur de texte par défaut. Le premier paramètre sert D'ID de traduction. L'avantage d'utiliser le paramètre value: est que le texte par défaut peut être modifié ultérieurement, mais que l'ID de traduction reste le même. localisable.le fichier strings contiendra "btn_yes" = "Yes";

Si le paramètre value: n'était pas utilisé, le premier paramètre serait utilisé pour les deux: pour l'ID de traduction et également pour la valeur de texte par défaut. localisable.le fichier de chaînes contiendrait "Yes" = "Yes";. Ce genre de gestion des fichiers de localisation semble être étrange. Surtout si le texte traduit est long, l'ID est aussi long. Chaque fois qu'un caractère de la valeur de texte par défaut est modifié, l'ID de traduction est également modifié. Cela entraîne des problèmes lorsque des systèmes de traduction externes sont utilisés. La modification de l'ID de traduction est comprise comme l'ajout d'un nouveau texte de traduction, qui peut ne pas être toujours voulu.

1
répondu petrsyn 2017-08-31 23:58:51
#define PBLocalizedString(key, val) \

[[NSBundle mainBundle] localizedStringForKey:(key) value:(val) table:nil]
0
répondu baozhifei 2013-06-27 09:25:12

Avec iOS 7 & Xcode 5, vous devriez éviter d'utiliser la ' localisation.strings' méthode, et utiliser la nouvelle méthode' localisation de base'. Il y a quelques tutoriels autour si vous google pour 'localisation de base'

Doc Apple: localisation de Base

0
répondu Ronny Webers 2014-09-10 16:46:55

Moi - même, je suis souvent emporté par le codage, oubliant de mettre les entrées dans .les chaînes de fichiers. Ainsi, j'ai des scripts d'aide pour trouver dans quoi dois-je remettre .chaînes de fichiers et traduire.

Comme j'utilise ma propre macro sur NSLocalizedString, Veuillez examiner et mettre à jour le script avant d'utiliser comme je l'ai supposé pour simplifier que nil est utilisé comme deuxième paramètre de NSLocalizedString. La partie que vous voulez changer est

NSLocalizedString\(@(".*?")\s*,\s*nil\) 

Il suffit de le remplacer par quelque chose qui correspond à votre macro et à L'utilisation de NSLocalizedString.

Voici le script, vous n'avez besoin que de la partie 3 en effet. Le reste est de voir plus facilement d'où tout vient:

// Part 1. Get keys from one of the Localizable.strings
perl -ne 'print "$1\n" if /^\s*(".+")\s*=/' myapp/fr.lproj/Localizable.strings

// Part 2. Get keys from the source code
grep -n -h -Eo -r  'NSLocalizedString\(@(".*?")\s*,\s*nil\)' ./ | perl -ne 'print "$1\n" if /NSLocalizedString\(@(".+")\s*,\s*nil\)/'

// Part 3. Get Part 1 and 2 together.

comm -2 -3 <(grep -n -h -Eo -r  'NSLocalizedString\(@(".*?")\s*,\s*nil\)' ./ | perl -ne 'print "$1\n" if /NSLocalizedString\(@(".+")\s*,\s*nil\)/' | sort | uniq) <(perl -ne 'print "$1\n" if /^\s*(".+")\s*=/' myapp/fr.lproj/Localizable.strings | sort) | uniq >> fr-localization-delta.txt

Le fichier de sortie contient des clés qui ont été trouvées dans le code, mais pas dans le Localizable.fichier de chaînes. Voici un exemple:

"MPH"
"Map Direction"
"Max duration of a detailed recording, hours"
"Moving ..."
"My Track"
"New Trip"

Peut certainement être poli plus, mais je pensais partager.

0
répondu Stanislav Dvoychenko 2016-04-07 15:18:57

Si quelqu'un cherche une solution rapide. Vous pouvez consulter ma solution que j'ai mise en place ici: SwiftyLocalization

Avec quelques étapes pour configurer, vous aurez une localisation très flexible dans Google Spreadsheet (commentaire, couleur personnalisée, surbrillance, police, plusieurs feuilles, et plus encore).

En bref, les étapes sont: Google Spreadsheet - > fichiers CSV - > Localizable.chaînes

De plus, il génère également des Localizables.swift, une structure qui agit comme des interfaces à une récupération de clé & décodage pour vous (vous devez spécifier manuellement un moyen de décoder la chaîne à partir de la clé).

Pourquoi est-ce génial?

  1. Vous n'avez plus besoin d'avoir une clé comme une chaîne simple partout.
  2. Les mauvaises clés sont détectées au moment de la compilation.
  3. Xcode peut effectuer la saisie semi-automatique.

Bien qu'il existe des outils qui peuvent compléter automatiquement votre clé localisable. La référence à une variable réelle garantira que c'est toujours une clé valide, sinon elle ne compilera pas.

// It's defined as computed static var, so it's up-to-date every time you call. 
// You can also have your custom retrieval method there.

button.setTitle(Localizables.login.button_title_login, forState: .Normal)

Le le projet utilise Google App Script pour convertir les feuilles - > CSV, et le script Python pour convertir les fichiers CSV - > localisable.chaînes vous pouvez jeter un coup d'œil à cette feuille d'exemple pour savoir ce qui est possible.

0
répondu aunnnn 2016-10-13 06:12:42