Lokaliseer uw webapplicatie voor elk land met de Google Translate API

Wat je gaat creëren

In mijn zelfstudielokaal Lokalisatie met I18n voor het samenstellen van uw startup met PHP-reeks heb ik voorbeeld Spaanse code gemaakt door tekststrings in Google Translate te knippen en te plakken. Ik begon me af te vragen of ik de Google Translate API kon integreren met het I18n resource-extractiescript van het Yii Framework om de vertaling voor een aantal landen te automatiseren. Ik postte een functieverzoek op het Yii Forum en besloot toen om te kijken of ik de functie zelf kon bouwen.

In deze tutorial leid ik je door mijn extensies naar het Yii I18n extract script die precies dit doen. En ik zal demonstreren dat ik mijn startup-applicatie, Meeting Planner, vertaal in een handvol talen.

Houd er rekening mee dat Google Vertalen niet perfect is en geen problemen met betrekking tot datum- en tijdnotaties en valuta behandelt. Maar voor een snelle en betaalbare (gratis) manier om standaardvertalingen voor uw webtoepassing in 50+ talen te bouwen, is dit een ideale oplossing.

Dit is bijvoorbeeld een meer opvallende fout die ik tegenkwam bij het testen - gelukkig zijn deze zeldzaam:

'nFormatted TB' => 'nFormatted tuberculos', 

Als je een meer professionele aanpak nodig hebt, heeft een vriend me gewezen op een betaalde service voor het beheren van lokalisatie binnen apps, Transifex. Ik heb het zelf niet gecontroleerd, maar het ziet er intrigerend uit.

Werken met Google Translate

Welke talen ondersteunt het?

Google Translate biedt vertaaldiensten voor 64 talen, waaronder de Zweedse, maar helaas niet de Zweedse chef-kok:

Hier is een greep uit de ondersteunde talen van Google - zie de volledige lijst hier:

Praten met de Google Translate API

Ik heb twee Composer-bibliotheken gevonden voor het werken met de Google Translator API in PHP:

  • Levan Velijanashvili's Google Translate-bibliotheek
  • Travis Tillotson's Google-vertaalclient

Ik vond Velijanashvili's eerste dus het is wat ik gebruikte in deze tutorial. Het maakt gebruik van Google Translate via de gratis RESTful webinterface, zodat u geen API-sleutel nodig heeft. Als u echter over een grote bibliotheek met bronnen beschikt of van plan bent veel talen te vertalen, wilt u waarschijnlijk Tillotson's integreren, omdat deze volledig is geïntegreerd met de betaalde service van Google Translate via de sleutels.

Voor deze tutorial bouw ik voort op de codebase Building Your Startup With PHP-serie. Om Velijanashvili's Google Translate-bibliotheek te installeren, typ je gewoon:

componist vereist stichoza / google-translate-php

Hier is een voorbeeldcode om te vertalen van Engels naar Spaans:

gebruik Stichoza \ Google \ GoogleTranslate; echo GoogleTranslate :: staticTranslate ('hallo wereld', 'en', 'es'). "\ N"; 

Het zou moeten uitvoeren:

hola mundo

Het I18n-bericht- / uittrekscript van Yii2 uitbreiden

Hoe de I18n-ondersteuning van Yii2 vandaag werkt

Op dit moment wilt u misschien mijn Localization With I18n-zelfstudie bekijken waarin wordt uitgelegd hoe u berichtreeksen kunt extraheren voor uw benodigde taalvertalingen.. 

U kunt Yi's Gii-codegenerator gebruiken om modellen en CRUD-code te genereren die I18n-ondersteuning automatisch integreert. Elke tekenreeks in de code wordt vervangen door een functieaanroep zoals Yii :: t ('categorie', 'tekststring om te vertalen');.

Yii biedt een consolebevelbericht / -uittreksel dat al deze functieaanroepen in uw toepassing vindt en een mapstructuur met bestanden op taal en categorie maakt voor vertalingen van al deze tekenreeksen.

Hier is een voorbeeld van een stringbestand voor Duits:

 'Machen Sie sich mit Yii begonnen', 'Heading' => 'Überschrift', 'My Yii Application' => 'Meine Yii-Anwendung', 'Yii Documentation' => 'Yii Dokumentation', 'Yii Extensions' => ' Yü -Erweiterungen ',' Yii Forum '=>' Yii Forum ',' Weet je zeker dat je dit item wilt verwijderen? ' => 'Sind Sie sicher, Sie wollen diesen Inhalt löschen?', 'Gefeliciteerd!' => 'Herzlichen Glückwunsch!', 'Create' => 'schaffen', 'Create modelClass' => 'schaffen modelClass', 'Created At' => 'Erstellt am', 'Delete' => 'löschen ',' ID '=>' Identifikatie ',

Hier is een voorbeeld van de directorypaden:

Uitbreiding van bericht / uittreksel voor Google Vertalen

Ik koos voor de aanpak van het maken van een vervangend script met de naam message / google_extract die Google Translate zou bellen als het nodig was om een ​​string te vertalen.

Voorkomen dat code verbroken wordt bij het vertalen van tokens

Omdat I18n parameter-tokens in accolades integreerde voor variabele waarden, kwam ik meteen een aantal problemen tegen. Hier zijn bijvoorbeeld enkele I18n-reeksen die tokens en geneste tokens bevatten:

'Maak modelClass' Geregistreerd op 0, datum, MMMM dd, JJJJ UU: mm van 1 "0, datum, MMMM dd, JJJJ UU: mm" nGeformatteerd n, meervoud, = 1 gibibyte andere gibibytes '

De Google Translate API heeft geen parameter voor het negeren van tokens zoals deze in dit formulier. Maar we kunnen deze niet vertalen omdat ze corresponderen met variabele namen en opmaakstrings in code.

Het leek mij niet dat een reguliere expressie dit kon oplossen waar vertaalbare tekenreeksen en tokens samen aanwezig waren. Het is waarschijnlijk dat lezers een efficiëntere oplossing hebben dan ik heb gevonden voor het oplossen van dit probleem. Als dit voor u duidelijk is, kunt u dit in de opmerkingen plaatsen..

Ik heb ervoor gekozen om de tekenreeksen per teken te scannen en het nesten van accolades te volgen. Ik zal de eerste zijn om toe te geven dat er misschien een betere manier is. Dit is mijn functie parse_safe_translate ():

/ * * parseert een string in een array * splitsen door alle segmenten van de beugel * inclusief geneste accolades * / public function parse_safe_translate ($ s) $ debug = false; $ result = array (); $ Start = 0; $ nest = 0; $ Ptr_first_curly = 0; $ total_len = strlen ($ s); voor ($ i = 0; $ i<$total_len; $i++)  if ($s[$i]=='')  // found left curly if ($nest==0)  // it was the first one, nothing is nested yet $ptr_first_curly=$i;  // increment nesting $nest+=1;  elseif ($s[$i]=='')  // found right curly // reduce nesting $nest-=1; if ($nest==0)  // end of nesting if ($ptr_first_curly-$start>= 0) // push-string in de aanloop naar de eerste links-krullende $ prefix = substr ($ s, $ start, $ ptr_first_curly- $ start); if (strlen ($ prefix)> 0) array_push ($ resultaat, $ voorvoegsel);  // druk (mogelijk genest) krulstring $ achtervoegsel = substr ($ s, $ ptr_first_curly, $ i- $ ptr_first_curly + 1); if (strlen ($ suffix)> 0) array_push ($ resultaat, $ achtervoegsel);  if ($ debug) echo '|' .substr ($ s, $ start, $ ptr_first_curly- $ start-1). "| \ n"; echo '|' .substr ($ s, $ ptr_first_curly, $ i- $ ptr_first_curly + 1). "| \ n";  $ start = $ i + 1; $ Ptr_first_curly = 0; if ($ debug) echo 'volgende start:'. $ start. "\ n";  $ achtervoegsel = substr ($ s, $ start, $ total_len- $ start); if ($ debug) echo 'Start:'. $ start. "\ n"; echo 'Pfc:'. $ ptr_first_curly. "\ n"; echo $ suffix. "\ n";  if (strlen ($ suffix)> 0) array_push ($ result, substr ($ s, $ start, $ total_len- $ start));  return $ resultaat;  

Het converteert een I18n-reeks in een array van elementen gescheiden in vertaalbare en onvertaalbare elementen. Bijvoorbeeld deze code:

$ message = 'De afbeelding' file 'is te groot. De hoogte kan niet groter zijn dan limit, number limit, plural, one pixel other pixels. '; print_r ($ this-> parse_safe_translate ($ message)); 

Genereert deze output:

Array ([0] => De afbeelding "[1] => file [2] =>" is te groot. De hoogte kan niet groter zijn dan [3] => limit, number [4] => [ 5] => limit, plural, one pixel other pixels [6] =>.) 

Telkens wanneer het extractieproces een nieuwe tekenreeks identificeert die moet worden vertaald, wordt de tekenreeks in deze delen verbroken en wordt de Google Translate API aangeroepen voor elke vertaalbare tekenreeks, bijvoorbeeld een die niet begint met een linker accolade. Vervolgens worden die vertalingen samengevoegd met de tokenized strings terug in een enkele string.

Een tokenized string vertalen met Google Translate

Dit is de functie getGoogleTranslation () voor een string en een doeltaal. De brontaal wordt bepaald door Yii :: $ app-> taal.

 openbare functie getGoogleTranslation ($ message, $ language) $ arr_parts = $ this-> parse_safe_translate ($ message); $ translation = "; foreach ($ arr_parts als $ str) if (! stristr ($ str, '')) if (strlen ($ translation)> 0 en substr ($ translation, -1) == ' ') $ translation. = "; $ vertaling. = GoogleTranslate :: staticTranslate ($ str, Yii :: $ app-> taal, $ taal);  else // voeg spatie voorvoegsel toe tenzij het eerst als (strlen ($ vertaling)> 0) $ vertaling. = ". $ str; anders $ vertaling. = $ str; print_r ($ vertaling); terugkeer $ vertaling;  

Ik ontdekte dat de combinatie van deze benaderingen bijna perfect werkte in mijn testen.

Het bericht / uittreksel van Yii aanpassen

De I18n-implementatie van Yii ondersteunt het laden van resourcekringen van .PO-bestanden, .PHP-bestanden (die ik gebruik) en de database. Voor deze zelfstudie heb ik Message / Extract aangepast voor het genereren van PHP-bestanden.

Ik heb gekopieerd en uitgebreid message / extract in /console/controllers/TranslateController.php. Vanwege de strikte regels van PHP 5.6.x heb ik de functienamen voor gewijzigd saveMessagesToPHP naar saveMessagesToPHPEnhanced en saveMessagesCategoryToPHP naar saveMessagesCategoryToPHPEnhanced.

Hier is de saveMessagesToPHPEnhanced () functie:

/ ** * Schrijft berichten in PHP-bestanden * * @param array $ messages * @param string $ dirName naam van de map om naar te schrijven * @param Boolean $ overschrijft als bestaand bestand overschreven moet worden zonder back-up * @param boolean $ removeUnused if verouderde vertalingen moeten worden verwijderd * @param Boolean $ sorteer als vertalingen gesorteerd moeten worden * / beschermde functie saveMessagesToPHPEnhanced ($ messages, $ dirName, $ overwrite, $ removeUnused, $ sort, $ language) foreach ($ messages as $ category => $ msgs) $ file = str_replace ("\\", '/', "$ dirName / $ category.php"); $ path = dirname ($ bestand); FileHelper :: createDirectory ($ path); $ msgs = array_values ​​(array_unique ($ msgs)); $ coloredFileName = Console :: ansiFormat ($ file, [Console :: FG_CYAN]); $ this-> stdout ("Berichten opslaan in $ coloredFileName ... \ n"); $ this-> saveMessagesCategoryToPHPEnhanced ($ msgs, $ file, $ overwrite, $ removeUnused, $ sort, $ category, $ language);  

Het roept de saveMessagesCategoryToPHP functie:

/ ** * Schrijft categorieberichten in PHP-bestand * * @param array $ messages * @param string $ fileName naam van het bestand om te schrijven naar * @param Boolean $ overschrijft als bestaand bestand overschreven moet worden zonder back-up * @param Boolean $ removeUnused als verouderde vertalingen moeten worden verwijderd * @param boolean $ sorteer als vertalingen gesorteerd moeten worden * @param Boolean $ language language to translating to * @param boolean $ force google translate * @param string $ category message category * / protected function saveMessagesCategoryToPHPEnhanced ($ berichten, $ fileName, $ overwrite, $ removeUnused, $ sort, $ category, $ language, $ force = true) if (is_file ($ fileName)) $ existingMessages = require ($ fileName); sort ($ messages); ksort ($ existingMessages); if (! $ force) if (array_keys ($ existingMessages) == $ messages) $ this-> stdout ("Niets nieuws in \" $ categorie \ "categorie ... Niets om op te slaan. \ n \ n", Console: : FG_GREEN); terug te keren;  $ merged = []; $ untranslated = []; foreach ($ messages as $ message) if (array_key_exists ($ message, $ existingMessages) && strlen ($ existingMessages [$ message])> 0) $ merged [$ message] = $ existingMessages [$ message];  else $ untranslated [] = $ bericht;  ksort ($ merged); sort ($ onvertaald); $ todo = []; foreach ($ onvertaald als $ bericht) $ todo [$ message] = $ this-> getGoogleTranslation ($ message, $ language);  ksort ($ existingMessages); foreach ($ existingMessages als $ message => $ translation) if (! isset ($ merged [$ message]) &&! isset ($ todo [$ message]) &&! $ removeUnused) if (! empty ($ translation) && strncmp ($ vertaling, '@@', 2) === 0 && substr_compare ($ translation, '@@', -2, 2) === 0) $ todo [$ message] = $ vertaling;  else $ todo [$ message] = '@@'. $ vertaling. '@@';  $ merged = array_merge ($ todo, $ merged); if ($ sort) ksort ($ merged);  if (false === $ overwrite) $ fileName. = '.merged';  $ this-> stdout ("Vertaal samengevoegd. \ n");  else $ merged = []; foreach ($ messages as $ message) $ merged [$ message] = "; ksort ($ merged); $ array = VarDumper :: export ($ merged); $ content = <<id 'opdracht. * Het bevat de lokaliseerbare berichten geëxtraheerd uit de broncode. * U kunt dit bestand wijzigen door de geëxtraheerde berichten te vertalen. * * Elk array-element vertegenwoordigt de vertaling (waarde) van een bericht (sleutel). * Als de waarde leeg is, wordt het bericht beschouwd als niet vertaald. * Berichten die niet langer moeten worden vertaald, worden voorzien van vertalingen * tussen een paar '@@'-markeringen. * * Berichtstring kan worden gebruikt met formatie in meervoudsvormen. Controleer i18n sectie * van de gids voor details. * * OPMERKING: dit bestand moet worden opgeslagen in UTF-8-codering. * / return $ array; EOD; file_put_contents ($ fileName, $ content); $ this-> stdout ("Vertaling opgeslagen. \ n \ n", Console :: FG_GREEN); 

Helaas wordt de oorspronkelijke Message / Extract-code niet becommentarieerd. Hoewel er mogelijk enkele aanvullende verbeteringen kunnen worden aangebracht, heb ik hier eenvoudigweg een oproep aan de Google Translate API toegevoegd:

foreach ($ onvertaald als $ bericht) $ todo [$ message] = $ this-> getGoogleTranslation ($ message, $ language); 

En ik heb een parameter toegevoegd ($ Force = true) om het kopiëren van de berichtenbestanden te forceren:

if (! $ force) if (array_keys ($ existingMessages) == $ messages) $ this-> stdout ("Niets nieuws in \" $ categorie \ "categorie ... Niets om op te slaan. \ n \ n", Console: : FG_GREEN); terug te keren; 

Message Planner vertalen

Testen voltooid, ik was verheugd om Message Planner in meer talen te vertalen. Eerst voegen we de nieuwe taalvertalingen toe aan de /console/config/i18n.php het dossier:

 __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' => ['ar', 'es', 'de', 'it', 'iw', 'ja', 'yi', 'zh-CN'], 

Nogmaals, als u een bredere taalondersteuning nodig heeft of een grotere hoeveelheid strings wilt vertalen, wilt u misschien overstappen op de vertaalclient van Travis Tillotson en betaalde API-toegang.

Vervolgens heb ik vertaalreeksen toegevoegd /frontend/views/layouts/main.php en /frontend/views/site/index.php om de vertaling van de startpagina te demonstreren. Omdat deze pagina's niet worden gegenereerd door Yi's Gii-codegenerator, waren de tekenreeksen in gewone HTML achtergelaten. Hier is een voorbeeld van hoe ze er nu uit zien:

»

Dit is hoe de startpagina er in het Engels uitziet:

Toen rende ik weg google_extract:

./ yii translate / google_extract /Users/Jeff/sites/mp/common/config/i18n.php 

Opmerking: Zorg ervoor dat wanneer u dit doet, de taal van de toepassing is ingesteld op uw standaardtaal, bijvoorbeeld Engels. Deze instelling is in /common/config/main.php:

 dirname (dirname (__ DIR__)). '/ vendor', // beschikbare talen // 'ar', 'de', 'es', 'it', 'iw', 'ja', 'yi', 'zh-CN "language' => 'en ', // Engelse' componenten '=> [ 

Ik vond dat het nodig was om te rennen google_extract eenmaal om de initiële berichtbestandssjabloon te maken en een tweede keer om de oproepen naar Google Translate te initiëren.

Dan kan ik de taalinstelling in wijzigen /common/config/main.php om elke vertaling te zien. De resultaten zijn best ongelooflijk voor iets dat zo snel kan worden gegenereerd.

Hier is de startpagina in het Chinees:

Hier is de startpagina in het Arabisch:

Hier is de startpagina in het Japans:

Hier is de startpagina in Jiddisch:

Hier is de startpagina in het Duits:

Wat is het volgende?

Ik hoop dat je deze tutorial leuk vond. Het was leuk om iets te schrijven dat zo'n grote impact had op het potentiële bereik van mijn Meeting Planner-toepassing. Als u meer wilt weten over Meeting Planner, bekijk dan de komende tutorials in onze Building Your Startup With PHP-serie. Er komen veel leuke functies aan.

Voel je vrij om je 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

  • Bouw je Startup met PHP: Lokalisatie met I18n (Tuts +)
  • Programmeren met Yii2: Aan de slag (Tuts +)
  • Introductie van het Yii Framework (Tuts +)
  • De Yii2 definitieve gids: internationalisatie