Jazykové překlady entit rubrika: Programování: PHP
Zdravím, zajímal by mě váš názor:
Pracuji na webové aplikaci, kde jsou důležitá data a jejich jazykové mutace. Nejen pro výpis na webu v rámci jazykových mutací, ale také ve vyhledávání, správném skloňování a podobně. Například potřebuji kompletní databázi kontinentů, zemí, států, měst, a různých variabilních "turistických oblastí". Všechny názvy potřebuji mít dostupné ve všech pádech. Gettext a podobné je proto samozřejmě nedostatečný, je potřeba to ukládat do databáze. Dost ale váhám nad její strukturou. Jazyků bude k dispozici třeba 5. Používám Symfony2 a Doctrine.
Všechny entity ukládám do vlastních tabulek (continents, countries ...) s vazbami dolů a nahoru (možná by byl lepší použít třeba Nested set). Napadají mě 4 možnosti jak ukládat jazykové verze:
- 1) Všechno v jedné tabulce dané entity.
- 2) Jedna jazyková tabulka pro danou entitu (continents_translations, cities_translations), která se bude rozšiřovat horizontálně (en_plural, cs_form_4, cs_form_6, ...). Jazyky nebudou vznikat nijak často.
- 3) Jedna tabulka pro daný jazyk (translations_cs) a sloupce (country_id, city_id, .., en_plural, cs_form_4, ...).
- 4) Co jazyk a entita to vlastní tabulka (continents_cs, cities_cz, ...).
Řešili jste někdo něco podobného? Nějaký zajímavý nápad?
Tak nakonec jsem to vyřešil tím, že v jednotlivých entitách jsou odkazy na jednotlivé jazyky a každý jazyk je zvláštní tabulka.
/** * @Entity() */ class City { /** * @var TranslationCzech * @OneToOne(targetEntity="TranslationCzech", cascade={"persist"}) * @JoinColumn(name="cs_translation_id", referencedColumnName="translation_id") */ private $translationCzech; /** * @var TranslationEnglish * @OneToOne(targetEntity="TranslationEnglish", cascade={"persist"}) * @JoinColumn(name="en_translation_id", referencedColumnName="translation_id") */ private $translationEnglish; }
/** * @Entity() */ class TranslationCzech { /** * @var string * @Column(name="singular_form_1", type="string", length=255) */ private $singularForm1; /** * @var string * @Column(name="singular_form_2", type="string", length=255, nullable=true) */ private $singularForm2;
Komentáře
- pix : Dostal jsem za své řešení od někoho mínus. Docela by mě zároveň potěšil důvod a feedback, díky :). — 6.2.2015
- Jakub Macek : Řekl bych, že toto řešení "úspěšně" kombinuje všechna ostatní řešení aniž by zachovávalo kteroukoliv z výhod. Nejzřetelnější je, že to neodpovídá intuitivně žádné z běžných vazeb. Podle umístění atributů cizího klíče by mělo více měst využívat jeden překlad (je to 1:N). Kdyby to bylo pro 1:1, což bych řekl, že je v tomto případě očekávaná situace, tak by měly obě tabulky sdílet stejný primární klíč a ten by měl být v překladové tabulce zároveň cizím klíčem do měst. Zároveň rozdělení jazyků do samotatných tabulek vypadá jen jako zbytečná denormalizace. — 8.2.2015
- danaketh : Nebylo by lepší si ty překlady nechat vrátit do jedný property jako collection? A napsat si getter, kterej by vracel překlad na základě parametru. // $City->getTranslation($lang) // by vrátilo Translation objekt, takže by se dalo volat třeba // $City->getTranslation($lang)->getSingular($variant) // a tam mít zase getter, kterej vrací singular/plural podle parametru. Pak můžeš překlady nasypat do jedný tabulky, jen jim dáš ID podle jazyka. — 8.2.2015
- pix : 2jakub.macek.0: Nemyslím si. Naopak to všechny aspekty, které jsem v úvodu zmiňoval jako hlavní, splňuje. Není to 1:N ale 1:1. Nemůže to používat jednotný primární klíč, jelikož propojení je na více entit: City, Country, Region, Continent, ... — 8.2.2015
- pix : 2danaketh: Každý jazyk má svoje specifika a z každého dokonce nepotřebuju vše, někde zase potřebuju o daném výrazu vědět něco navíc. Třeba finština má 17 pádů, čeština a polština 7, angličtina žádné. Nemůže to být v jedné tabulce. — 8.2.2015
- v6ak : Může, ale měla by více sloupců. (Jak jsem psal, různé sloupce pro různé jazyky jsou obecně dobře: je tu jiný collation a jiné indexování. Nevím ale, jestli se toho využije u této konkrétní aplikace.) — 8.2.2015
- Jakub Macek : @pix: Možná je to tím, že netušíme, co je účelem té aplikace. Takto by to bylo například vhodné pro aplikaci zabývající se jazykem, ale dost nešikovné pro aplikaci zabývající se cestováním. Stačí si představit situaci, že přijdu k projektu jako nový programátor a mám přidat funkci s nadpisem "Novinky ve městě X". Abych tu udělal v této situaci, tak musím naprogramovat v daném místě nadpisu kód, který bude znát všechny jazyky a podle jejich gramatiky vytáhne příslušnou formu. Jenomže já vím o finštině/čínštině/... akorát to, co jsme brali v zeměpisu, takže nemám šanci tam vypsat správný tvar. Proto je obvyklejší mít v překladech formy podle užití v aplikaci, takže tam nebude "singularForm2", ale "neco_v_X" ("hlavni_nadpis_X", "vyhledavani_X", ...). Tím pádem se zodpovědnost za znalost gramatiky jazyka přenese na jednotlivé překladatele (budou tam mít třeba příklad užití v originálním jazyce) a programátor může programovat. V důsledku to pak ještě způsobí otočení té vazby (není to striktně nutné, ale má to určité výhody při dotazech). — 9.2.2015
Pro zobrazení všech 8 odpovědí se prosím přihlaste:
Nebo se přihlaste jménem a heslem:
Komentáře