Dit is deel vier van de Building Your Startup With PHP-serie op Tuts +. In deze serie begeleid ik je door een opstart van concept naar realiteit te starten met behulp van mijn Meeting Planner-app als een echt voorbeeld. Bij elke stap zullen we de Meeting Planner-code vrijgeven als open source-voorbeelden waar u van kunt leren. We zullen ook opstartgerelateerde zakelijke problemen aanpakken zodra deze zich voordoen.
In deze zelfstudie wilde ik een stap terug doen en I18n-ondersteuning voor internationalisatie toevoegen aan onze applicatie voordat we meer en meer code bouwen. Volgens Wikipedia is I18n een numeroniem:
18 staat voor het aantal letters tussen de eerste letters ik en als laatste n in internationalisering, een gebruik gemunt op DEC in de jaren 70 of 80.
Met I18n worden alle tekenreeksen die door de toepassing aan de gebruiker worden getoond, vervangen door functieaanroepen die vertaalde reeksen dynamisch kunnen laden voor elke taal die de gebruiker selecteert.
Alle code voor Meeting Planner is geschreven in het Yii2 Framework voor PHP, die ingebouwde ondersteuning voor I18n heeft. Als je meer wilt weten over Yii2, bekijk dan onze parallelle serie Programming With Yii2 at Tuts+.
Ter herinnering, ik neem wel deel aan de commentaarthreads hieronder. Ik ben vooral geïnteresseerd als je verschillende benaderingen of aanvullende ideeën hebt, of onderwerpen wilt voorstellen voor toekomstige zelfstudies.
Bij het bouwen van een startup is het nuttig om vanaf het begin globaal te denken, maar niet altijd. Als alternatief kan het zinvol zijn om u alleen te richten op het bouwen voor uw lokale markt. Moet uw minimaal haalbare product in andere talen werken voor gebruikers uit verschillende landen?
In ons geval biedt het Yii Framework ingebouwde ondersteuning voor I18n, dus het is relatief eenvoudig om vanaf het begin ondersteuning voor I18n te bouwen - en tijdrovend om het later toe te voegen.
I18n werkt door alle verwijzingen naar tekst die aan de gebruiker wordt getoond te vervangen door functieaanroepen die zorgen voor vertaling wanneer dat nodig is.
Dit is bijvoorbeeld wat de namen van het kenmerkveld in het model Place zien vóór I18n:
public function attributeLabels () return ['id' => 'ID', 'name' => 'Naam', 'place_type' => 'Plaatstype', ...
Het leveren van vertaalde versies van de code zou erg ingewikkeld worden. Niet-technische vertalers zouden de code moeten vertalen, waarschijnlijk de syntaxis.
Hier is hoe dezelfde code eruit ziet met I18n:
public function attributeLabels () return ['id' => Yii :: t ('frontend', 'ID'), 'name' => Yii :: t ('frontend', 'Name'), 'place_type' = > Yii :: t ('frontend', 'Place Type'),
Yii: t ()
is een functieaanroep die controleert welke taal momenteel is geselecteerd en geeft de juiste vertaalde reeks weer. 'voorkant'
verwijst naar een deel van onze applicatie. Vertalingen kunnen naar keuze in verschillende categorieën worden georganiseerd. Maar waar verschijnen deze vertaalde reeksen?
De standaardtaal, in dit geval Engels, wordt in de code geschreven, zoals hierboven weergegeven. Taalresourcebestanden zijn lijsten met arrays van reeksen waarvan de sleutel de standaardtaal is - bijv. 'Plaatstype'-en elk bestand biedt vertaalde tekstwaarden voor de juiste taal.
Hier is een voorbeeld van ons voltooide Spaanse vertaalbestand, taalcode "es". De Yii: t ()
functie gebruikt dit bestand om de juiste vertaling te vinden om weer te geven:
'Agregar ubicación actual', 'Voeg een Google toe modelClass' = 'Añadir un Google modelClass', 'Gecreëerd door' => 'Creado por', 'Volledig adres' => 'Dirección completa', 'Google Place ID '=>' Google Plaats ID ',' Naam '=>' Nombre ',' Notities '=>' Notas ',' Plaats Type '=>' Plaats Tipo ',' Plaatsen '=>' Lugares ',
Hoewel dit tijdrovend lijkt, biedt Yii scripts om de generatie en organisatie van deze bestanden te automatiseren.
Door de tekst van de code te scheiden, maken we het eenvoudiger voor niet-technische meertalige experts om onze applicaties voor ons te vertalen - zonder de code te overtreden.
I18n biedt ook gespecialiseerde functies voor het vertalen van tijd, valuta, meervoudsvormen en andere. Ik zal hier niet in detail op ingaan in deze tutorial.
Helaas is de Yii2-documentatie voor I18n nog niet erg beschrijvend - en het was moeilijk om werkbare, stapsgewijze voorbeelden te vinden. Gelukkig voor jou, zal ik je laten doorlopen wat ik heb geleerd van het doorzoeken van de documenten en het web. Ik vond het I18n-voorbeeld van de Code Ninja en de Yii2 Definitive Guide on I18n nuttig, en Yii-medewerker Alexander Makarov bood me ook wat hulp aan.
We gebruiken de geavanceerde Yii2-sjabloon voor vergaderplanner. Dit creëert twee Yii-applicaties in onze codebase, frontend en backend. En, het creëert een gemeenschappelijke ruimte voor modellen die worden gedeeld tussen beide toepassingen. De configuratiebestanden van Yii worden geladen wanneer er pagina-aanvragen worden gedaan. We zullen de I18n-berichtenscripts van Yii gebruiken om een configuratiebestand voor I18n uit te bouwen in de common / config
pad.
Van onze codebasiswortel, zullen we de Yii draaien message / config
script:
./ yii message / config @ common / config / i18n.php
Dit genereert de volgende bestandssjabloon die we kunnen aanpassen:
__DIR__, // array, vereist, lijst met taalcodes waarmee de uitgepakte berichten // moeten worden vertaald. Bijvoorbeeld ['zh-CN', 'de']. 'languages' => ['de'], // string, de naam van de functie voor het vertalen van berichten. // Standaard ingesteld op 'Yii :: t'. Dit wordt gebruikt als een markering om de berichten / // vertaald te vinden. U kunt een tekenreeks gebruiken voor een enkele functienaam of een array voor // meerdere functienamen. 'vertaler' => 'Yii :: t', // boolean, of berichten moeten worden gesorteerd op sleutels bij het samenvoegen van nieuwe berichten // met de bestaande berichten. De standaardinstelling is false, wat betekent dat de nieuwe (niet-vertaalde) // berichten gescheiden zijn van de oude (vertaalde) berichten. 'sort' => false, // boolean, of berichten moeten worden verwijderd die niet meer in de broncode voorkomen. // Standaard ingesteld op false, wat betekent dat elk van deze berichten wordt ingesloten met een paar '@@'-markeringen. 'removeUnused' => false, // array, lijst met patronen die aangeven welke bestanden / mappen NIET moeten worden verwerkt. // Als het leeg is of niet is ingesteld, worden alle bestanden / mappen verwerkt. // Een pad komt overeen met een patroon als het de patroonreeks aan het einde bevat. Bijvoorbeeld, // '/ a / b' komt overeen met alle bestanden en mappen die eindigen op '/ a / b'; // de '* .svn' komt overeen met alle bestanden en mappen waarvan de naam eindigt met '.svn'. // en de '.svn' komt overeen met alle bestanden en mappen met de naam '.svn'. // Let op, de '/' tekens in een patroon komen overeen met '/' en '\'. // Zie helpers / FileHelper :: findFiles () beschrijving voor meer informatie over patroonovereenkomstregels. 'alleen' => ['* .php'], // array, lijst met patronen die aangeven welke bestanden (geen mappen) moeten worden verwerkt. // Als het leeg is of niet is ingesteld, worden alle bestanden verwerkt. // Raadpleeg "behalve" voor meer informatie over de patronen. // Als een bestand / map overeenkomt met zowel een patroon in "alleen" als "behalve", wordt het NIET verwerkt. 'except' => ['.svn', '.git', '.gitignore', '.gitkeep', '.hgignore', '.hgkeep', '/ messages',], // 'php' uitvoerformaat is voor het opslaan van berichten naar php-bestanden. 'format' => 'php', // Rootdirectory met berichtenvertalingen. 'messagePath' => __DIR__. DIRECTORY_SEPARATOR. 'messages', // boolean, of het berichtbestand moet worden overschreven met het 'overschrijf' => true, / * // 'db' uitvoerformaat van de samengevoegde berichten dient om berichten in de database op te slaan. 'format' => 'db', // Verbindingscomponent om te gebruiken. Optioneel. 'db' => 'db', // Aangepaste bronberichtentabel. Optioneel. // 'sourceMessageTable' => '% source_message' // Aangepaste naam voor tabel met vertaalboodschappen. Optioneel. // 'messageTable' => '% message', * / / * // 'po' uitvoerindeling is voor het opslaan van berichten naar tekst-po-bestanden. 'format' => 'po', // Hoofddirectory met berichtenvertalingen. 'messagePath' => __DIR__. DIRECTORY_SEPARATOR. 'berichten', // Naam van het bestand dat zal worden gebruikt voor vertalingen. 'catalogus' => 'berichten', // boolean, of het berichtbestand moet worden overschreven met de samengevoegde berichten 'overschrijven' => waar, * /];
Ik ben mijn bestand aan het aanpassen. ik beweeg messagePath
naar de top en aanpassen SourcePath
en messagePath
. Ik specificeer ook de talen die ik wil dat mijn applicatie ondersteunt, naast Engels, in dit geval Spaans en Duits, 'es' en 'de'. Hier is een lijst met alle I18n-taalcodes.
return [// string, required, root directory of all source files 'sourcePath' => __DIR__. DIRECTORY_SEPARATOR. '...'. DIRECTORY_SEPARATOR. '...'. DIRECTORY_SEPARATOR // Rootdirectory met berichtvertalingen. 'messagePath' => __DIR__. DIRECTORY_SEPARATOR. '...'. DIRECTORY_SEPARATOR. 'messages', // array, vereist, lijst met taalcodes waar de uitgepakte berichten // naartoe moeten worden vertaald. Bijvoorbeeld ['zh-CN', 'de']. 'talen' => ['es', 'de'],
In de volgende stap gebruiken we het extract-script van Yii, dat alle code in het script zal scannen SourcePath
boom om standaard stringbestanden te genereren voor alle labels die in onze code worden gebruikt. Ik ben aan het aanpassen SourcePath
om de volledige codestructuur te scannen. Ik ben aan het aanpassen messagePath
om de resulterende bestanden in te genereren common / berichten
.
./ yii message / extract @ common / config / i18n.php
Je ziet Yii al je codebestanden scannen:
Extraheren van berichten van /Users/Jeff/Sites/mp/frontend/models/Place.php... Extraheren van berichten van /Users/Jeff/Sites/mp/frontend/models/PlaceGPS.php... Extracten van berichten van / Users / Jeff / Sites / mp / frontend / models / PlaceSearch.php ... Extraheren van berichten van /Users/Jeff/Sites/mp/frontend/models/ResetPasswordForm.php... Extraheren van berichten van /Users/Jeff/Sites/mp/frontend/models/SignupForm.php... Extraheren van berichten van /Users/Jeff/Sites/mp/frontend/views/layouts/main.php... Extraheren van berichten van /Users/Jeff/Sites/mp/frontend/views/meeting/_form.php... Extracten van berichten van / Users / Jeff / Sites / mp / frontend / views / meeting / _search.php ... Extraheren van berichten van /Users/Jeff/Sites/mp/frontend/views/meeting/create.php... Extracten van berichten van / Users / Jeff / Sites / mp / frontend / views / meeting / index.php ... Extraheren van berichten van /Users/Jeff/Sites/mp/frontend/views/meeting/update.php... Extracten van berichten van / Users / Jeff / Sites / mp / frontend / views / meeting / view.php ... Berichten extraheren m /Users/Jeff/Sites/mp/frontend/views/place/_form.php... Extraheren van berichten van /Users/Jeff/Sites/mp/frontend/views/place/_formGeolocate.php... Extracten van berichten van / Users / Jeff / Sites / mp / frontend / views / place / _formPlaceGoogle.php ... Extraheren van berichten van /Users/Jeff/Sites/mp/frontend/views/place/_search.php... Extracten van berichten van / Users / Jeff / Sites / mp / frontend / views / place / create.php ... Extraheren van berichten van /Users/Jeff/Sites/mp/frontend/views/place/create_geo.php... Extracten van berichten van / Users / Jeff / Sites / mp / frontend / views / place / create_place_google. php ... Extraheren van berichten van /Users/Jeff/Sites/mp/frontend/views/place/index.php... Extraheren van berichten van /Users/Jeff/Sites/mp/frontend/views/place/locate.php... Extracten van berichten van / Gebruikers / Jeff / Sites / mp / frontend / views / place / update.php ... Extraheren van berichten van /Users/Jeff/Sites/mp/frontend/views/place/view.php... Extracten van berichten van / Users / Jeff / Sites / mp / frontend / views / site / about.php ... Extraheren van berichten f rom /Users/Jeff/Sites/mp/frontend/views/site/contact.php... Extractie van berichten van /Users/Jeff/Sites/mp/frontend/views/site/error.php... Extracten van berichten van / Users / Jeff / Sites / mp / frontend / views / site / index.php ... Extraheren van berichten van /Users/Jeff/Sites/mp/frontend/views/site/login.php... Extracten van berichten van / Users / Jeff / Sites / mp / frontend / views / site / requestPasswordResetToken.php ... Extraheren van berichten van /Users/Jeff/Sites/mp/frontend/views/site/resetPassword.php... Extracten van berichten van / Users / Jeff / Sites / mp / frontend / views / site / signup. php ... Extraheren van berichten van /Users/Jeff/Sites/mp/frontend/web/index-test.php... Extraheren van berichten van /Users/Jeff/Sites/mp/frontend/web/index.php... Extracten van berichten van / Users / Jeff / sites / mp / frontend / widgets / Alert.php ...
Als het voltooid is, zie je zoiets in je codebase:
In het algemene configuratiebestand, common / config / main.php
, we gaan Yii vertellen over onze nieuwe taalondersteuning. Ik zal Spaans mijn standaardtaal maken:
dirname (dirname (__ DIR__)). '/ vendor', 'language' => 'es', // spanish 'components' => ['cache' => ['class' => 'yii \ caching \ FileCache',], 'i18n' => [ 'translations' => ['frontend *' => ['class' => 'yii \ i18n \ PhpMessageSource', 'basePath' => '@ common / messages',], 'backend *' => ['class' => 'yii \ i18n \ PhpMessageSource', 'basePath' => '@ common / messages',],],],],];
Maar er is nog meer te doen. We moeten onze code I18n bewust maken.
In deel twee van deze serie, Building Your Startup With PHP: Feature Requirements and Database Design, hebben we Yii's geweldige codegenerator, Gii, gebruikt om onze modellen, controllers en views te genereren. Maar we hebben I18n niet geactiveerd, dus al onze in code ingesloten tekstreeksen. Laten we dit opnieuw doen.
We keren terug naar Gii, waarschijnlijk http: // localhost: 8888 / mp / gii in uw browser, en voeren de model- en controller-generators opnieuw uit met I18n geactiveerd.
Opmerking: als u deel drie van onze serie bijhoudt, moet u mogelijk de verschillen met elk bestand noteren en de code handmatig verplaatsen. Of misschien is het het gemakkelijkst om uw code te vervangen door de Github-repository voor deze zelfstudie, die rechtsboven is gekoppeld.
Hier is een voorbeeld van het genereren van de modelcode van Meeting met geactiveerde I18n. Merk op dat we specificeren "voorkant" voor onze berichtcategorie. We plaatsen al onze frontend tekststrings in één frontend categoriebestand.
Laten we hetzelfde doen voor de CRUD-generatie voor controllers en weergaven:
Als u in modellen, controllers en weergaven door de gegenereerde code bladert, ziet u dat de tekenreeksen worden vervangen door de Yii: t ('frontend', ...)
functie:
title = Yii :: t ('frontend', 'Places'); $ this-> params ['breadcrumbs'] [] = $ this-> title; ?>= Html::encode($this->titel)?>
render ('_ search', ['model' => $ searchModel]); ?>= Html::a(Yii::t('frontend', 'Create modelClass', [ 'modelClass' => 'Plaats',]), ['create'], ['class' => 'btn btn-success'])?> = Html::a(Yii::t('frontend','Add Current Location'), ['create_geo'], ['class' => 'btn btn-success'])?> = Html::a(Yii::t('frontend','Add a Google modelClass',[ 'modelClass' => 'Plaats']), ['create_place_google'], ['class' => 'btn btn-success'])?>
Uw berichtenbestanden vertalen
Bekijk ons Spaanse berichtenbestand,
/common/messages/es/frontend.php
. Het is een lange lijst met lege arraywaarden:return ['Voeg huidige locatie toe' => ", 'Voeg een Google toe modelClass' =>", 'Weet je zeker dat je dit item wilt verwijderen?' => ", 'Create' =>", 'Create modelClass' => ", 'Created At' =>", 'Created By' => ", 'Delete' =>", 'Volledig adres' => ", 'Google Plaats ID' =>", 'ID' => ", 'Vergaderingstype' =>", 'Vergaderingen' => ", 'Bericht' =>", 'Naam' => ", 'Notities' => ", 'Eigenaar ID' =>", 'Plaats Type' => ", 'Plaatsen' =>", 'Reset' => ", 'Zoeken' =>", 'Slug' => ", 'Status '=> ",' Update '=>",' Update modelClass: '=> ",' Bijgewerkt bij '=>",' Omgeving '=> ",' Website '=>",];Voor het invullen van onze Spaanse vertalingen voor deze zelfstudie gebruik ik Google Vertalen. Lastig, he?
Vervolgens gaan we wat knippen en plakken met die vertalingen terug in het berichtbestand.
return ['Voeg huidige locatie toe' => 'Agregar ubicación actual', 'Voeg een Google toe modelClass' => 'Añadir un Google modelClass', 'Created By' => 'Creado por', 'Full Address' = > 'Dirección completa', 'Google plaats-ID' => 'Google plaats-ID', 'Naam' => 'Nombre', 'Aantekeningen' => 'Notas', 'Plaatstype' => 'Plaats Tipo', 'Plaatsen '=>' Lugares ',' Slug '=>' Slug ',' Vicinity '=>' Alrededores ',' Website '=>' Sitio Web ',' Weet je zeker dat je dit item wilt verwijderen? ' => '¿Estás seguro que quières borrar este elemento?', 'Maken' => 'Crear', 'Maken modelClass' => 'Crear Lugar', 'Gemaakt bij' => 'Creado El', 'Verwijderen' => 'Eliminar', 'ID' => 'ID', 'Ontmoetingstype' => 'Tipo de Reunión', 'Vergaderingen' => 'Encuentros', 'Bericht' => 'Mensaje', 'Eigenaar ID' = > 'Propietario ID', 'Reset' => 'Reset', 'Zoeken' => 'Buscar', 'Status' => 'Estado', 'Update' => 'Actualizar', 'Update modelClass:' = > 'Actualizar Lugar', 'Bijgewerkt bij' => 'Actualización A',];Wanneer we de Place-indexpagina bezoeken, zie je de Spaanse versie - leuk, he?
Merk op dat de navigatiebalk in het Engels blijft - dat is omdat het Message / Extract-script de Bootstrap-navigatiearray-definities niet ophaalde en converteerde naar
Yii: t ()
. Dat doen we met de hand. Merk ook op dat Home- en paging-tekst automatisch werden vertaald - Yii's codebase bevat taalvertalingen voor deze standaardstrings.Hier is de Maak een plaats het formulier:
Als ik wil terugschakelen naar het Engels, verander ik gewoon het configuratiebestand,
/common/main.php
, terug naar het Engels:dirname (dirname (__ DIR__)). '/ vendor', 'language' => 'en', // english // 'language' => 'es', // spaansJe zult ook merken dat het vervangen van strings in JavaScript zijn eigen complexiteiten heeft. Ik heb het zelf niet onderzocht, maar de Yii 1.x JsTrans-extensie kan een nuttige richtlijn zijn om dit te ondersteunen.
Verder gaan met I18n
Uiteindelijk willen we onze applicatie mogelijk in een aantal talen vertalen. Ik heb een Yii-functieverzoek geplaatst om het Message / Extract-script uit te breiden om de Google Translate API te gebruiken om dit proces te automatiseren. Ik heb Tuts + ook gevraagd om mij hierover een zelfstudie te laten schrijven, dus houd het in de gaten. Dit levert uiteraard alleen een basisvertaling op. Misschien wilt u professionele vertalers inhuren om de bestanden achteraf af te stemmen.
Sommige applicaties stellen gebruikers in staat hun moedertaal te kiezen, zodat wanneer ze inloggen, de gebruikersinterface automatisch voor hen vertaalt. In Yii stelt u de
$ App-> taal
variabele doet dit:\ Yii :: $ app-> language = 'es';
Andere toepassingen, zoals JScrambler.com hieronder, maken gebruik van het URL-pad om van taal te veranderen. De gebruiker klikt gewoon op het gewenste taalvoorvoegsel, bijvoorbeeld. "FR", en de app wordt automatisch vertaald:
Opmerking: kijk mijn Tuts + instructeurspagina voor een aanstaande tutorial over JScrambler - het is een redelijk nuttige service. Het is mogelijk al verschenen tegen de tijd dat u dit leest.
Yii's URL Manager kan dit type functionalisme ook bieden. Ik zal deze functies waarschijnlijk voor Meeting Planner implementeren in een toekomstige zelfstudie.
Wat is het volgende?
Ik hoop dat je iets nieuws hebt geleerd met deze tutorial. Ik had eerder I18n met Rails gebruikt, maar dit was de eerste keer dat ik het met PHP implementeerde. Kijk uit voor komende tutorials in onze Building Your Startup With PHP-serie - er komen veel leuke functies aan.
Aarzel niet om uw vragen en opmerkingen hieronder toe te voegen; Ik neem over het algemeen deel aan de discussies. Je kunt me ook bereiken via Twitter @reifman of mij rechtstreeks een e-mail sturen.
Gerelateerde Links
- Programmeren met Yii2: Aan de slag
- Introductie tot het Yii Framework
- De Yii2 definitieve gids: internationalisatie