Meilleure façon de concevoir la localisation des chaînes

C’est un peu une question générale, ouverte aux opinions. J’ai essayé de trouver un bon moyen de concevoir la localisation des ressources de chaîne pour une application Windows MFC et les utilitaires associés. Ma liste de souhaits est la suivante:

  • Doit préserver les littéraux de chaîne dans le code (par opposition à remplacer par une macro #define ID de la ressource), afin que les messages restnt lisibles en ligne
  • Doit autoriser les ressources de chaîne localisées (duh)
  • Ne doit pas imposer de ressortingctions supplémentaires à l’environnement d’exécution (par exemple: dépendance à l’égard de .NET, etc.)
  • Devrait avoir une obstruction minimale dans le code existant (le moins de modification possible)
  • Devrait être déboguable
  • Devrait générer des fichiers de ressources modifiables par des outils communs (ex: format commun)
  • Ne pas utiliser les blocs de commentaires de type copier / coller pour préserver les chaînes littérales dans le code, ou tout autre élément créant un risque de désynchronisation
  • Serait bien de permettre la vérification statique (à la compilation) que chaque chaîne “notée” se trouve dans le ou les fichiers de ressources
  • Serait bien de permettre la mise en pool de chaînes de ressources multilingues (pour les composants dans différentes langues, par exemple: C ++ natif et .NET)

J’ai un moyen qui remplit toute ma liste de souhaits dans une certaine mesure, sauf pour la vérification statique, mais j’ai dû développer un peu de code personnalisé pour y parvenir (et il a des limites). Je me demande si quelqu’un a résolu ce problème de manière particulièrement efficace.

Edit: La solution que j’ai actuellement ressemble à ceci:

ShowMessage( RESTRING( _T("Some ssortingng") ) ); ShowMessage( RESTRING( _T("Some ssortingng with variable %1"), sNonTranslatedSsortingngVariable ) ); 

J’ai ensuite un utilitaire personnalisé pour parsingr les chaînes dans les blocs ‘RESTRING’ et les placer dans un fichier .resx pour la localisation, et un object C # COM distinct pour les charger à partir de fichiers de ressources localisés avec repli. Si l’object C # n’est pas disponible (ou ne peut pas être chargé), je me rabat sur la chaîne du code. La macro se développe en une classe de modèle qui appelle l’object COM et effectue le formatage, etc.

Quoi qu’il en soit, j’ai pensé qu’il serait utile d’append ce que j’ai maintenant à titre de référence.

Nous utilisons la chaîne anglaise comme identifiant.

S’il échoue à la recherche de l’object ressource international (chargé depuis la DLL I18N installée), nous passons par défaut à la chaîne ID.

Le code ressemble à:

 doAction(I18N.get("Press OK to continue")); 

Dans le cadre des processus de construction, nous avons un script perl qui parsing toutes les sources pour les constantes de chaîne. Il construit un fichier temporaire de toutes les chaînes de l’application, puis les compare aux chaînes de ressources de chaque local pour voir si elles existent. Toute chaîne manquante génère un courrier électronique à l’équipe de traduction appropriée.

Nous pouvons avoir plusieurs dll pour chaque local. Le nom de la DLL est basé sur la RFC 3066
langue [_territory] [.codeet] [@ modificateur]

Nous essayons d’extraire les parameters régionaux de la machine et d’être aussi précis que possible lors du chargement de la DLL I18N mais de revenir à des variations locales moins spécifiques si la version plus spécifique n’est pas présente.

Exemple:

Au Royaume-Uni: Si le local était en_GB.UTF-8
(J’utilise le terme dll vaguement pas dans le sens spécifique de windows).

Recherchez d’abord le dll I18N.en_GB.UTF-8 . Si cette DLL n’existe pas, revenez à I18N.en_GB . Si cette DLL n’existe pas, revenez à I18N.en Si cette DLL n’existe pas, faites confiance à I18N.default

La seule exception à cette règle est la suivante: le chinois simplifié (zh_CN), où le secours est l’anglais américain (en_US). Si la machine ne prend pas en charge le chinois simplifié, il est peu probable qu’elle prenne en charge le chinois complet.

Je ne sais pas trop comment cela se fait normalement sur Windows, mais la manière dont les chaînes localisées sont gérées dans le framework Cocoa d’Apple fonctionne plutôt bien. Ils ont un fichier texte de base très simple que vous pouvez envoyer à un traducteur et des macros de préprocesseur pour récupérer les valeurs des fichiers.

Dans votre code, vous verrez les chaînes dans votre langue maternelle, plutôt que comme des identifiants opaques.

Votre solution est assez similaire à la solution Unix / Linux ” gettext “. En fait, vous n’auriez pas besoin d’écrire les routines d’extraction.

Je ne sais pas pourquoi vous voulez que la macro _RESTRING gère plusieurs arguments. Mon code (utilisant le support de wxWidgets pour gettext) ressemble à ceci: MySsortingng.Format(_("Some ssortingng with variable %ls"), _("variable")); . C’est-à-dire que Ssortingng :: Format (…) obtient deux arguments traduits individuellement. Avec le recul, Boost :: Format aurait été meilleur, mais il permettrait aussi de boost::format(_("Some ssortingng with variable %1")) % _("variable");

(Nous utilisons la macro _() pour des raisons de concision)

Le moyen le plus simple est d’utiliser uniquement des identifiants de chaîne dans votre code – pas de chaîne de caractères. Vous pouvez ensuite produire différentes versions du fichier.rc pour chaque langue et créer des DLL de ressources uniquement ou simplement des versions de langues différentes.

Il existe quelques utilitaires de partage de fichiers localisant le fichier rc qui gèrent les éléments de dialog de redimensionnement pour les langues avec des mots plus longs et des avertissements sur les traductions manquantes.

Un problème plus compliqué est l’ordre des mots, si vous avez plusieurs nombres dans un printf qui doivent être dans un ordre différent pour la grammaire d’un langage différent. Il existe des classes printf étendues sur codeproject qui vous permettent de spécifier des choses comme printf (“mot% 1s et% 2s”, var1, var2). Vous pouvez donc changer% 1s et% 2s si nécessaire.

Sur un projet que j’avais localisé dans plus de 10 langues, je mettais tout ce qui devait être localisé dans une seule DLL. Au moment de l’installation, l’utilisateur a sélectionné quelle DLL a été installée avec son application.

Je n’avais qu’à livrer le dll anglais à l’équipe de localisation. Ils m’ont renvoyé une DLL localisée pour chaque langue incluse dans la compilation.

Je sais que ce n’est pas parfait, mais ça a fonctionné.

Comme il est ouvert aux opinions, voici comment je le fais.

Mon fichier texte localisé est un simple fichier texte délimité par des tabulations qui peut être chargé dans Excel et modifié. La première colonne est pour définir et chaque colonne à droite est une langue ultérieure, par exemple:

 ID ENGLISH FRENCH GERMAN STRING_YES YES OUI YA STRING_NO NO NON NEIN 

Ensuite, dans mon makefile, il y a une étape de génération de cusom qui génère un fichier ssortingngs.h et un ssortingngs.dat. Dans mon cas, il construit une liste enum pour les identifiants de chaîne, puis un fichier binary avec des décalages pour le texte. Étant donné que dans mon application l’utilisateur peut changer la langue à tout moment, je les ai tous en mémoire, mais vous pouvez facilement demander à votre préprocesseur de générer un fichier de sortie différent pour chaque langue si nécessaire.

Ce que j’aime dans cette conception, c’est que si des chaînes sont manquantes, j’aurais une erreur de compilation alors que si des chaînes étaient recherchées à l’exécution, vous pourriez ne plus connaître une chaîne manquante dans une partie rarement utilisée du code.

Vous voulez un utilitaire avancé que j’ai toujours voulu écrire mais que je n’ai jamais eu le temps de Si vous ne trouvez pas un tel outil, vous souhaiterez peut-être utiliser les classes wrapper CMsg () et CFMsg () qui permettent d’extraire très facilement des chaînes de la table des ressources. (CFMsg fournit même un wrapper FormatMessage à une ligne. Et oui, en l’absence de cet outil, conserver une copie de la chaîne dans un commentaire est une bonne solution. En ce qui concerne la désynchronisation du commentaire, rappelez-vous que très rarement changé.

http://www.codeproject.com/KB/ssortingng/ssortingngtable.aspx

BTW, les programmes Win32 natifs et les programmes .NET ont une gestion du stockage des ressources totalement différente. Vous aurez du mal à trouver une solution commune pour les deux.