Lokalizace HTML + údržba překladů
- zelenomodrypes
- Člen | 11
Řeším překlad stránek do dalších jazyků a přemýšlím nad těmito dvěmi věcmi:
- Jak hlídat, které překlady jsou stále používané a které už ne a zbytečně zabírají místo v databázi a při překladu do dalšího jazyka pak stojí čas navíc?
Příklad. Mám tento řádek kódu, může být na několika místech v kódu a v různých souborech (i v šablonách):
$this->translator->translate('Zadejte prosím platnou e-mailovu adresu.');
Jeden z těcho řádků pak upravím, např. takto:
$this->translator->translate('Zadejte prosím platnou e-mailovou adresu, na kterou Vám můžeme zaslat potvrzení objednávky.');
Otázka tedy zní – jak efektivně hlídat, zda se v aplikaci nachází starý text ještě někde jinde a tudíž starý překlad musím zachovat?
Napadlo mě řešení pomocí konstant, nebo něčeho podobného, co se dá dobře ve zdrojových souborech vyhledávat – jak v PHP kódu, tak v šablonách, kde může být forma zápisu různá. Tyto konstanty by pak odkazovaly na text k přeložení. Jak toto řešíte vy?
- Jak překládat řetězce obsahující HTML kód? Rozdělíte řetězec na více částí a ty pak přeložíte? Nebo překládáte celý řetězec i s HTML kódem? Co když potřebujete do překládaného textu vložit nějaké další hodnoty, např. proměnnou, vygenerovat URL nebo použít helper?
- voda
- Člen | 561
Bod 1 řeší gettext. Postup je takový, že nejdříve si vytáhneš ze zdrojáků všechny texty a pak aktualizuješ jednotlivé katalogy překladů podle této šablony. V katalogu potom máš navíc chybějící překlady, nepoužité překlady tam zůstanou zakomentované.
V překladech se snažím html nemít, pokud je potřeba dosadit nějakou hodnotu, pak použiji printf.
- petr.pavel
- Člen | 535
Já to řeším tak, že nepoužívám jako identifikátor textu variantu
žádného jazyka. Tudíž ne
‚Zadejte prosím platnou e-mailovu adresu.‘
ale ‚uzivatel-registrace-email-neprazdny‘
Tím mám vyřešené změny – ty dělám v „překladu“.
Když už text nepotřebuju a mažu ho v PHP, smažu ho rovnou i v překladovém slovníku.
- zelenomodrypes
- Člen | 11
@voda: A jak si jednoduše vytáhnu ze zdrojáků všechny texty? O to mi hlavně jde.
Editoval zelenomodrypes (18. 2. 2014 11:21)
- Tomáš Kolinger
- Člen | 136
Gettext je IMHO slepá ulička, nikdy to pořádně nefungovalo a celkově to víc problémů přidělá než vyřeší… Používat nativní implementaci v PHP nemůžeš. Originální translátor (poedit) je taky špatně použitelný… Takže si to musíš napsat sám či použít nějaké PHP knihovny a to taky většinou nefunguje jak má…
Mě se nejvíc osvědčilo používat hloupá PHP pole – předkládat to můžeš v jakékoliv editoru, je to rychlé a nenáročné, lehce uděláš diff dvou jazyků a získáš nepřeložené texty… Napsat podobný translátor je velice jednoduché.
Pokud jde o údržbu a získání aktuálně používaných překladů, tak
nejčistější je obalovat PHP překlady do nějaké funkce – např.
__('key to translation')
. Potom ti stačí jednoduchý extractor
(viz. příspěvek výše). Samozřejmě by to taky chtělo přidat podporu pro
latte – já používám jen zápis {_'key to translation'} a tím může být
extractor jednodušší.
Ona funkce __()
nemusí nutně překládat, stačí když string
jen vrátí a samotný překlad uděláš pěkně pomocí služby
ITranslator
. To samé platí pro formuláře, kde nastavíš
translátor, takže je nesmysl, aby funkce __()
překládala. Je to
čistě berlička pro extractor. Hezčí a stejně funkční řešení jsem
nenašel.
Editoval Tomáš Kolinger (18. 2. 2014 12:45)
- zelenomodrypes
- Člen | 11
@Tomáš Kolinger: Popravdě, gettext použitý nemám, veškeré
překlady mám uložené v databázi (jednoduchá tabulka se sloupci
code
, language_id
a text
) a využívám
iterface ITranslator
. Překlad a úprava textů je pak velmi
jednoduchá. Hledal jsem jenom způsob, jak překládané texty ve zdrojových
kódech hlídat. Pomocí GettextExtractor jsem
schopný veškeré texty ze zdrojových kódů vytáhnout do souboru a ten pak
pomocí jednoduchého algoritmu porovnat oproti databázi – zjistím tak,
které překlady v databázi chybí a které jsou tam naopak navíc.
Jako řešení jsem viděl ještě použítí konstant jako identifikátorů textů k překladu, které by se ve zdrojových kódech daly velmi jednoduše dohledat. Ale sepsání těchto konstant by zabralo příliš mnoho času, moc se mi toto řešení nelíbilo.
@castamir: Tohle vypadá taky dost našlapaně :-)
- zelenomodrypes
- Člen | 11
@Oli: Jednoduché napojení na šablony, resp. možnost použití
makra {_expression}
. V databázi máš jenom dva sloupce? To moc
nechápu.
- Oli
- Člen | 1215
nemam jen 2 sloupce. Napriklad stránky (pages): object_id, language_id, title, slug, text, …
vytáhnu si co potřebuju
$this->connection->table(pages)->where('language_id = ?, object_id = ?', $lang, $object);
v šabloně to potom jednoduše vypíšu
<h1>{$page->title}</h1>
{$page->text}
Proto tady nevidím důvod používat to makro. To makro používám pro
nedynamický věci
typu Copyright © 2008, 2014 Nette Foundation | {_'Terms of use'}
- zelenomodrypes
- Člen | 11
Jasný, to dává smysl. Mě vyhovuje mít všechny překlady uložené na jednom místě.
Ale ještě k tvému řešení – jak poznáš, které překlady na stránkách v databázi nemáš a které jsou naopak v databázi zbytečné, tj. nepoužívají se? (Jasný, pro malé weby je zbytečné toto řešit, ale pokud máš složitější stránku a v databázi nemáš uložený překlad (např. prázdný sloupec), na stránku se ti nevypíše nic – podle čeho tedy poznáš, že tam něco mělo být vypsané?)
Editoval zelenomodrypes (19. 2. 2014 11:07)
- Oli
- Člen | 1215
Zatím to je na editorech/administrátorech těch webů, kteří si tím pádem zodpovídají za obsah plně sami.
Nicméně by nebyl problém třeba zablokovat publikování toho oběktu (pages), pokud nejsou všechny jazykové mutace vyplněny. Nebo pokud se to takhle publikuje poslat někomu mail, bacha je publikovaná stránka jen v cs… Těch možností je víc, ale zatím nebylo nutné nějakým způsobem tohle řešit.
V db není nic přebytečné. Bloky textu, které nepatří žádnému objektu se ukládají v boxech a pak se vypíšou pomocí vlastního makra {box folder-super-text}. Pokud ten box není potřeba tak se smaže/ukryje. Pokud chybí tak se dodělá.
Takhle to řeším pro větší nebo členitější bloky textu… Kontrola jestli to je přeloženo viz stránky.
- Tomáš Kolinger
- Člen | 136
Tak tvůj hlavní problém je spojení překladů… Celkově nedává smysl, aby si měl statické i dynamické na jednom místě… Potom problém uvedený v prvním příspěvku narůstá do velkých rozměrů – stačí změnit interpunkci v článku a máme nový překlad… Což se uhlídat prakticky nedá, jelikož neexistuje pevná návaznost na článek.
Tohle spojení má i zásadnější problémy… Jako je třeba kešování. Statické překlady musíš kešovat vždy. Nopak dynamické se kešovat nevyplatí. Protože jejich změny probíhají opravdu často. Statické se mění z 90% při deployi nové verze.
Já osobně statické řeším pomocí ITranslator
, jestli to
uložíš do pole či do databáze a keše je už fuk. Dynamické řeším na
úrovni databáze. Pro výpis dat si vytvořím pohled a potom dám jednoduchý
dotaz –
SELECT content FROM articles WHERE id = ? AND language = ?
a mám
přesně to co potřebuji. Překlady potom můžeš ukládat do oddělené
tabulky (language_id, article_id, content). Ve finále tvůj problém řešit
nemusíš – statické se dají ohlídat extractorem a dynamické ohlídá
samotná databáze – nedovolí ti vytvořit nový překlad, když už jeden
existuje.
Tohle řešení je pracnější na naprogramování ale pokud se jedná
o větší web, tak překládat dynamické překlady pomocí
ITranslator
je velice ale opravdu velice neefektivní.
Editoval Tomáš Kolinger (19. 2. 2014 13:27)
- zelenomodrypes
- Člen | 11
@Oli: Jsem tě špatně pochopil – taky mám dynamické texty
(např. články, informační podstránky) uložené v databázi zvlášť
(tabulky articles
a pages
, které obsahují podobné
sloupce, tj. language_id
, title
, text
).
Tohle je na správu velmi jednoduché – většinou je pro každou tabulku
jeden presenter, jeden template a tím to končí. Statické texty, např. text
v patičce stránky, labely u formulářů apod., mám uložené také
v databázi a tady řeším ten problém, jak efektivně hlídat, které texty
se používají a které ne.
@Tomáš Kolinger: Viz odpověď Olimu, špatně jsem se možná vyjádřil. Mám je samozřejmě zvlášť, bavím se čistě o statických textech (patička stránky, labely u formulářů, flash messages atd.)
Teď to mám ve stavu, který jsi popsal, tj. statické se dají ohlídat
extractorem a dynamické ohlídá samotná databáze. Překládat text
několikaodstavcového článku skrz ITranslator
mi samozřejmě
taky přijde jako slušná prasárna.