Construire votre démarrage avec PHP Localisation avec I18n

Ce que vous allez créer

Ceci est la quatrième partie de la série Construire son démarrage avec PHP sur Tuts +. Dans cette série, je vous guide dans le lancement d'une startup du concept à la réalité en utilisant mon application Meeting Planner comme exemple concret. À chaque étape, nous publierons le code de Meeting Planner sous forme d’exemples open source à partir desquels vous pourrez apprendre. Nous aborderons également les problèmes commerciaux liés au démarrage à mesure qu'ils surviennent..

Dans ce didacticiel, je souhaitais prendre du recul et ajouter le support de l'internationalisation I18n à notre application avant de générer de plus en plus de code. Selon Wikipedia, I18n est un numéronyme:

18 représente le nombre de lettres entre le premier je enfin n dans internationalisation, un usage inventé à DEC dans les années 1970 ou 80.

Avec I18n, toutes les chaînes de texte affichées à l’utilisateur à partir de l’application sont remplacées par des appels de fonction permettant de charger de manière dynamique les chaînes traduites pour n’importe quelle langue choisie par l’utilisateur..

Tout le code de Meeting Planner est écrit dans le framework Yii2 pour PHP, qui prend en charge I18n de manière intégrée. Si vous souhaitez en savoir plus sur Yii2, consultez notre série parallèle Programmer avec Yii2 chez Tuts+.

Juste un rappel, je participe aux commentaires ci-dessous. Je suis particulièrement intéressé si vous avez des approches différentes, des idées supplémentaires ou si vous souhaitez suggérer des sujets pour de futurs tutoriels..

Les objectifs de l'internationalisation

Lors de la création d'une startup, il est utile de penser globalement dès le début, mais pas toujours. Sinon, il peut être judicieux de vous concentrer uniquement sur le développement de votre marché local. Votre produit minimum viable doit-il fonctionner dans d'autres langues pour des utilisateurs de différents pays??

Dans notre cas, le framework Yii fournit une prise en charge intégrée pour I18n, il est donc relativement facile de créer une prise en charge pour I18n depuis le début, ce qui prend beaucoup de temps et de l'ajouter ultérieurement..

Comment ça marche?

I18n fonctionne en remplaçant toutes les références au texte affiché à l'utilisateur par des appels de fonction qui fournissent une traduction en cas de besoin.. 

Par exemple, voici à quoi ressemblent les noms de champ d'attribut dans le modèle Place avant I18n:

public function attributLabels () return ['id' => 'ID', 'name' => 'Name', 'place_type' => 'Type de lieu',… 

Fournir des versions traduites du code deviendrait très compliqué. Les traducteurs non techniques devraient traduire le code en place, ce qui risquerait de briser la syntaxe.

Voici à quoi ressemble le même code avec I18n:

fonction publique attributLabels () return ['id' => Yii :: t ('frontend', 'ID'), 'name' => Yii :: t ('frontend', 'Nom'), 'place_type' = > Yii :: t ('frontend', 'Type de lieu'),

Yii: t () est un appel de fonction qui vérifie quelle langue est actuellement sélectionnée et affiche la chaîne traduite appropriée. 'l'extrémité avant' fait référence à une section de notre application. Les traductions peuvent être organisées en fonction de différentes catégories. Mais, où apparaissent ces chaînes traduites? 

La langue par défaut, dans ce cas l'anglais, est écrite dans le code, comme indiqué ci-dessus. Les fichiers de ressources linguistiques sont des listes de tableaux de chaînes dont la clé est la langue par défaut text-e.g. 'Type de lieu'-et chaque fichier fournit des valeurs de texte traduit pour la langue appropriée.

Voici un exemple de notre fichier de traduction en espagnol complété, code de langue "es". le Yii: t () function utilise ce fichier pour trouver la traduction appropriée à afficher:

 'Ajouter un Google modelClass' => 'Ajouter un Google modelClass', 'Created By' => 'Creado por', 'Full Address' => 'Dirección completa', 'Google Place ID '=>' ID de lieu Google ',' Nom '=>' Nombre ',' Notes '=>' Notas ',' Type de lieu '=>' Lieu Tipo ',' Lieux '=>' Lugares ',

Bien que cela prenne beaucoup de temps, Yii fournit des scripts pour automatiser la génération et l'organisation de ces fichiers.. 

En séparant le texte du code, nous aidons les experts multilingues non techniques à traduire nos applications pour nous, sans casser le code..

I18n offre également des fonctions spécialisées pour la traduction du temps, de la monnaie, de pluriels et al. Je n'entrerai pas dans les détails de ceux-ci dans ce tutoriel. 

Configuration du support I18n

Malheureusement, la documentation de Yii2 pour I18n n’est pas encore très descriptive et il était difficile de trouver des exemples concrets, étape par étape. Heureusement pour vous, je vais vous expliquer ce que j'ai appris en parcourant les documents et le Web. J'ai trouvé l'exemple I18n de Code Ninja et le Guide définitif Yii2 sur I18n utiles, et Alexander Makarov, contributeur de Yii, m'a également offert son aide..

Génération du fichier de configuration I18n

Nous utilisons le modèle avancé Yii2 pour le planificateur de réunions. Cela crée deux applications Yii dans notre base de code, frontend et backend. Et, cela crée un espace commun pour les modèles partagés entre les deux applications. Les fichiers de configuration de Yii sont chargés chaque fois que des demandes de page sont effectuées. Nous utiliserons les scripts de message I18n de Yii pour créer un fichier de configuration pour I18n dans le commun / config chemin.

Depuis notre racine de base de code, nous allons lancer le Yii message / config scénario:

 ./ yii message / config @ common / config / i18n.php

Cela génère le modèle de fichier suivant que nous pouvons personnaliser:

 __DIR__, // array, required, liste des codes de langue dans lesquels les messages // extraits doivent être traduits. Par exemple, ['zh-CN', 'de']. 'languages' => ['de'], // string, le nom de la fonction de traduction des messages. // La valeur par défaut est 'Yii :: t'. Ceci est utilisé comme marque pour trouver les messages à // traduire. Vous pouvez utiliser une chaîne pour un seul nom de fonction ou un tableau pour // plusieurs noms de fonction. 'translator' => 'Yii :: t', // boolean, si les messages doivent être triés par clé lors de la fusion de nouveaux messages // avec les messages existants. La valeur par défaut est false, ce qui signifie que les nouveaux // messages (non traduits) seront séparés des anciens (traduits). 'sort' => false, // boolean, s'il faut supprimer les messages qui n'apparaissent plus dans le code source. // La valeur par défaut est false, ce qui signifie que chacun de ces messages sera entouré d'une paire de marques '@@'. 'removeUnused' => false, // array, liste des modèles qui spécifient quels fichiers / répertoires NE doivent PAS être traités. // Si vide ou non défini, tous les fichiers / répertoires seront traités. // Un chemin correspond à un modèle s'il contient la chaîne de modèle à sa fin. Par exemple, // '/ a / b' correspondra à tous les fichiers et répertoires se terminant par '/ a / b'; // le '* .svn' correspondra à tous les fichiers et répertoires dont le nom se termine par '.svn'. // et le '.svn' correspondra à tous les fichiers et répertoires nommés exactement '.svn'. // Remarque, les caractères '/' d'un motif correspondent à la fois à '/' et à '\'. // Voir la description de helpers / FileHelper :: findFiles () pour plus de détails sur les règles de correspondance de modèles. 'only' => ['* .php'], // array, liste de modèles spécifiant quels fichiers (et non pas les répertoires) doivent être traités. // Si vide ou non défini, tous les fichiers seront traités. // Veuillez vous référer à "sauf" pour plus de détails sur les motifs. // Si un fichier / répertoire correspond à la fois à un modèle dans "seulement" et "sauf", il ne sera PAS traité. 'sauf' => ['.svn', '.git', '.gitignore', '.gitkeep', '.hgignore', '.hgkeep', '/ messages',], // format de sortie 'php' est pour enregistrer des messages dans des fichiers php. 'format' => 'php', // répertoire racine contenant les traductions des messages. 'messagePath' => __DIR__. DIRECTORY_SEPARATOR. 'messages', // booléen, si le fichier de messages doit être remplacé par les messages fusionnés 'écraser' => true, / * // Le format de sortie 'db' sert à enregistrer les messages dans la base de données. 'format' => 'db', // composant de connexion à utiliser. Optionnel. 'db' => 'db', // Table de messages source personnalisée. Optionnel. // 'sourceMessageTable' => '%% source_message' ', // Nom personnalisé pour la table des messages de traduction. Optionnel. // 'messageTable' => '% message', * / / * // Le format de sortie 'po' sert à enregistrer les messages dans des fichiers po gettext. 'format' => 'po', // Répertoire racine contenant les traductions des messages. 'messagePath' => __DIR__. DIRECTORY_SEPARATOR. 'messages', // Nom du fichier qui sera utilisé pour les traductions. 'catalogue' => 'messages', // booléen, si le fichier de messages doit être écrasé par les messages fusionnés 'écraser' => true, * /]; 

Je personnalise mon dossier. je bouge messagePath jusqu'au sommet et personnaliser sourcePath et messagePath. Je spécifie également les langues que je souhaite utiliser dans mon application en plus de l'anglais, dans ce cas l'espagnol et l'allemand, "es" et "de". Voici une liste de tous les codes de langue I18n.

return [// chaîne, obligatoire, répertoire racine de tous les fichiers source 'sourcePath' => __DIR__. DIRECTORY_SEPARATOR. '…' DIRECTORY_SEPARATOR. '…' DIRECTORY_SEPARATOR, // Répertoire racine contenant les traductions des messages. 'messagePath' => __DIR__. DIRECTORY_SEPARATOR. '…'. DIRECTORY_SEPARATOR. 'messages', // tableau, obligatoire, liste des codes de langue dans lesquels les messages // extraits doivent être traduits. Par exemple, ['zh-CN', 'de']. 'languages' => ['es', 'de'],

Dans l'étape suivante, nous exécuterons le script d'extraction de Yii, qui analysera tout le code de la sourcePath tree pour générer des fichiers de chaîne par défaut pour toutes les étiquettes utilisées dans notre code. Je personnalise sourcePath pour analyser l’ensemble de l’arbre de code. Je personnalise messagePath générer les fichiers résultants dans commun / messages.

 ./ yii message / extract @ common / config / i18n.php

Vous verrez Yii analyser tous vos fichiers de code:

Extraction de messages de /Users/Jeff/Sites/mp/frontend/models/Place.php… Extraction de messages de /Users/Jeff/Sites/mp/frontend/models/PlaceGPS.php… Extraction de messages de / Users / Jefferson / Sites / mp / frontend / models / PlaceSearch.php… Extraction de messages de /Users/Jeff/Sites/mp/frontend/models/ResetPasswordForm.php… Extraction de messages de /Users/Jeff/Sites/mp/frontend/models/SignupForm.php…. Extraction de messages depuis /Users/Jeff/Sites/mp/frontend/views/layouts/main.php… Extraction de messages depuis /Users/Jeff/Sites/mp/frontend/views/meeting/_form.php… Extraction de messages depuis / Utilisateurs / Jeff / Sites / mp / frontend / views / meeting / _search.php… Extraction de messages de /Users/Jeff/Sites/mp/frontend/views/meeting/create.php… Extraction de messages de / Users / Jeff / Sites / mp / frontend / views / meeting / index.php… Extraction de messages de /Users/Jeff/Sites/mp/frontend/views/meeting/update.php… Extraction de messages de / Users / Jeff / Sites / mp / frontend / views / meeting / view.php… Extraction de messages m /Users/Jeff/Sites/mp/frontend/views/place/_form.php… Extraction de messages de /Users/Jeff/Sites/mp/front/views/place/_formGeolocate.php… Extraction de messages depuis / Utilisateurs / Jeff / Sites / mp / frontend / views / place / _formPlaceGoogle.php… Extraction de messages de /Users/Jeff/Sites/mp/frontend/views/place/_search.php… Extraction de messages de / Users / Jeff / Sites / mp / frontend / views / place / create.php… Extraction de messages de /Users/Jeff/Sites/mp/frontend/views/place/create_geo.php… Extraction de messages de / Users / Jeff / Sites / mp / frontend / views / place / create_place_google. php… Extraire les messages de /Users/Jeff/Sites/mp/frontend/views/place/index.php… Extraire les messages de /Users/Jeff/Sites/mp/frontend/views/place/locate.php… Extraire les messages de / Users / Jeff / Sites / mp / frontend / views / place / update.php… Extraction de messages de /Users/Jeff/Sites/mp/frontend/views/place/view.php… Extraction de messages de / Users / Jeff / Sites / mp / frontend / views / site / about.php… Extraction de messages f rom /Users/Jeff/Sites/mp/frontend/views/site/contact.php… Extraction de messages de /Users/Jeff/Sites/mp/frontend/views/site/error.php… Extraction de messages de / Users / Jeff / Sites / mp / frontend / views / site / index.php… Extraction de messages de /Users/Jeff/Sites/mp/frontend/views/site/login.php… Extraction de messages de / Users / Jeff / Sites / mp / frontend / views / site / requestPasswordResetToken.php… Extraction de messages de /Users/Jeff/Sites/mp/frontend/views/site/resetPassword.php… Extraction de messages de / Users / Jeff / Sites / mp / frontend / views / site / signup. php… Extraction de messages de /Users/Jeff/Sites/mp/frontend/web/index-test.php… Extraction de messages de /Users/Jeff/Sites/mp/frontend/web/index.php… Extraction de messages de / Utilisateurs / Jeff / Sites / mp / frontend / widgets / Alert.php… 

Une fois terminé, vous verrez quelque chose comme ceci dans votre base de code:

Activer I18n et sélectionner une langue

Dans le fichier de configuration commun, common / config / main.php, nous allons parler à Yii de notre nouveau support linguistique. Je ferai de l'espagnol ma langue par défaut:

 dirname (dirname (__ DIR__)). '/ vendor', 'language' => 'es', // espagnol 'composants' => ['cache' => ['class' => 'yii \ caching \ FileCache',], 'i18n' => [ 'translations' => ['frontend *' => ['class' => 'yii \ i18n \ PhpMessageSource', 'basePath' => '@ common / messages',], 'backend *' => ['class' => 'yii \ i18n \ PhpMessageSource', 'basePath' => '@ common / messages',],],],],]; 

Mais il reste encore beaucoup à faire. Nous devons rendre notre code I18n conscient.

Utilisation du générateur de code Gii de Yii avec I18n

Dans la deuxième partie de cette série, Construire son démarrage avec PHP: fonctionnalités requises et conception de base de données, nous avons utilisé le formidable générateur de code de Yii, Gii, pour générer nos modèles, nos contrôleurs et nos vues. Mais, nous n'avons pas activé I18n, donc toutes nos chaînes de texte incorporées dans le code. On refait ça.

Nous revenons à Gii, probablement http: // localhost: 8888 / mp / gii dans votre navigateur, puis relancez les générateurs de modèles et de contrôleurs avec I18n activé..

Remarque: Si vous avez suivi la troisième partie de notre série, vous devrez peut-être noter les différences entre chaque fichier et déplacer manuellement le code. Ou bien, il peut être plus simple de remplacer votre code par le référentiel Github de ce tutoriel, lié en haut à droite..

Voici un exemple de génération du code de modèle Meeting avec I18n activé. Notez que nous spécifions "l'extrémité avant" pour notre catégorie de message. Nous plaçons toutes nos chaînes de texte frontales dans un fichier de catégorie frontend. 

Faisons de même pour la génération CRUD des contrôleurs et des vues:

Si vous parcourez le code généré dans les modèles, les contrôleurs et les vues, vous verrez les chaînes de texte remplacées par Yii: t ('frontend',…) une fonction:

title = Yii :: t ('frontend', 'Places'); $ this-> params ['breadcrumbs'] [] = $ this-> title; ?> 

titre)?>

render ('_ search', ['model' => $ searchModel]); ?>

'Place',]), ['create'], ['class' => 'btn btn-success'])?> 'btn btn-success'])?> 'Place']), ['create_place_google'], ['class' => 'btn btn-success'])?>

Traduire vos fichiers de messages

Consultez notre fichier de messages en espagnol, /common/messages/es/frontend.php. C'est une longue liste de valeurs de tableau vides:

return ['Add Current Location' => "," Ajouter un Google modelClass "=>", "Êtes-vous sûr de vouloir supprimer cet élément? ' => ", 'Create' =>", 'Create modelClass' => ", 'Créé à' =>", 'Créé par' => ", 'Delete' =>", 'Full Address' => ", 'Google Place ID' =>", "ID" => "," Type de réunion "=>", "Réunions" => "," Message "=>", "Nom" => "," Notes " => ", 'Owner ID' =>", 'Type de lieu' => ", 'Lieux' =>", 'Réinitialiser' => ", 'Rechercher' =>", 'Slug' => ", 'Statut '=> ",' Update '=>", "Update modelClass:" => "," Mis à jour à "=>", "Vicinity" => "," Website "=>",];

Afin de compléter nos traductions en espagnol pour ce tutoriel, je vais utiliser Google Translate. Tricky, hein?

Ensuite, nous ferons du copier-coller avec ces traductions dans le fichier de messages.. 

return ['Add Current Location' => 'Ajouter un lieu actuel', 'Ajouter un Google modelClass' => 'Añadir un Google modelClass', 'Créé par' => 'Creado por', 'Adresse complète' = > 'Dirección completa', 'Google Place ID' => 'Google Place ID', 'Nom' => 'Nombre', 'Notes' => 'Notas', 'Type de lieu' => 'Place Tipo', 'Lieux '=>' Lugares ',' Slug '=>' Slug ',' Vicinity '=>' Alrededores ',' Website '=>' Sitio Web ',' Êtes-vous sûr de vouloir supprimer cet élément? ' => 'Vous voulez que les choses soient faites?', 'Créer' => 'Crear', 'Create modelClass' => 'Crear Lugar', 'Created At' => 'Creado El', 'Supprimer' => 'Eliminar', 'ID' => 'ID', 'Type de réunion' => 'Type de réunion', 'Réunions' => 'Encuentros', 'Message' => 'Mensaje', 'Propriétaire ID' = > 'Propietario ID', 'Reset' => 'Reset', 'Search' => 'Buscar', 'Status' => 'Estado', 'Update' => 'Actualizar', 'Update modelClass:' = > 'Actualizar Lugar', 'Updated At' => 'Actualización A',];

Lorsque nous visitons la page d’index Place, vous verrez la version espagnole-nice, hein?

Notez que la barre de navigation reste en anglais, car le script Message / Extract n’a pas récupéré les définitions du tableau de navigation Bootstrap et les a converties en utilisant Yii: t (). Nous allons le faire à la main. Notez également que le texte de Home et de pagination a été traduit automatiquement. La base de code de Yii inclut des traductions dans la langue de ces chaînes standard..

Ici se trouve le Créer un lieu forme:

Si je veux repasser en anglais, je modifie simplement le fichier de configuration, /common/main.php, retour en anglais:

 dirname (dirname (__ DIR__)). '/ vendor', 'language' => 'en', // anglais // 'language' => 'es', // espagnol

Vous remarquerez également au fur et à mesure que vous procédez que le remplacement de chaînes en JavaScript a ses propres complexités. Je ne l’ai pas exploré moi-même, mais l’extension Yii 1.x JsTrans peut servir de guide utile pour soutenir cette.

Aller plus loin avec I18n

En fin de compte, nous voudrons peut-être traduire notre application dans un certain nombre de langues. J'ai posté une demande de fonctionnalité Yii pour étendre le script Message / Extrait afin d'utiliser l'API Google Translate pour automatiser ce processus. J'ai aussi demandé à Tuts + de me laisser écrire un tutoriel à ce sujet, alors restez à l'écoute. Bien sûr, cela fournit juste une traduction de base. Vous voudrez peut-être engager des traducteurs professionnels pour ajuster les fichiers par la suite.

Certaines applications permettent aux utilisateurs de sélectionner leur langue maternelle afin que, lorsqu'ils se connectent, l'interface utilisateur traduise automatiquement pour eux. Dans Yii, régler le $ app-> langue la variable fait ceci:

\ Yii :: $ app-> language = 'es';

D'autres applications, telles que JScrambler.com ci-dessous, exploitent le chemin de l'URL pour changer de langue. L’utilisateur clique simplement sur le préfixe de la langue qu’il souhaite, par exemple. "FR", et l'application est automatiquement traduite: 

Note: regarder ma page instructeurs Tuts + pour un prochain tutoriel sur JScrambler, c’est un service très utile. Il est peut-être déjà apparu au moment où vous lisez ceci.

Le gestionnaire d'URL de Yii peut également fournir ce type de fonctionnalité. Je vais probablement implémenter ces fonctionnalités pour Meeting Planner dans un futur tutoriel.

Et après?

J'espère que vous avez appris quelque chose de nouveau avec ce tutoriel. J'avais déjà utilisé I18n avec Rails, mais c'était la première fois que je l'implémentais avec PHP. Surveillez les prochains tutoriels dans notre rubrique Construire votre démarrage avec la série PHP: de nombreuses fonctionnalités amusantes sont à venir..

N'hésitez pas à ajouter vos questions et commentaires ci-dessous; Je participe généralement aux discussions. Vous pouvez également me joindre sur Twitter @reifman ou m'envoyer un email directement.

Liens connexes

  • Programmation avec Yii2: Mise en route
  • Introduction au framework Yii
  • Le guide définitif Yii2: Internationalisation