Construirea sistemului de pornire cu PHP Localizare cu I18n

Ce veți crea

Aceasta este partea a patra a programului Build Your Startup With PHP pe Tuts +. În această serie, vă conduc prin lansarea unei lansări de la concept la realitate utilizând aplicația mea Planificator de întâlniri ca exemplu de viață reală. Fiecare pas de-a lungul drumului, vom lansa codul Planificatorului de întâlniri ca exemple de sursă deschisă pe care le puteți învăța. Vom aborda, de asemenea, problemele de afaceri legate de pornire în momentul în care apar.

În acest tutorial, am vrut să renunț și să adaug sprijin pentru internaționalizare I18n aplicației noastre înainte să construim un cod din ce în ce mai mare. Potrivit Wikipedia, I18n este un numeron:

18 reprezintă numărul de litere dintre primul eu și ultimul n în internaționalizare, o utilizare inventată la DEC în anii '70 sau '80.

Cu I18n, toate șirurile de text afișate utilizatorului din aplicație sunt înlocuite de apeluri de funcții care pot încărca dinamic șiruri translate pentru orice limbă pe care utilizatorul o selectează.

Întregul cod pentru Planificatorul întâlnirilor este scris în cadrul Yii2 Framework for PHP, care are suport integrat pentru I18n. Dacă doriți să aflați mai multe despre Yii2, consultați seria noastră paralelă Programming With Yii2 de la Tuts+.

Doar un memento, eu particip la comentariile de mai jos. Sunt interesat în special dacă aveți abordări diferite sau idei suplimentare sau doriți să sugerați subiecte pentru tutoriale viitoare.

Obiectivele internaționalizării

Când construiți o pornire, este util să gândiți la nivel global de la început - dar nu întotdeauna. În mod alternativ, este posibil să se concentreze numai pe construirea pieței dvs. locale. Produsul dvs. minim viabil trebuie să funcționeze în alte limbi pentru utilizatorii din diferite țări?

În cazul nostru, cadrul Yii oferă suport integrat pentru I18n, deci este relativ ușor să construiți suport pentru I18n de la început și consumatoare de timp pentru al adăuga mai târziu.

Cum funcționează I18n

I18n funcționează înlocuind toate referințele la text afișate utilizatorului cu apeluri de funcții care asigură traducerea atunci când este necesar. 

De exemplu, iată ce arată numele câmpului atributului în modelul Place, înainte de I18n:

funcția publică funcțiaLabels () return ['id' => 'ID', 'name' => 'Nume', 'place_type' => 'Tipul locului', ... 

Furnizarea de versiuni traduse ale codului ar deveni foarte complicată. Traducătorii non-tehnici ar trebui să traducă codul în loc, probabil sintaxa de rupere.

Iată ce arată același cod cu I18n:

funcția publică funcțiaLabels () return 'id' => Yii :: t ('frontend', 'ID'), 'name' => Yii :: t (' > Yii :: t ('frontend', 'Place Type'),

Yii: t () este o funcție de apeluri care verifică ce limbă este selectată în prezent și afișează șirul corespunzător tradus. 'în față' se referă la o secțiune a aplicației noastre. Traducerile pot fi organizate opțional în funcție de diferite categorii. Dar, unde apar aceste șiruri traduse? 

Limba implicită, în acest caz limba engleză, este scrisă în cod, după cum se arată mai sus. Fișierele cu resurse lingvistice sunt liste de tablouri de caractere ale căror cheie este textul lingvistic implicit, de ex. "Tip loc"-și fiecare fișier furnizează valori text traduse pentru limba corespunzătoare.

Iată un exemplu al fișierului de traducere spaniol completat, codul de limbă "es". Yii: t () funcția folosește acest fișier pentru a găsi traducerea corespunzătoare pentru a afișa:

 'Agregar ubicación actual', 'Adăugați Google modelClass' => 'Añadir un Google modelClass', 'Creat de' => 'Creado por', 'Full Address' ID '=>' Locația Tipo ',' Locurile '=>' Lugares ',',

În timp ce acest lucru pare a consuma timp, Yii oferă scripturi pentru a automatiza generarea și organizarea acestor fișiere. 

Prin separarea textului de cod, facem mai ușoară ca experții non-tehnici multilingvi să traducă aplicațiile noastre pentru noi - fără a sparge codul.

I18n oferă, de asemenea, funcții specializate pentru traducerea timpului, valutei, plurals et al. Nu voi intra în detalii despre acestea în acest tutorial. 

Configurarea suportului I18n

Din păcate, documentația Yii2 pentru I18n nu este încă foarte descriptivă - și a fost dificil să găsim lucruri, exemple pas cu pas. Din fericire pentru tine, o să te trec prin ceea ce am învățat de la spălarea documentelor și a web-ului. Am găsit exemplul I18n al Codului Ninja și Ghidul definitiv Yii2 pe I18n, iar contribuitorul Yii Alexander Makarov mi-a oferit asistență și.

Generarea fișierului de configurare I18n

Utilizăm șablonul avansat Yii2 pentru Planificatorul de întâlniri. Acest lucru creează două aplicații Yii în baza noastră de cod, frontend și backend. Și creează o zonă comună pentru modelele partajate între cele două aplicații. Fișierele de configurare ale lui Yii sunt încărcate ori de câte ori se fac solicitări de pagină. Vom folosi scripturile mesajului I18n pentru a construi un fișier de configurare pentru I18n în comună / config cale.

Din radacina codbasei noastre, vom rula Yii Mesaj / config script:

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

Aceasta generează următorul șablon de fișier pe care îl putem personaliza:

 __DIR__, // array, required, listă de coduri de limbă pe care mesajele extrase // ar trebui să fie traduse la. De exemplu, ['zh-CN', 'de']. 'languages' => ['de'], // string, numele funcției pentru traducerea mesajelor. // Valoare implicită la 'Yii :: t'. Acesta este folosit ca un semn pentru a găsi mesajele care urmează să fie // traduse. Puteți utiliza un șir pentru numele unei singure funcții sau o matrice pentru // nume de funcții multiple. 'translator' => 'Yii :: t', // boolean, dacă doriți să sortați mesajele prin chei atunci când îmbinați mesajele noi // cu cele existente. Implicit la false, ceea ce înseamnă că mesajele noi (netranslate) // vor fi separate de cele vechi (traduse). 'sort' => false, // boolean, dacă doriți să eliminați mesajele care nu mai apar în codul sursă. // Defaults to false, ceea ce înseamnă că fiecare dintre aceste mesaje va fi închis cu o pereche de "@@" mărci. 'removeUnused' => false, // array, lista modelelor care specifică care fișiere / directoare NU trebuie procesate. // Dacă este gol sau nu, toate fișierele / directoarele vor fi procesate. // Un traseu se potrivește cu un șablon dacă conține șirul de model la sfârșitul acestuia. De exemplu, // '/ a / b' se va potrivi cu toate fișierele și directoarele care se termină cu '/ a / b'; // '* .svn' se va potrivi cu toate fișierele și directoarele al căror nume se termină cu '.svn'. // și ".svn" se vor potrivi cu toate fișierele și directoarele numite exact ".svn". // Notă, caracterele "/" dintr-un model se potrivesc atât cu "/", cât și cu "\". // Vezi descrierea helpers / FileHelper :: findFiles () pentru mai multe detalii despre regulile de potrivire a modelului. 'only' => ['* .php'], // array, lista modelelor care specifică care fișiere (nu directoare) ar trebui procesate. // Dacă este gol sau nu este setat, toate fișierele vor fi procesate. // Vă rugăm să consultați "excepție" pentru detalii despre modele. // Dacă un fișier / director se potrivește atât cu un model în "numai", și "cu excepția", acesta NU va fi procesat. 'excepție' => ['.svn', '.git', '.gitignore', '.gitkeep', '.hgignore', '.hgkeep', '/ messages',], // ' este pentru salvarea mesajelor în fișiere php. 'format' => 'php', // Director rădăcină care conține traduceri de mesaje. 'messagePath' => __DIR__. DIRECTORY_SEPARATOR. 'messages', // boolean, dacă fișierul de mesaj trebuie suprascris cu mesajul "overwrite" => true, / * // 'db' pentru mesajele îmbinate este pentru salvarea mesajelor în baza de date. 'format' => 'db', // Componenta de conectare de utilizat. Opțional. 'db' => 'db', // Tabela de mesaje personalizate. Opțional. // 'sourceMessageTable' => '% source_message', // Numele personalizat pentru tabelul cu mesaje de traducere. Opțional. // 'messageTable' => 'Formatul de ieșire' % message ', * / / * //' po 'este pentru salvarea mesajelor în fișierele gettext po. 'format' => 'po', // director rădăcină care conține traduceri de mesaje. 'messagePath' => __DIR__. DIRECTORY_SEPARATOR. 'messages', // Numele fișierului care va fi folosit pentru traduceri. 'catalog' => 'mesaje', // boolean, dacă fișierul de mesaj trebuie suprascris cu suprascrierea mesajelor îmbinate '=> true, * /]; 

Îmi personalizez dosarul. ma mut messagePath până în partea de sus și personalizați sourcePath și messagePath. De asemenea, precizez limbile în care vreau să-mi susțin cererea în afara limbii engleze - în acest caz spaniolă și germană, "es" și "de". Iată o listă a tuturor codurilor de limbă I18n.

returnați [// string, necesar, directorul rădăcină al tuturor fișierelor sursă "sourcePath" => __DIR__. DIRECTORY_SEPARATOR. "...". DIRECTORY_SEPARATOR. "...". DIRECTORY_SEPARATOR, // Directorul rădăcină care conține traduceri de mesaje. 'messagePath' => __DIR__. DIRECTORY_SEPARATOR. "...". DIRECTORY_SEPARATOR. 'messages', // array, required, listă de coduri de limbă pe care mesajele extrase // ar trebui să fie traduse la. De exemplu, ['zh-CN', 'de']. 'limbi' => ['es', 'de'],

În pasul următor, vom executa scriptul de extragere al lui Yii, care va scana tot codul în sourcePath copac pentru a genera fișiere de șir implicite pentru toate etichetele utilizate în codul nostru. Sunt personalizat sourcePath pentru a scana întregul arbore de cod. Sunt personalizat messagePath pentru a genera fișierele rezultate în comune / mesaje.

 ./ yii mesaj / extras @ common / config / i18n.php

Veți vedea Yii scanând toate fișierele de cod:

Extragerea mesajelor din /Users/Jeff/Sites/mp/frontend/models/Place.php ... Extragerea mesajelor din /Users/Jeff/Sites/mp/frontend/models/PlaceGPS.php ... Extragerea mesajelor de la / Users / Jeff / Sites / mp / frontend / models / PlaceSearch.php ... Extragerea mesajelor din /Users/Jeff/Sites/mp/frontend/models/ResetPasswordForm.php ... Extragerea mesajelor din /Users/Jeff/Sites/mp/frontend/models/SignupForm.php... Extragerea mesajelor din /Users/Jeff/Sites/mp/frontend/views/layouts/main.php ... Extragerea mesajelor din /Users/Jeff/Sites/mp/frontend/views/meeting/_form.php ... Extragerea mesajelor din / Users / Jeff / Sites / mp / frontend / views / meeting / _search.php ... Extragerea mesajelor din /Users/Jeff/Sites/mp/frontend/views/meeting/create.php ... Extragerea mesajelor de la / Users / Jeff / Sites / mp / frontend / views / meeting / index.php ... Extragerea mesajelor din /Users/Jeff/Sites/mp/frontend/views/meeting/update.php ... Extragerea mesajelor din / Users / Jeff / Sites / mp / frontend / views / meeting / view.php ... Extragerea mesajelor de la m /Users/Jeff/Sites/mp/frontend/views/place/_form.php... Extragerea mesajelor din /Users/Jeff/Sites/mp/frontend/views/place/_formGeolocate.php ... Extragerea mesajelor de la / Users / Jeff / Site-uri / mp / frontend / views / place / _formPlaceGoogle.php ... Extragerea mesajelor din /Users/Jeff/Sites/mp/frontend/views/place/_search.php ... Extragerea mesajelor din / Users / Jeff / Sites / mp / frontend / view / place / create.php ... Extragerea mesajelor din /Users/Jeff/Sites/mp/frontend/views/place/create_geo.php ... Extragerea mesajelor din / Users / Jeff / Sites / mp / frontend / views / place / create_place_google. php ... Extragerea mesajelor din /Users/Jeff/Sites/mp/frontend/views/place/index.php ... Extragerea mesajelor din /Users/Jeff/Sites/mp/frontend/views/place/locate.php ... Extragerea mesajelor din / Utilizatorii / Jeff / Sites / mp / frontend / views / place / update.php ... Extragerea mesajelor de la /Users/Jeff/Sites/mp/frontend/views/place/view.php ... Extragerea mesajelor de la / Users / Jeff / Sites / mp / frontend / views / site / about.php ... Extragerea mesajelor f rom /Users/Jeff/Sites/mp/frontend/views/site/contact.php ... Extragerea mesajelor din /Users/Jeff/Sites/mp/frontend/views/site/error.php ... Extragerea mesajelor din / Users / Jeff / Site-uri / mp / frontend / views / site / index.php ... Extragerea mesajelor din /Users/Jeff/Sites/mp/frontend/views/site/login.php ... Extragerea mesajelor de la / Users / Jeff / Sites / mp / frontend / vizualizări / site / requestPasswordResetToken.php ... Extragerea mesajelor din /Users/Jeff/Sites/mp/frontend/views/site/resetPassword.php ... Extragerea mesajelor de la / Users / Jeff / Sites / mp / frontend / views / site / signup. php ... Extragerea mesajelor din /Users/Jeff/Sites/mp/frontend/web/index-test.php ... Extragerea mesajelor din /Users/Jeff/Sites/mp/frontend/web/index.php ... Extragerea mesajelor din / Users / Jeff / Site-uri / mp / front-end / widget-uri / Alert.php ... 

După ce se termină, veți vedea ceva de genul acesta în codul dvs. de bază:

Activarea I18n și selectarea unei limbi

În fișierul de configurare obișnuit, comună / config / main.php, o să-i spunem lui Yii despre noul nostru suport lingvistic. Voi face limba spaniolă limba mea implicită:

 dirname (dirname (__ DIR__)). '/' ['class' => 'yii \ caching \ FileCache',], 'i18n' => [[ 'backend' => ['class' => 'yii \ i18n \ PhpMessageSource', 'basePath' => 'common' => 'yii \ i18n \ PhpMessageSource', 'basePath' => '@ comun / mesaje',],],],],]; 

Dar mai sunt încă multe de făcut. Trebuie să conștientizăm codul nostru.

Utilizând generatorul de cod Gii al lui Yii cu I18n

În partea a doua a acestei serii, Construirea sistemului de pornire cu PHP: Cerințe de bază și proiectare baze de date, am folosit generatorul de cod Yii, Gii, pentru a genera modelele, controlorii și opiniile noastre. Dar, nu am activat I18n, deci toate codurile de text încorporate în text. Să refacem asta.

Ne întoarcem la Gii, probabil http: // localhost: 8888 / mp / gii în browserul dvs. și re-executați generatoarele de model și controler cu I18n activat.

Notă: Dacă ați ținut pasul cu partea a treia a seriei noastre, este posibil să fie necesar să notați diferențele cu fiecare fișier și să mutați manual codul. Sau, poate fi mai ușor să înlocuiți codul cu depozitul Github pentru acest tutorial, legat la dreapta sus.

Iată un exemplu de generare a codului modelului Meeting cu I18n activat. Observați că specificăm "în față" pentru categoria noastră de mesaje. Introducem toate șirurile de text frontend într-un fișier de categorie frontală. 

Să facem același lucru pentru generația CRUD pentru controlori și vizualizări:

Dacă răsfoiți codul generat în modele, controale și vizualizări, veți vedea cărurile de text înlocuite cu Yii: t ("frontend", ...) funcţie:

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

titlu)?>

render ('_ căutare', ['model' => $ searchModel]); ?>

'Place',]), ['crea'], ['class' => 'btn btn-succes']) "btn btn-succes"])>> 'Place']), ['create_place_google'], ['class' => 'btn btn-success'])

Traducerea fișierelor dvs. de mesaje

Aruncati o privire la fisierul nostru de mesaj spaniol, /common/messages/es/frontend.php. Este o listă lungă de valori de matrice goale:

întoarceți ['Adăugați locația curentă' => ',' Adăugați Google modelClass '=> "Sigur doriți să ștergeți acest articol?" = "", "Creare" => "", "Creare" => "," ID de locație Google "=>", "ID" => "," Tip de întâlnire "=> => "," Locația "=>", "Reset" => "," Căutare "=> '=>', 'Actualizare' => ',' Actualizare modelClass: '=>', 'Actualizat la' => ';

În scopul completării traducerilor în limba spaniolă pentru acest tutorial, voi folosi Google Translate. Drăguț, huh?

Apoi, vom face niște tăieturi și lipi cu aceste traduceri înapoi în fișierul de mesaje. 

retur ['Adăugați locația curentă' => 'Agregar ubicación actual', 'Adăugați Google modelClass' => 'Creado por', 'Full Address' = = > 'Dirección completa', 'Google Place ID' => 'Locația Google Loc', 'Nume' => 'Nombre', 'Notes' => '=>' Sireo Web ',' Sigur vrei să ștergi acest element? '=>' Lugares ',' Slug '=>' Slug ',' Vicinity '=>' Alrededores ',' Website '=>' = "'Creat' => 'Crear', 'Creare modelClass' => 'Crear Lugar', 'Creat la' => 'Eliminar', 'ID' => 'ID', 'Tip de întâlnire' => 'Tipo de Reunión', 'Meetings' => 'Encuentros', 'Message' => > 'Actualizar', 'Update modelClass:' = 'Reset' => 'Reset' > "Actualizar Lugar", "Actualizat la '=>' Actualización A ',];

Atunci când vizităm pagina de index a locației, veți vedea versiunea spaniolă - frumos, nu?

Observați că bara de navigare rămâne în limba engleză - aceasta deoarece scriptul Message / Extract nu a ridicat definițiile de navigare Bootstrap și le-a convertit la utilizarea Yii: t (). O vom face cu mâna. De asemenea, observați că textul Acasă și de paginare a fost tradus automat - codul de bază al lui Yii include traducerile de limbă pentru aceste șiruri standard.

Iată-l Creați un loc formă:

Dacă vreau să mă întorc în engleză, schimb doar fișierul de configurare, /common/main.php, înapoi la limba engleză:

 dirname (dirname (__ DIR__)). '/ vânzător', 'limbă' => 'en', // english // 'limbă' => 'es', // spaniolă

Veți observa, de asemenea, pe măsură ce procedați că înlocuirea șirurilor în JavaScript are propriile sale complexități. Nu am analizat-o singură, dar extinderea Yii 1.x JsTrans poate oferi o îndrumare utilă pentru susținerea acestui lucru.

Mergând mai departe cu I18n

În cele din urmă, este posibil să dorim să traducem aplicația noastră într-un număr de limbi. Am postat o solicitare de caracteristică Yii pentru a extinde scriptul Message / Extract pentru a utiliza API-ul Google Translate, pentru a automatiza acest proces. De asemenea, l-am rugat pe Tuts + să mă lase să scriu un tutorial despre asta, deci stați liniștit. Desigur, aceasta oferă doar o traducere de bază. Poate doriți să angajați traducători profesioniști pentru a regla fișierele ulterior.

Unele aplicații permit utilizatorilor să selecteze limba lor maternă, astfel încât atunci când se conectează, interfața cu utilizatorul se traduce automat pentru ei. În Yii, setarea $ App-> limba variabilă face acest lucru:

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

Alte aplicații, cum ar fi JScrambler.com de mai jos, utilizează calea URL pentru a schimba limbile. Utilizatorul doar face clic pe prefixul de limbă dorit, de ex. "FR", iar aplicația este tradusă automat: 

Notă: Uita-te pagina mea Tuts + instructor pentru un tutorial viitoare despre JScrambler - este un serviciu destul de util. S-ar putea să fi apărut deja când ați citit acest lucru.

Managerul de adrese Yii poate oferi și acest tip de funcționalitate. Voi implementa, probabil, aceste caracteristici pentru Planificatorul întâlnirilor într-un viitor tutorial.

Ce urmeaza?

Sper că ați învățat ceva nou cu acest tutorial. Am folosit I18n cu Rails înainte - dar aceasta a fost prima dată când l-am implementat cu PHP. Uita-te pentru tutoriale viitoare în construirea dvs. de pornire cu seria PHP-există o mulțime de caracteristici distractive vine.

Vă rugăm să nu adăugați întrebările și comentariile de mai jos; În general, particip la discuții. Puteți să mă contactați și pe Twitter @reifman sau să mă trimiteți direct prin e-mail.

Link-uri conexe

  • Programarea cu Yii2: Noțiuni de bază
  • Introducere în Cadrul Yii
  • Ghidul definitiv Yii2: Internaționalizarea
Cod