Jazykové překlady entit rubrika: Programování: PHP

6 pix
položil/-a 5.1.2015

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?

Komentáře

  • Pavel Kepka : Šel bych nejspíš cestou 2, jedna překladová tabulka pro každou entitu. Plus bych varianty slova ukládal v JSON do textového pole, což umožní fultextové hledání a není třeba dál strukturu větvit. 5.1.2015
  • pix : Dvojka se mi i z pohledu ORM jeví také jako vhodná. Do Twigu se poté přidá nějaký filter, kterému se předá entita a pád, a ten již bude vědět, že v češtině je to tenhle pád, v angličtině je to singular, v polštině tak a tak. Jinak vyhledávání asi budu řešit exportem to nějaké speciální vyhledávací tabulky, možná lépe do ElasticSearch, protože se bude vyhledávat mezi více entitami najednou. 5.1.2015
  • pix : I když. Teď o tom přemýšlím a chybí tam ještě jedna možnost z pohledu ORM ještě lepší. Jako 3), ale s jednou tabulkou: Jedna tabulka překladů a v nich všechny možnosti jako sloupce (country_id, city_id, .., en_plural, cs_form_4, ...). Nebudu muset vytvářet v podstatě duplicitní entity (CountryTranslation, CityTranslation, ...), ale prostě jedna Translation, která bude jen napojená na City, Country ... 5.1.2015
  • pix : Ty jo, ale zase forma 3) (TranslationCzech, TranslationEnglish, ...) je lepší na úsporu přenášených dat. Když se někomu načte webová stránka, vždycky bude jen v jednom jazyce, tudíž data z Translation entity je potřeba jen pro jeden jazyk. Všechny body mají výhody a nevýhody. 5.1.2015
  • spazef0rze : Na skloňování lze zkusit knihovnu https://github.com/Mikulas/inflection - existuje i jako rychlejší PHP rozšíření. 9.1.2015
odkaz Vyřešeno
6 pix
odpověděl/-a 5.1.2015

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:

Rychlé přihlášení přes sociální sítě:

Nebo se přihlaste jménem a heslem:

Zadejte prosím svou e-mailovou adresu.
Zadejte své heslo.