Jak sobie radzicie z tłumaczeniami aplikacji webowej?

0

Mam pewien dylemat dotyczący wielu wersji językowych aplikacji. Powiedzmy, że w bazie danych jest tabela menu, która zawiera kolumne name, które oznacza pozycję w menu zapisaną w jęz. polskim. Potrzeba przetłumaczyć projekt na wersję angielską. Co robicie?

1. Nowa tabela

Tworzymy nową tabelę - powiedzmy - menu_trans, która będzie zawierała tłumaczenia naszych pozycji menu. Robimy tak dla każdej tabeli, która zawiera jakieś teksty do tłumaczenia.

2. Tlumaczenie na poziomie renderowania strony

W plikach trzymamy tłumaczenia projektu w postaci klucz => wartość. Stringi przepuszczane są przez jakąś tłumaczącą funkcję, na poziomie renderowania strony. Baza pozostaje bez zmian.

3 ???

Jakie Wam przychodzą rozwiązania "za i przeciw"?

0

Tam gdzie teksty sa statyczne korzystam z rozwiazania numer 2. Jeżeli natomiast istnieje potrzeba zmieniania tekstów z poziomu jakiegos panelu admina (dynamiczna tresc) to preferuje rozwiazanie z nowa tabela - dla kazdego nowego jezyka tworze nowa tabele z odpowiednim prefiksem. W przypadku tabeli menu zrobilbym to najlepiej tak:

  • zmienilbym nazwe tabeli menu na pl_menu
  • dodalbym tabele en_menu

Czasami mozna z pierwszego kroku zrezygnowac w obawie o potencjalne bledy.

Zdarza mi sie tez isc na latwizne i dodawac nie tyle tabele co kolumny. Czyli w tabeli menu dodalbym kolumne en_name i zmienilbym nazwe kolumny name na pl_name.

0

Tutaj racze osobna tabela do każdego języka nie byłaby potrzebna. Można stworzyć jedną tabelę - np. menu_trans, a w niej menu_id, language oraz value. Potem wyciągając pozycje menu:

SELECT menu.id, menu_trans.value
FROM menu
JOIN menu_trans ON menu_id = menu.id AND language = 'en'
1

@Adam Boduch: a czemu nie użyjesz gettext? U mnie wszystko piszemy po ang i przepuszczamy przez funkcje _ (a konkretniej przez jakiś translate Zend'a). Do generowanie tłumaczeń możesz użyć poedit. Przykładowy plik wyglada tak:

msgid "'%value%' contains characters which are non alphabetic and no digits"
msgstr "Wartość '%value%' powinna zawierać znaki z alfabetu lub cyfry"

W projekcie, który tworzyłem w Laravelu użyłem tego: https://github.com/xinax/laravel-gettext
Oczywiście jeżeli tworzysz aplikację w jsie, to ja to rozwiązałem tak:

elixir.extend('i18n', function (src) {
    var langPath = 'resources/lang/i18n/pl_PL/LC_MESSAGES/';
    new Task('i18n', function () {
        return gulp.src(langPath + '**/*.po')
            .pipe(exec('msgfmt -cv -o ' + langPath + 'messages.mo ' + langPath + 'messages.po'))
            .pipe(pojson())
            .pipe(gulp.dest(langPath));
    }).watch(langPath + '**/*.po');
});

elixir(function (mix) {
    mix.i18n('messages.po');
});

To mi tworzy plik json, z którym później już sobie możesz zrobić co Ci się podoba:

// Main function responsible for translating text with JS
// If message equals meta:value function returns meta with given key
export function __(message) {
    return ~message.indexOf('meta')
        ? i18n.meta[message.split(':')[1]]
        : sprintf(i18n.dic[message], Array.prototype.slice.call(arguments, 1));
}
0

Mozesz tak zrobic ale czy jest to lepsze rozwiazanie to nie wiem. W przypadku menu ma to raczej niewielkie znaczenie, ale tam gdzie danych byloby duzo to lepsza bylaby chyba opcja z osobnymi tabelami. Wtedy po stronie skryptu wybierzesz sobie odpowiednia tabele (na zasadzie prefiks_jezyka + '_' + nazwa_tabeli) i nie musisz robic zlaczen co pewnie przekladaloby sie na troche lepsza wydajnosc. Dodatkowa zaleta (z mojego punktu widzenia) jest to, ze poszczegolne wersje jezykowe sa od siebie odseparowane (do pewnego stopnia bo calkowitej separacji pewnie sie nie uniknie) co sprawia wrazenie lepszego porzadku. No ale to tylko moje zdanie :)

Oczywiscie do wszystkiego nalezy podchodzic z glowa. Jak Ci sie z jakis powodow nie oplaci robic kilku tabel to zawsze mozesz pozostac przy wersji z jedna dodatkowa tabela.

0

W javie są od tego gotowe cuda i robi sie to wg schematu numer 2.

0

Akurat w tym konkretnym przypadku. Załóżmy że w testowym katalogu projektu mam następujące pliki

i18n/pl.php

 <?php
return array(
); 

i18n/en.php

<?php
return array(
    'Strona domowa' => 'Home',
    'O nas' => 'About',
    'Kontakt' => 'Contact',
); 

i18n/it.php

<?php

return array(
    'Strona domowa'  => 'Casa',
    'O nas' => 'Riguardo a noi',
    'Kontakt' => 'Contatto',
);

Klasa helper: I18n.php

 <?php

class I18n
{
    public static $default = 'pl';

    public static function load($lang)
    {
        return include DOCROOT . 'i18n' . DIRECTORY_SEPARATOR . $lang . '.php';
    }

    public static function get($string, $lang = NULL)
    {
        if ($lang === NULL)
        {
	    $lang = I18n::$default;
        }

        $table = I18n::load($lang);
        return isset($table[$string]) ? $table[$string] : $string;
    }
}

if (!function_exists('__'))
{
    function __($string, array $values = NULL, $lang = 'pl')
    {
        if ($lang !== I18n::$default)
        {
	    $string = I18n::get($string);
        }

        return empty($values) ? $string : strtr($string, $values);
    }
}

oraz testowy index.php (testowałem na CLI)

 <?php
define('DOCROOT', realpath(dirname(__FILE__)).DIRECTORY_SEPARATOR);
spl_autoload_extensions('.php');
spl_autoload_register();

$menu = array('Strona domowa', 'O nas', 'Kontakt');

I18n::$default = 'pl';
echo "Polish translation:\n\n";
foreach ($menu as $item)
{
    echo "\t" . __($item) . "\n";
}

I18n::$default = 'en';
echo "\nEnglish translation:\n\n";
foreach ($menu as $item)
{
    echo "\t" . __($item) . "\n";
}

I18n::$default = 'it';
echo "\nItalian translation:\n\n";
foreach ($menu as $item)
{
    echo "\t" . __($item) . "\n";
}

Chociaż jako punkt odniesienia powinien być język angielski i I18n::$default powinno być ustawione na en a wszystkie klucze powinny być po angielsku a ich wartości to odpowiednie tłumaczenia i całe menu w bazie powinno być też po angielsku.

1 użytkowników online, w tym zalogowanych: 0, gości: 1