Witam,
Od jakiegoś czasu piszę duży projekt i doszedłem do wybierania języku. Chciałbym poznać Wasze zdanie jak ma działać taki system wielojęzykowości strony. Pobuszowałem po internecie i oto, co wymyśliłem.
Myślę ze dobrym rozwiązaniem są pliki. Stosuje sie je w wielu cmsach i projektach.
Tłumaczenia w bazie danych to według mnie zaśmiecanie db i w dodatku majac wiele jezykow robi sie syf i przedluza sie czas wyszukiwania.
Tutaj nalezy zadac pytanie jak stworzyc taki plik. Czy ma byc to plik php w ktorym definiuje się zmienne/stałe czy zwykły plik tekstowy typu
jeżeli w projekcie masz zamiar używać OPT, to ja na twoim miejscu użył bym opt'owego i18n ;]
Smarty: {config_load file="text.conf" section=$language} no i posprzątane
Ja korzystam z modifiera SMARTY
{"Jakis_tam_komunikat"|lang:"admin"}
A ja się bawię "słownikiem" - mam plik lang_pl.php, lang_en.php itp..... w bazie trzymam dla jakiego użytkownika jaki plik załadować (oczywiście to może później sobie zrobić). W plikach tych mam tablicę $Lang:
<?php $Lang['Enter'] = 'Wejście'; $Lang['Exit'] = 'Wyjście'; . . . ?>
Ja z kolei napisałem sobie plugin do Smartego. Templejty tworzę normalnie, używając naszego narodowego języka. Mam również plik XML, który nazywa się identycznie jak nazwa szablonu czy też modułu szablonu i zawiera tłumaczenia tekstów z templejta w wielu językach.
Np.:
Moduł szablonu: menu.mod.tpl
I ma taką wadę, że języki są różne i różną mają gramatyke... twoim sposobem czesto zdażyć się może, że nie da się w prosty sposób przetłumaczyć danego zdania.
http://developer.gnome.org/projects/gtp/translate-gnome/x22.html - pliki .po i ich dekoder napisany przez Bastiona to całkiem dobre rozwiązanie.
Fajnie też rozwiązał to NuLL, ale pliki .PO są bardzo popularne, istnieje też wiele programów służących do ich edycji, co upraszcza tworzenie nowych wersji językowych. gTranslator i KBabel, for example.
<?php $Lang['Enter'] = 'Wejście'; $Lang['Exit'] = 'Wyjście'; . . . ?>
Ja ze swojej strony mogę polecić draft i18n z Mojavi 4, całość prezentuje się iście interesująco.. niestety w chwili obecnej serwer Mojavi leży..
Ja mam strony wielojezykowe zrobione na podstawie bazy danych i dosłownie zero tekstu w kodzie html. Struktura plikow php wyglada podobnie jak bym smarty zastosowal.
Jeden minus to ze jest duzo zapytan do bazy i moze stanowic obciazenie przy wiekszym serwisie. Ale wtedy juz prosto mozna zastosowac cachowanie stron.
Ja osobiscie korzystam z plikow ini. Plik jezykowy globalny, + pomniejsze pliki jezykowe np: do konkretnego modulu. W Smarty korzystam z postfilter ktory podmienia odpowiednie ciagi znakow na wartosci np: [lang:mod_news,dodaj] na "Dodaj newsa"
ja wczytuje zawartosc pliku ini dla wybranego jezyka do tablicy (parse_ini_file) a potem po prostu:
{$lang[costam][costam]}
Moim zdaniem prawda znowu leży po środku - wydaje mi się, że pliki są bardzo dobrym rozwiązaniem, jeśli chodzi o teksty formularzy itp. Jednak co, jeśli ktoś będzie chciał tłumaczyć całe artykuły, znajdujące się w bazie? Wtedy najlepszym rozwiązaniem byłoby połączenie systemu pliki+baza.
Wydaje mi się, że można by stworzyć tabele osobno dla każdego języka, np. en_articles, pl_articles itp., bo trzymanie tych danych w jednej tabeli nie miałoby raczej najmniejszego sensu, skoro i tak są one wykorzystywane naprzemiennie, a nie razem.
PS. Nie jedźcie po mnie za bardzo, bo ostatnio w php coś pisałem chyba z pół roku temu:) I wesołych świąt wam życzę.
ID | Tytul | Tresc | Lang
SELECT * FROM tabela WHERE Lang=$_GET['lang']
<?php {$Translation.StronaGlowna} ?>
Teraz tak myślę i doszedłem do wniosku, że twoj podejście jest chyba lepsze od mojego (jeśli chodzi o trzymanie w bazie, bo xml i pliki to dla mnie to samo - wszystko zależy od możliwości serwera itp) - zakładając, że chcę dodać kolejny język, przy twoim podejściu mogę (przynajmniej teoretycznie) dodać go z poziomu panelu, nie grzebiąc w strukturze baz.
A co wy na to (suma kilku pomysłów):
A plik translacji wyglądałby oczywiście
<?php function array_path_insert(&$array, $sep, $path, $value) { $path_el = http://www.php.net/split($sep, $path); $arr_ref =& $array; for($i = 0; $i < http://www.php.net/sizeof($path_el); $i++) { $arr_ref =& $arr_ref[$path_el[$i]]; } $arr_ref = $value; } $trans=http://www.php.net/array(); foreach(http://www.php.net/file("translations/{$lang}.txt") as $line) { $chunks=http://www.php.net/explode("=", $line); http://www.php.net/define("TXT_".http://www.php.net/array_shift($chunks), http://www.php.net/implode("=", $chunks)); /* define("TXT_".array_shift($chunks), eval(implode("=", $chunks))); // tak jakby chciać tutaj włożyć jakąś logikę */ /* define("TXT_".array_shift($chunks), str_replace('\n', "\n", implode("=", $chunks))); // tutaj jakby nie chcieć interpretować wszystkiego */ /* można też zrobić preg_replace z tablicami */ /* XXX: Ależ mi nachodzi pomysłów. Dla tablicowców-smartowców następna wersja. (funkcje znalazłem w komentarzach do manuala) */ array_path_insert($trans, '.', http://www.php.net/array_shift($chunks), http://www.php.net/implode("=", $chunks)); } $smarty->cośtam('lang', $trans); ?>
A co, jeśli w tłumaczonym tekście wystąpi znak "=" bądź przełamanie linii?
Jabol: Muszę się zgodzić z Borą, wygląd pliku jest podobny do plików INI,a wprowadzenie tego w życie jest bardzije zamotane niż INI. Mój skrypt jest tylko silnikiem (albo słowo ostatnio bardzo popularne - frameworkiem) i nie ja go będe dalej rozwijał. Parse_ini_file jest w php4, pod które skrypt (niestety)...
Pewnie zaraz padnie pytanie: "Po co ten temat ?". Szukam jakieś alternatywy dla plików ini i wielkich tablic.
pozdrawiam
Witam,
Kilka dni temu pisalem klase opbsugujaca jezyk w moim frameworku. Wyglada to tak:
Klasa Language :
__construct($sLanguage = null)
1. jezeli podano w parametrze jezyk, ustaw go.
2. jezeli nie podano go, a ustnieje ciastko z nazwa jezyka (tlumaczenie strony w czasie trwania sesji), to zastosuja taki jezyk
3. w innym przypadku stosuj dod`myslny.
__get() dzieki ktorej w prtosty sposob korzysta,my z jezyka.
W pliku english.php mam tablice:
$aLanguage['main_menu_custam'] = 'SuperTurboMegaGigaUltraString ';
W aplikacji odwoluje sie do tego tak:
$oLanguage->main_menu_custam;
W szablonach wpisuje: {$LANGUAGE.MAIN_MENU_CUSTAM}.
Dziala :]
Przepraszam będe pisał bez shifta bo siedze w szkole
w każdym razie:
wg. mnie najlepszym rozwiązaniem jest to które już oferuje pewien mod do php (nie pamiętam niestsety nazwy ale jest nawet jego opis gdzieś w manualu):
polega on na korzystaniu z tablic zawierających całe tłumaczenia stringów i wywoływanie tłumaczeń np poprzez funkcję
a przedtem na załądowaniu tej tablicy do pamięci. Potem wystarczy napisać sobie edytor w c++ (czy co tam chcecie) który wyciąga wszystkie stringi zawarte w tych funkcjach np. w podanym katalogu i przedstawia wygodny formularz do tłumaczenia. Za to w plikach .php pisazemy sobie jakimś językiem referencyjnym np. angielskim.
<?php _("Tłumacz mnie"); ?>
takie wlasnie (podobne) rozwiaznie jest w klasie Babel, ktory korzysta z plikow .po / .mo z gettexta. nie trzeba pisac zadnego programu w c++, wystarczy skorzytac z progmau gettext
xgettext example01.php -L php -o pl_PL.po --keyword=_r --keyword=_p
i wycina do pliku po wszystkie ciagi tekstowe poprzedzone funkcja _r i _p
moze pomoze:
http://www.tutorialized.com/tutorial/Multi-Language-System/12488
pozdro
Odkopuje temat bo zastanawiam sie nad tym w jaki spsob, zgrabnie pobierac dane z tablicy z jezykami wewnatrz obiektu.
Moja tablica wyglada mnie wiecej tak:
<?php $lang['pl_PL'] = http://www.php.net/array( 'app' => http://www.php.net/array( 'title' => 'Test' ) ); ?>
<?php $landSetting = 'pl_PL'; require_once($landSetting . '.lang.php'); $foo = new Foo($lang[$landSetting]); class Foo { var $_lang = null; function Foo(&$lang) { $this->_lang = &$lang; } } ?>
<?php Lang::getMsg('app.title', 'pl_PL') ?>
Bardzo przydatny temat dla wszystkich którzy odwiedziają ten wątek: http://forum.mojavi.org/index.php?showtopic=1502&st=0
Są tam diagramy które ilustrują istotę działania. Polecam uwadze wszystkich.
Mam taką tablicę
<?php $lang=http://www.php.net/array ( 'Ave' => 'Łukasz Peroń', 'JK' => 'Jan Kowalski', ); ?>
<?php http://www.php.net/echo $lang['Ave']; ?>
<?php {%Ave%} ?>
a co powiedzie o languagefactory::GetLang()
a pozniej w miejscach w tpl <? $lang->get('id_slowa');?>
?
Moim zdaniem, (ja tak zrobilem w moim programie ktory teraz pisze), w pliku php, zrobic array :
Angielskie:
<?php $cp_Lang = http://www.php.net/array( "ok" => "OK", "yes" => "Yes", "no" => "No", "user not found" => "User not found"); ?>
<?php $cp_Lang = http://www.php.net/array( "ok" => "OK", "yes" => "Tak", "no" => "Nie", "user not found" => "U?ytkownik nie istnieje"); ?>
<?php function _($string) { $string = http://www.php.net/trim(http://www.php.net/strtolower($string)); $language = $_CFG['system_language']; require_once("i18n/lang.$language.php"); if(!http://www.php.net/empty($cp_Lang[$string])) { return $cp_Lang[$string]; } else { return $string; } } ?>
Witam
Odgrzeję kotleta...
Piszę średniej wielkości aplikację i także stanąłem przed problemem wielojęzyczności.
Miałem zamiar rozwiązać to przy pomocy plików językowych zawierających tablice z całymi "zdaniami"
Jednak po przeczytaniu tego tematu zainteresowałem się plikami .po/.mo (zwłaszcza, że miałem z nimi już do czynienia przy okazji tłumaczenia jakiejś gry...)
I teraz mam prośbę do kogoś kto kożysta z tego sposobu tłumaczenia w php.
Proszę o jakieś fragmęty kodu jak się używa tych plików.
I jescze nasówa mi się pytanie czy na serwerze nie musi być coś doinstalowywane żeby obsługa tych plików była możliwa, bo jeśli tak to niestety ten sposób lokalizacji odpada
Pozdrawiam
http://forum.php.pl/index.php?showtopic=42371&hl=babel
Można też skorzystać z TMX, zunifikowany opis XMLowy.
Nie wiem czy ktoś wogóle o tym słyszał czy używał, ale ja osobiscie pracuje z gettextem. Bardzo szybki, duzo narzedzi okienkowych, z webowymi jest gorzej, chociaz sam juz napisałem cos takiego ale jest jeszcze w wersji wczesnych beta, jesli nie masz tlumaczenia dla klucza, to pokazuje ci sie klucz, niby wymaga od uzytkownika zeby klucze byly pelnymi zdaniami, ale chociaz szablony dla widoku sa czytelniejsze. Problemy: trzeba przygotowywac pliki poprzez kompliacje.
Jeszcze jeden blad to to ze serverrobi cache plikow skompilowanych i przy czestej edycji nie widac poprawek. Ale sa sposoby na obejscie tego problemu
Właśnie o gettext była mowa, gdy wspominaliśmy o Babel oraz plikach .mo i .po
Problem multijęzykowości rozwiązałem w prosty sposób. Mam taką strukturę katalogów:
musiałbyś poprawić tylko jeden plik, czy się mylę ?
Korzystam z autorskiego edytora i 2 pluginów multijezykowych:
1. pierwszy pozwala mi pisać w kodzie php coś takiego
<?php http://www.php.net/echo('{*pl:To jest komputer**eng:This is computer*}'); ?>
oraz dodatkowy plik ze stałymi
<?php http://www.php.net/echo(''.lang_const_1.''); ?>
Widzę że prawie każdy skupił się tylko na jednej (IMHO prostszej) stronie medalu jakim są teksty stałe. Tutaj w zasadzie pomysły są 2/3 (tablice, pliki ini i pokrewne własne formaty i ewentualnie i18n) różniące się tylko sposobem implementacji. Mnie natomiast interesuje ta ciekawsza strona medalu jaką jest:
Jak rozwiązujecie kwestie wielu języków w bazach danych.
Jak do tego podchodzicie robiąc projekt z założenia 2-językowy (np. pl i en) oraz jak to rozwiązujecie mając w planie pełną wielojęzykowość bez z góry określonej liczby języków. Interesuje mnie nie tylko jak kształtujecie samą bazę ale także typowe odwołania do niej.
W przypadku projektów 2-językowych korzystam głównie z typowej konstrukcji wielokolumnowej:
id | date | title_pl | title_en | content_pl | content_en
dorzucając do niej ewentualnie pole boolean valid_{$lang} określające czy dany język występuje w danym rekordzie.
Użycie w kodzie dość banalne:
$SQL = 'SELECT title_' . $_USER['lang'] . ', content_'' . $_USER['lang'] itd
Natomiast w przypadku projektów wielojęzykowych mam zawsze dylemat jak konstruować bazę danych.
Czy mi się wydaje czy to jest jeden 'artykuł' -> wiele wersji? Bo takie określenie podsuwa od razu sposób rozwiązania.
czyli tabele wiążącą 'artykuł' z treścią, coś w stylu:
artykul_id|tresc_id|jezyk_id
(czy coś podobnego, bo język można przecież określić na zbiorze, ale z drugiej strony może być w tabeli języków nazwa skrótowa jak i cała, też ułatwi sprawdzenie jakie języki obsługuje)
Ale to tak na z marszu piszę, do tego mam nikłe doświadczenie, więc lepiej niech ktoś lepszy w tych sprawach skomentuje...
Moim zdaniem baza danych w zupełności odpada, bez sensu, przy dużych iloścach informacji czas działania aplikacji zwrasta, a nie o to chodzi. U mnie wszystkie pliki językowe siedzą w plikach:
/Application/Languages/Polish/Polish.Language.php - domyślny plik języka polskiego
/Application/Languages/Polish/Subgrupa_Polish.Language.php - inny plik języka polskiego, przykład:
/Application/Languages/Polish/Register_Polish.Language.php
Budowa takiego pliku jest następująca:
<?php final class fr_Vlang extends VlangPattern { public $foo = 'C’est le foo.'; public $change_id = 'Polski'; public $change_sr = 'FR'; public $entry_add_true = 'L’entrée a été ajoutée avec succes! Afficher?'; public $entry_add_false = 'Erreur de base de données, entrée non ajoutée!'; public $entry_add_false_text = 'Copiez ici le code a ajouter!'; public $entry_add_false_token = 'L’identifiant d’autorisation est erroné!'; public $entry_link = 'Voici le lien vers votre entrée:'; public $entry_connection_lost = 'Impossible d’accéder au serveur, réessayez.'; // itd itd itd... } ?>
Hm... Jest trochę prostsze rozwiązanie, z którego ja korzystam. Może i jest przez to więcej rekordów w bazie danych... no ale cóż
Ogólnie koncepcja jest prosta. Mamy tabelę articles:
id | date | title | body | author |lang
Pole lang jest polem CHAR (2) w którym mamy podane np.: pl, en, fr...
Czyli pobranie artykułu po angielsku to po prostu:
<?php $test = http://www.php.net/mysql_query('SELECT * FROM articles WHERE lang='en'); ?>
rozwiazanie powyzej jest fajne, ale ma jedna wade: dane w bazie sie powtarzaja
ja uzywam symfony i rozwiazania z tamtego frameworka, czyli mamy dwie tabele w jednej sa dane, ktore sie nie zmieniaja np id uzytkownika, data utworzenia a w drugiej teksty powiazane za pomoca klucza obcego i dodatkowo pole z jezykiem
No, powtarzają się, ale jest to bardzo łatwe do zaimplementowania. Odpowiednia budowa tabel w bazie danych a będzie śmigać aż miło
Ja podobnie jak ~bela używam symfony i uważam tamto rozwiązanie za optymalne. Zarówno pod względem przechowywania elementów interface i treści w bazie danych. Polecam zapoznanie się z tym jak jest to tam http://www.symfony-project.com/book/trunk/13-I18n-and-L10n
jezeli ktos sie zdecyduje na symfony, to radze pobierac przez metode doSelectWithI18n, bo samo doSelect nie pobiera danych z jezykow i za kazdym razem wali selecta.
Od jakiegoś czasu zastanawiam się na wielojęzykowością w moich projektach i patrząc na potrzeby moich klientów widzę cztery mechanizmy opisujące ich oczekiwania:
1. Klient chce mieć TYLKO z góry określoną liczbę języków.
W takich wypadkach robię po prostu jak kolega wyżej zaproponował, czyli kolumny w tabeli: tytul_pl, tytul_en etc.
2. Klient chce mieć stronę w kilku językach ale one generalnie są niezależne (różne działy etc.).
Wtedy po prostu robię kilka stron, którymi da się administrować z jednego panelu.
3. Klient chce mieć jedną stronę w kilku językach, każdy artykuł w różnych wersjach językowych.
Internauta przełącza się pomiędzy wersjami za pomocą linków (np. chorągiewek z flagami).
W bazie jest to zapisywane jako relacja n do n pomiędzy artykułami i językami gdzie w relacji łączącej jest zapisany tytuł i treść artykułu w odpowiednim języku.
4. Klient chce mieć stronę generalnie w jednym języku (menu etc.) ale poszczególne artykuły w kilku wersjach wyświetlanych na jednej stronie.
Baza jest podobna do tej z pkt. 3.
Przypadek 1. jest szczególną formą jednego z pozostałych.
Ostatnio zastanawiam się nad wyglądem linków wielojęzykowej strony.
Z jednej strony ciekawym rozwiązaniem było by budowanie strony na zasadzie: "example.com/kontakt/" - dla polskiej wersji językowej, a "example.com/contact/" - w przypadku anglojezycznej wersji. Ale co w przypadku gdy np po niemiecku kontakt pisze się tak samo jak po polsku, można zawsze wczytywać język przeglądarki w takim wypadku i zapisywać go do sesji, ale czy to nie będzie "przyrost formy nad treścią"?
Dodatkowa sprawa to zapisywanie jak mają wyglądać linki w danym języku, pobieranie z bazy danych bądź pliku zawsze trochę zmniejszy trochę szybkość
No i jak na takie rzeczy reagują wyszukiwarki, bo zmniejsza to chyba to skuteczność trafności wyników.
Macie jakieś inne ciekawe sposoby na budowanie odnośników na stronach wielojęzykowych?
Mam podobny problem jezykowy przy tworzeniu strony moich rodzicow.
Maja biuro projektowe, a na stronce chcą miec dane kontaktowe oraz opisy wraz ze zdjąciami budynków przez nich zaprojektowanych.
Wymyśliłem nastepujace rozwiazanie:
- dane stale takie jak dane kontaktowe, wszystkie podpisy (menu, strona główna etc.) przechowywał bym w plikach lang_xx.php
- a dane zmienne (opisy budynków, zdjęć etc.) dodawał bym do bazy danych przy czym każdy język... i tu sie pojawia problem czy lepiej żeby miał osobną baze (np. sim_pl etc.) czy wystarczy osobna tabela (np. opisy_pl etc.)
chyba ze by było jakieś jeszcze lepsze rozwiązanie.
moja idea:
<?php class language { function __construct($language='pl'){ $this->language=$language; $this->get_data(); } function __get($id){ return $this->data[$id]; } function get_data(){ /* funkcja jakoś pobierze dane językowe, np z bazy danych mysql */ /* mogą być to dane zapisane już jako tablica w pliku php */ http://www.php.net/mysql_query(); include 'plik_z_jezykiem_'.$this->language.'.php'; /* etc. */ $this->data=... } } $l='pl'; $lang=new language($l); http://www.php.net/echo $lang->10; http://www.php.net/echo $lang->1337; ?>
Mój sposób wygląda tak:
Plik Global_Lang.php:
<?php $glang[] = 'polish'; $glang[] = 'english'; $glang[] = 'spanish'; ?>
<?php $interface['val1'] = null; $interface['val2'] = null; $interface['val3'] = null; //... itd są to indexy które muszą występować w każdym pliku językowym w tym folde
rze ?>
<?php $lang['val1'] = 'czesc'; $lang['val2'] = 'czas'; $lang['val3'] = 'zegnaj'; ?>
<?php $lang['val1'] = 'hello'; $lang['val2'] = 'time'; $lang['val3'] = 'goodbye'; ?>
A mnie tak ciągle zastanawia, dlaczego artykuły/newsy itp. idą z id języka do bazy danych, a już np. nazwy działów lecą do plików?
Przecież to są informacje które można modyfikować, jak jeszcze założymy że tych elementów nie można przez panel admina ruszać to można by było podciągnąć pod statyczne elementy, ale przy możliwości dodania języka?
Ale może niech ktoś, kto ma jakieś pojęcie o tym wypowie, bo ja sobie tak gdybam i tylko jedna rzecz przychodzi mi do głowy, która może determinować wybór, aby za każdym razem nie pobierało danych z bazy.
Tylko że baza ma służyć do przechowywania i sprawnej dystrybucji danych...
Pojawił się w tym wątku pomysł, aby trzymać dane zależnie od języków w odpowiednich tabelach, przykładowo:
Przy nazwach tabel z dodanym oznaczeniem języka, konieczne by było posiadanie modelu dla każdej tabeli, lub co wydaje mi się prostsze i oczywiste, zbudowanie jakiegoś Factory dla tych modeli - w momencie, kiedy tworzę model, sprawdzam czy jest to tabela wrażliwa językowo i wtedy uruchamiam fabrykę. Dzięki temu, zawsze do danych o artykułach dostanę się przez $this->ArticlesModel (nie potrzebuję mieć, ArticlesPl_Model czy ArticlesDe_Model). Również przy dodaniu języka nie interesuje mnie budowa nowego modelu - factory zrobi to za mnie.
<?php $this->ArticlesModel->FinById(10); ?>
Ja bym szybciej jedną tabele `article` i w niej kolumny:
id|lang_id|... PRIMARY KEY (id,lang_id)
bo obie są unikalnym identyfikatorem, zakładając że mam powiązania miedzy artykułami w różnych językach.
A wybieranie to z automatu dodawany jeden warunek, jak nie ma rekordu z takimi warunkami to nie ma, a nie tworzy bóg wie ile tabel.
@Sedziwoj - masz oczywiście rację, zdaje się, że trochę się zapędziłem :)
Jedna tabela z oznaczeniem języka dla każdego rekordu to faktycznie bardziej elegenackie rozwiązanie.
pozdr.
Dawno nie pisałem na forum dlatego pozdrawiam i witam wszystkich. Sporo siedziałem nad tym tematem i chciałbym pokazać swój sposób i prośić o ewentualny komentarz:
1. Tabela bazy sql "languages" zawiera pola: ID | name | short . Można ona pomiescić dowolną liczbę języków.
2. Przy starcie strony wybierany jest język o ID=1 który jest językiem głównym. Jego parametry zapisane są w sesji: $_SESSION["language"]="polish" $_SESSION["language_id"] = 1 $_SESSION["language_short"] = "pl". Teraz możemy dla całego serwisu wykożystywać te zmienne. Czasem przydają się wszystkie 3.
3. Kliknięcie na flagę języka zmajdującej się gdzieś na witrynie powodujemy zmianę tych 3 zmiennych.
4. Ładowane są odpowiednie pliki które zawierają definicje sztywne np: define( "_COM_NEWSLETTER_TITLE", "Newsletter" ); Zeby wszystko działało gładko każdy komponent ma swój plik z tłumaczeniem np "russian_newsletter.php". Każdy plik zawiera w nazwie język tak żeby przypadkiem sobie nie nadpisać przy wysyłaniu na serwer róznych plików językowych.
5. Każda tabela z tekstami wprowadzanymi do bazy zawiera pole "language" identyfikujący język. Nie tworzę osobnych tabel dla innych języków, dzięki temu przy dodaniu nowego języka nie muszę tworzyc nowych tabel dla każdego komponentu.
==================
6. Zauważyłem, że taki system pozwala na dużo ciekawych rozwiązań np:
--- Można używać języka o ID=1 jako języka głównego a resztę jako reference. Wtedy przy odpowiedniej konfiguracji serwisu jeśli jakieś tłumaczenie nie istnieje łąduje się język główny i informacja, że wyświetlony został język natywny.
--- Można wysłać do tłumacza cały folder lub plik z tłumaczeniami sztywnymi.
--- Zmienną $_SESSION["language_short"] dobrze wykożystuje się do obrazków. Serwis może dla róznych języków załadować np "logo_pl.jpg" lub "logo_en.jpg"
A ja się zastanawiam nad sensownością innego rozwiązania wielojęzykowości. Generalnie jeśli chodzi o treści statyczne (czy to formularze, czy proste zwroty na stronach wbudowane w szablon), to rozwiązanie na poziomie plików (sposób dowolny) wydaje się najsensowniejsze. Jeśli jednak chodzi o wielojęzykowość treści podlegających ciągłym zmianom takich jak na przykład artykuły, wiadomości i tym podobne sprawy, rozwiązanie praktycznie musi leżeć po stronie bazy danych.
Myślałem jednak nad rozwiązaniem tego w następujący sposób (to tylko czyste spekulacje, bo nie próbowałem tego wprowadzać w życie).
Tabela odpowiadająca za artykuły (w sensie produkty, bo przykładem będzie wielojęzykowość na potrzeby e-commerce) przechowywane w bazie wg. pewnego bliżej nieokreślonego, przykładowego schematu (typy pól nieistotne):
Tabela: products
ja stosuję metodę zapisu do bazy każdy element ma swój prefix językowy na tej podstawię identyfikuję wszystko.
W http://phpdoctrine.org/ jest plugin do i18n. Wielojęzykowość staje się wtedy bardzo przyjemna.
http://www.phpdoctrine.org/documentation/manual/0_10?one-page#plugins:internationalization-with-i18n
a jak w tym doctrine wyglada to tłumacznie ? Osobne tabele ? Bo przy jednej jezykowosci jakos to widze przy powiedzmy 6-10 prawdopodobnie zaczely by sie schody z iloscia rekordow, a nie mowiac juz o wiecej ilosci rekordow powiedzmy z wiadomosciami, opisami, cechami przedmiotow/produktow.
No i czy to by uwzglednialo powtarzajace sie frazy.
Pytam tak bo szukam jakiegos dobrego rozwiazania wielojezykowego i jedynie na chwile obecna gettext jakos dziala, ale to tez ma swoje ograniczenia.
Przykład z dokumentacji doctrine:
news:
id | content
news_translation:
id | title | lang
W tym przypadku dla newsów będą tytuły w różnych językach. A używając doctrine wyciąga sie je tak:
<?php //po wykonaniu wcześniejszego Doctrine_Query http://www.php.net/echo $items[0]->Translation['PL']->title; // 'Witaj Świecie' ?>
(sorry za odkop)
Nie można po prostu użyć prefixów w bazie danych? np.
tabela
pl.news
en.news
w PHP:
<?php //[...] $lang_prefix = ('pl'); $sql="SELECT * FROM ".$lang_prefix."news ORDER BY dodano DESC"; //[...] ?>
<?php //[...] $lang_prefix = ('pl'); $sql="SELECT * FROM ".$lang_prefix."news ORDER BY dodano DESC"; //[...] ?>
Mam jeden prosty i sprawdzony sposób.
<?php http://www.php.net/echo __('Witaj Świecie!'); ?>
@radex_p
Co innego tłumaczenie statycznych rzeczy, co innego dynamicznie dodawanych.
Co masz na myśli? Te tablice z tłumaczeniami są (o ile dobrze zrozumiałem) statyczne.
EDIT:
Chyba już wiem, co miałeś na myśli. Napisałem "przyporządkowuje". __() nie dodaje tłumaczenia, tylko zwraca tłumaczenie stringa zawartego w argumencie.
@radex_p - myślę, że chodziło o np. artykuł dodawany do serwisu. Który tłumaczysz na polski, angielski czy niderlandzki.
aaaaa..... Teraz już rozumiem
Dokładnie, bo można rozgraniczyć na dwa rodzaje, jeden to to co jest właściwie raz tworzone, czyli komunikaty, teksty np. "Dodaj komentarz" itp. co jest przez nas robione, drugie to są rzeczy dodawane dynamicznie, czyli artykuły, wiadomości czy co tam w aplikacji zaoferujemy. Te drugie są w bazie danych więc, oczywiste jest że wszystkie wersje językowe tam muszą być.
Co do pierwszych, no to już jak widać różne opinie, ja do opisu statusów wykorzystuję bazę danych, bo i tak muszą być w bazie przez FK. Co do tekstów, to można zrobić tak jak już było nieraz podane, przez funkcję, ale tak na prawdę skąd ona bierze te dane, to już inna sprawa, ważne jest że w kodzie widzimy tekst jaki ma się pojawić a nie jakiś jego znacznik.
Można by dyskutować, a co jak nie będzie działać baza danych? Ale tak na prawdę to jak nie działa, to już cała strona też, więc tylko komunikat o niemożliwości połączenia z bazą musi być w pliku zapisany.
Obecnie korzystam z Symfony i podoba mi sie jak to tam jest rozwiązane.
Przypomne:
Teksty statyczne - XML i funkcja __('tekst')
Teksty dynamiczne - dwie tabele, np. products (id, symbol, item_number) i products_i18n(id,lang,name,description)
Jedyny minus Symfony to jeżeli brak tłumaczenia dla danego obiektu (np. nazwy produktu), wyświetlany jest pusty string, a w mojej aplikacji chciałbym żeby jeśli np. brak tłumaczenia polskiego, było wyświetlane tłumaczenie angielskie domyślnie. Oczywiście da się tak zrobić modyfikując propelowy generator, no ale znów generuje to dodatkowe zapytania do bazy.
Swojego czasu napisałem własny ORM który wykorzystał rozwiązanie jakiego tu jeszcze nikt nie zaproponował
Miałem tabele w bazie danych:
strings
id (int)
lang
content (varchar255)
texts
id (int)
lang
content(text)
gdzie id i lang były kluczem głównym. Jeżeli w którejkolwiek innej tabeli miał być content zależny od języka, oznaczałem to tak:
products
id
symbol
string_name (int)
text_description (int)
ORM w momencie pobierania obiektu z bazy danych, przed przygotowanie query, jeżeli napotkał pola z prefixem "string_" bądź "text_" robił joina z odpowiednia tabela strings bądż texts. Podobnie przy zapisie i uaktualnieniu danych.
Co sądzicie o takim rozwiązaniu? Jego zaleta to taka, że nie muszę projektować dodatkowych tabel _i18n, wystarczy że wszystkie pola zależne od języka będę oznaczał jako string_ bądż text_. Wada to oczywiście dodatkowy join w każdym zapytaniu (ale w symfony jest to samo), koniecznosc napisania wlasnego orm badz zmodyfikowania istniejacego, no i tak jak wcześniej napisałem, problem gdy chcemy korzystać z degradacji języka (czyli nie ma polskiego to angielski, nie ma angielskiego to niemiecki itp)
@joohn
Wada, to że wszystkie teksty są wrzucone do jednego worka, czyli tak na prawdę nie wiemy co to jest, tylko tyle że jakieś teksty.
Witam!
Podsumowując, moim zdaniem optymalnym rozwiązaniem:
dla elementów stałych jest utworzenie przykładowej klasy Language:
[b]artykuly[/b] id | autor_id | lang_id | tytul | zawartosc | ogladany | komentarzy | ocena | ... ------------------------------------------------------------------------------------- 1 | 476 | 1 | PHP 6 | content.. | 23 | 9 | 5 | ...
SELECT tytul, ogladany, ocena FROM artykuly WHERE lang = 1
[b]artykuly[/b] id | ogladany | komentarzy | ocena | ... ----------------------------------------------------------------------------------------------- 1 | 23 | 9 | 5 | ...
[b]artykuly_lang[/b] ... | art_id | lang_id | tytul | zawartosc | ... ----------------------------------------------------------------------------------------------- ... | 1 | 1 | PHP 6 | content.. | ...
[b]lang[/b] id | short_name | name -------------------------- 1 | pl | Polski
@rzymek01
Jak masz kolumnę lang, to niech to będzie integer, po co męczyć bazę stringiem, do tego najlepiej lang_id, i tabela gdzie jest id|short_name|name czyli skrócona nazwa języka np. PL i pełna Polski.
racja, mój błąd
nie chciałem już mieszać, bo na początku chciałem zrobić lang_id
Kolejny odkop no ale..
Ja uzywam dwoch tabel: jedna dla tzw. metadata czyli ID, kategoria; druga dla samych tlumaczen. Przypisuje im jezyk za pomoca lang_id w drugiej tabeli, I wyciagam z bazy za pomoca JOINa. Ogolnie ten skrypt co mam automatycznie wybiera jezyk przegladarki dla uzytkownika, lub - jezeli nie ma takiego jezyka w systemie - wybiera jezyk domyslny (angielski).
Zakladajac ze w bazie danych nie zawsze bedzie tlumaczenie dla kazdego artykulu w jezyku uzywanym w tym momencie przez uzytkownika, jak moznaby sformulowac zapytanie do SQLa tak aby przy wyciaganiu artykulow dla danej kategorii wyciagalo wszystkie artykuly w wersji jezykowej uzytkownika lub w wersji jezyka domyslnego jezeli poprzednie sie nie powiodlo? Poki co moim rozwiazaniem jest SELECT na wszystkie lang_id, i potem sprawdzanie co wyswietlic a co nie za pomoca PHP, ale to troche badziewne rozwiazanie IMO. Ktos sie natknal na taki problem?
@Blodo
Może coś w tym stylu:
SELECT * FROM base_data AS b LEFT JOIN lang_data AS l ON ( l.base_data_id = b.id AND l.lang_id = x) LEFT JOIN lang_data AS l2 ON (l2.lang_id = y AND l.id IS NULL);
Hmm, dobry pomysl. Co prawda trzeba w php potem sprawdzic ktore pole z tabeli nie jest "NULL", no ale i tak lepiej niz bylo. Dzieki ci za to.
Wybaczcie, że odgrzewam temat. Baardzo długo zastanawiałem się nad rozwiązaniem wielojęzykowości w moich skryptach. Końcowo doszedłem do wniosku, że idealnym rozwiązaniem będzie wykorzystanie systemu wbudowanego w OPT oraz kilku ciekawych ulepszeń. Po pierwsze, wszystkie stałe językowe przechowywane są w kategoriach niezależnych od czegokolwiek. Grupujesz jak chcesz, potem wczytujesz te grupy. Wczytanie jednej stałej z grupy powoduje wczytanie wszystkich z danej grupy.
Załóżmy, że mamy takie grupy:
mam pytanie jak sobie radzicie z wersją językową przechwyconych wyjątków, w każdej klasie jest:
<?php throw new exception (..) ?>
Ale w jakim celu tłumaczyć wyjątki? One są raczej informacją dla programu/skryptu, a nie użytkownika.
Możesz:
1) Przeklazać już odpowiednio przetłumaczony wyjątek:
<? throw new Exception(myTransolator('invalidABCDE')); ?>
Ale jeszcze raz zapytam: po co?
<? class MyException extends Exception{ public function __construct($msg = '', $code = 0){ $this->msg = myTranslate($msg); $this->code = $code; } } ?>
załóżmy, że mam klasę Config, która jest Singletonem i pobiera z pliku .ini wersję jęzkową systemu
jezyk = "pl" i w zależności od tego klasa Lang, parsuję odpowieni plik .ini z folderu gdzie znajdują się odpowiednie wersję językowe
co jeśli w pliku settings.php parsowanym przez klasę Config, użytkownik wpiszę język, który nie jest uwzględniony w folderze w którym znajdują się wersję językowe? pozostaję wypluć wyjątek, tu właśnie pojawia się w problem w jakim on ma być języku i jak ten język zaimplementować w klasie Lang i Config?
pzdr
Nie zawsze wyjątki są najlepsze, powinieneś sprawdzić czy dany język istnieje jeśli nie to ustawiany jest domyślny. Jeśli gdzieś w serwisie jest użyte coś, czego nie ma w pliku językowym to jest błąd, i taka informacja też nie musi być rozpowszechniana po prostu wymuszenie przez moduł językowy załadowania informacji o błędzie/braku informacji, to już jest statyczna informacja niezależna od błędu, no i log dla nas aby dojść co się sypnęło.
Witam,
tak pobieżnie przeglądając odpowiedzi nie widziałem sposobu z definiowaniem zmiennych językowych jako stałe np. define('HELLO_WORLD","Hello world"); echo HELLO_WORLD. Co o tym sądzicie?
Pozdrawiam
Mało przenośne. Co w sytuacji, gdy np. stała konfiguracyjna będzie nosiła tę samą nazwę jak językowa?
Poza tym, wg Twojego schematu idealny byłby http://pl.php.net/gettext.
tak tylko aplikacja ma być przenośna, a gettext nie wszędzie jest zainstalowany.
No i jeszcze wchodzi w grę licencja tego typu rozwiązań - odpada GPL.
To zainteresuj się Zend Framework (i zanim napiszesz coś o gettext przeczytaj dokładnie dokumentację).
To include GNU gettext support in your PHP build you must add the option --with-gettext[=DIR]
przeczytałem i ?
Nie miałem siły przeglądać całego watku, ale moim zdaniem najlepszym wyjściem jest podany 3 posty wyżej przez erixa sposób. http://pl.php.net/gettext Oczywiście jakaś nakładka na to co by zapamiętała jakie frazy używam w systemie i generacja pliku .po A później już z górki :]
Przez 2 lata używałem zwykłych zmiennych includowanych do klasy języków i metodą get() pobierania ich. Ale to nie jest wyjście. Ciężko się połapać w tym wszystkim.
viking: ok, ale aplikacja jest dosyć rozbudowana i nie ma już sensu przenosić jej na zend'a...
Zapewne da się ten komponent "wyciąć" z niego i stosować osobno.
Wordpress jest najlepszym przykładem. Ja także nie używam gettext(), jedynie się na tym wzoruje. Poszukać w google wystarczy "i18n php" i wyskoczy wiele różnych rozwiązań. Nawet na tym forum jakieś znalazłem
Ewentualnie w PHP 5.3 jest coś takiego http://pl2.php.net/manual/en/class.messageformatter.php
Tyle, że na php 5.3 na serwerach troche trzeba poczekać Kolega robił update php wczoraj, ale na trójkę się nakłonić nie dał... nie wiem czemu ;/ ("bo wyszła dzisiaj")
Dziwisz się? Osobiście np. Fx-a zaktualizuje za może miesiąc; obie paczki są jeszcze za świeże, nie zostały wystarczająco przetestowane.
Wyjdzie 5.3.1, będzie można się nieco pobujać. [; Ale nie zmieni to faktu, że w ogóle na edycję 5.3 trzeba jeszcze poczekać co najmniej pół roku.
Tak, do zalet gettext należy to, że jest lekki, szybki praktycznie ogólno dostępny... ale przekonaj klienta, żeby pobrał sobie z serwera pliczek z tłumaczeniami, pobrał i zainstalował sobie dodatkowe oprogramowanie np. poedit, wyedytował, a następnie wysyłał na serwer. Można też zrobić interfejs do aplikacji i generować np poprzez jakiś panel admina... jest jendno 'ale' - generowanie plików z tlumaczeniami, co wiąże się z dostepem do poleceń systemowych na serwerze... chyba malo ogolno dostępne, prawda? :-)
Dodatkowo: http://us2.php.net/manual/en/ref.gettext.php#50424 ;-)
Osobiście szczęśliwie korzystam z Zend_Translate oraz pliczków CSV - lekkie, proste, szybkie, wygodne i można bez zadnych przeszkód napisac do tego gui :-)
Jakoś we wszystkich hostingach, z którymi mam do czynienia, polecenia systemowe nie są zablokowane.
Więc śmiem twierdzić, że to nie jest promil.
A ja stosuje podzial na baze i pliki:
np w cmsie zrobilem sobie ze jezyk jest subdomena serwisump, en.domena.pl czy de.domena.pl.
Szablony stron, teksty i inne elementy pisane sa osobno pod kazdy jezyk.
A jesli chodzi o statyczne teksty typu "Zapisz", "To pole jest wymagane" - wiadomo, pliki.
Chciałam się poradzić w jednej sprawie dotyczącej spraw wielojęzykowości. Mam stronę w kilku językach, ale podstrony w tych językach niewiele różnią się od siebie. Strona zawiera głównie grafiki. To czy lepiej tłumaczyć fraz na tej stronie czy całą stronę. To znaczy, czy lepiej w kodzie tej strony, między grafikami mieć np $lang['tlumaczonytekst'], czy trzymać w bazie treść strony dla każdego języka i ładować odpowiednią stronę w zależności od wyboru usera? Teraz stosuje pierwsze rozwiązanie ale może tabela kolumnami textid, contentpl, contenten? Czy powinnam zastosować drugie rozwiązanie czy pozostac przy pierwszym?
pozdrawiam Jola
Zapomniałam napisać wprost, przy tej mojej metodzie z jedna stroną i tłumaczeniem fraz mam dużo małych zapytań do bazy. Gdybym zmieniła metodę to miałabym jedno duże zapytanie. Ale musiałabym mieć dwie treści i modyfikacje wprowadzać dwa razy i pamiętać o nich. Co lepsze?
A przeczytałaś cały wątek?
W Twoim przypadku 1. sposób wydaje się lepszy, tylko od razu pobieraj wszystkie langi (dużo ich na pewno nie masz) albo zapisuj je w pliku (lub plikach jak chcesz podzielić na moduły)
Oczywiście, że przeczytałam ten wątek, co za pytanie. Chcę się jedynie upewnić. Sposób 1 wydaje mi się wygodniejszy, dlatego go wybrałam. Ale obawiałam się o wydajność. Bo to kilka/kilkanaście zapytań do bazy, zamiast jednego dużego.
pozdrawiam Jola
Korzystał ktoś kiedyś ze Smarty Multilanguage? Jeśli tak - jaką to ma wydajność?
Dzięki za info
Pytanko/dylemat:
Zaznaczam od razu, że nie chodzi mi o artykuły/newsy. Chodzi mi o komunikaty w stylu: "dane zapisano", "Dodaj komentarz" etc.
Do tej pory miałem to w plikach .ini i było wszystko ok. Stanąłem jednak przed problemem, gdzie będę musiał dać klientowi możliwość edycji tych danych w panelu serwisu. Babranie się tu w edycję plików i do tego sensownie to grupować już nie jest takie fajne i przyjemne jak wówczas, gdyby to było wszystko bazie.
Do tego dochodzi problem, że ja mogę uaktualniać moduły i wraz z modułem mogą się uaktualnić pliki z tekstami. Jeśli klient by coś już zmodyfikował to ja przy aktualizacji bym mu to nadpisał.
A więc możliwe dwa rozwiązania:
1) pliki .ini
piszę jakiś systemik do aktualizacji danych. minusem będzie to, że gorzej się go będzie pisało niż dla DB
gdy klient zmodyfikuje jakiś zestaw danych, tworzony jest dodatkowy plik .ini z jego zmianami.
Gdy system będzie musiał odczytać jakiś tekst, szuka go najpierw w plikach zmodyfikowanych a jeśli tam go nie będzie, szuka w moich oryginalnych.
Jak widać trochę latania przy pobraniu tekstu tu będzie. Powiedzmy że bym zastosował cache to może by było znośnie.
2) tłumaczenia w bazie
O optymalność się nie martwie bo bym cacheowal.
Napisanie systemiku do edycji - w miarę proste.
Gdy ja dostarcze aktualizacje modułu z nowymi tekstami to wystarczy wykonać parę insertów i po sprawie - nic nikomu nie nadpiszę.
Minus - całe zarządzanie mam już na plikach .ini i bym musiał do bazy wrzucić wszystkie tłumaczenia jakie do tej pory mam.
Co Wy sądzicie o tym? Mieliście już do czynienia z taką właśnie sytuacją, że trzeba dać klientowi narzędzie do modyfikacji tekstów i mieć na uwadze kolejne aktualizacjie oprogramowania wraz z tekstami?
Jeszcze nie miałem takiej konieczności, jednak IMHO łatwiej byłoby w bazie.
Rozpisałeś mi tutaj zaawansowany system w DB: akceptacja, zestawienia.... aż tak bardzo nie chciałem szaleć
No nie rozwiałeś moich wątpliwości. To teoria, z której zdaję sobie sprawę. Mam nadzieję, że ktoś praktycznie miał z tym do czynienia.
edit:
dobra, robie na bazie. na plikach już mam to trzeba zadbac o nowe doświadczenia
A może zastosuj bazę i zrób małego bota co Ci wrzuci wszystko z tych .ini do bazy?
juz przepisałem ręcznie
Wszyscy się zastanawiają jak robić tłumaczenie, ale najprościej moim zdaniem zrobić podobnie jak ma wordpress. Sam tworzyłem teraz czterojęzyczny serwis i wychodzi, że najprościej jest dać np. w templatkach
Dla statycznych tekstów najlepiej jest użyć gettext. A dla trzymanych w bazie to l18n
Hmm, ja miast gettext korzystam z własnego sytemu z racji tego, że były problemy z tym gettext. Cachowało mi jakimś cudem plik i nie było możliwośći wgrania najnowszwego pliku. Co do danych typu newsy, mam kolumnę lang i później w zapytaniach where :langW: tzn. where lang = 'pl'
Dokładnie, to żadna sztuczka ta wielojęzyczność. Mi tam gettext działa bez problemu, tylko to trochę upierdliwe jest z tymi tłumaczeniami ;p trzeba się opisać jak głupi
@bim2: chyba osobną tabelę łączoną w relacji 1-1 (z id oraz językiem), a nie samą kolumnę
No tak. Zależy co masz. Jak mam stronę statyczną gdzie występuje tylko Tytuł i Treść to mam jedną tabelę, bo tytuł też tłumaczymy A id takie samo.
nie wiem czy ktoś już to pisał :F
ja mam różne języki zapisane w tablicach php i je wrzucam do templatki tak jak pozostałe zmienne. Kwestia pobrania odpowiedniego pliku językowego
jmail także tak miałem, ale po n serwisach to jest niewydajne w trakcie pisania tego. Musisz dodać sobie do tablicy wpis, później w templatkach {$lang.user} Tylko nie wiesz ci kryje się pod user jakbyś chciał coś zmienić/dodać.
Gettext jest najlepszym wyjściem i radzę Ci się na to przerzucić.
no jak tam kto uważa. dla mnie to jest wygodne i wydajne nie miałem jakoś probolemów do tej pory i jakoś tam działało ale przejrzę to co proponujesz i zobaczymy
Ok przeczytalem caly watek wywnioskowalem troche z niego tworzac wlasny "Fw" mysle ze przyda sie standartowa implementacja wielojezykowosci.
Dla stalych tresci zrobie to porostu tak:
Mam komponent news i jego opis autor,data,tresc i tytul i katalog jego widokow czyli:
$err['pl']['badpwd'] = 'Zle haslo'; $err['eng']['badpwd'] = 'Bad login';
if(blad podczac logowania) $view -> AddVar('error', $lang -> errors[$lang -> getLang()]['badpwd']);
Ja byłbym nadal za i18n, nawet dla błędów czyli $lang->get('Wrong login.');
Czyli jak i gdzie zapisywac bledy?
Bo nie rozumiem.
Nigdzie. Piszesz błąd jaki wystapił a tłumaczenie działa na zasadzie tłumaczenia całych fraz. Tj. ja mam w bazie danych tabelę langs z kolumnami hash|pl|en|pt|es Hash to md5 frazy, a reszty się chyba łatwo domyślić. Wszędzie piszę domyślnie po polsku czyli jak mam błąd to robię
$form->addError($lang->get('Niepoprawne hasło.'));
Wole to trzymac w plikach i zrobic tak jak ja to rozpisalem.
P.S ale dzieki za nastepna metode
Po 5 zleceniach odechciewa się szukania języków po plikach, sprawdzania poprawiania. Po przerzuceniu się na ten sposób odczujesz wielką ulgę Naprawdę, przestaw się już teraz będzie mniej problemów później :]
Kazdy komponent/plugin bedzie mial katalog errors a w nim plik z o nazwie takiej samej jak nazwa komponentu/pluginu dane bede zapisywane tak jak podalem wyzej wiec na to samo wychodzi czy pliki czy baza jeden kit.
Tak samo biblioteka tez bedzie mogla miec wlasne bledy w roznych jezykach jesli zajdzie taka potrzeba np lib do upload'u/download'u
Pomyśl, że chcesz później dodać kolejny język i dać możliwość grupie tłumaczy tłumaczenia tego. Jak to rozwiążesz?
Dam im plik z errors i do tego pliki widokow a dane dynamiczne jak news'y etc.... to wiadomo.
Taaak, rozdziel to dla kilku tłumaczy Nie będzie tak łatwo. Zresztą przy n modułach kopiuj sobie wszystkie pliki itd.
Mysle ze przy latwych stronach metoda moze sie sprawdzic jak nie zawsze bede mogl zmienic implementacje klasy language i tyle
Trochę zeszliście Panowie z tematu...
A co do tematu jak tym zarządzać, to... nie ma tematu - przygotowanie prostej aplikacji, która udostępniłaby jakiś w miarę przyjazny tłumaczowi interface to kwestia powiedzmy godzin, by było to w miarę dopracowane.
Jeżeli natomiast chodzi o format przechowywania danych w plikach tekstowych to wartym rozpatrzenia formatem jest oparty o XML XLIFF. Z własnego doświadczenia niewiele mogę powiedzieć o współpracy z tłumaczami przy wykorzystaniu tego formatu, ale ponoć istnieje trochę gotowych aplikacji do operowania na tym i inne firmy chętnie z tego korzystają.
Nie wiem na ile moje pytanie pasuje do reszty postów wątku ale:
Czyli lepiej tworzyć adresy z oznaczeniem języka jako subdomena czy nie?
www.strona.com/en/super/hiper/podstrona
czy
www.en.strona.com/super/hiper/podstrona
pozdro
Co do subdomen czy ogolnie jezyka w url wiem jedno jest to o tyle lepsze ze poprzez url uwzgledniamy odrazu jezyk strony dla user'a bez zadnego wybierania tzn jak wysle link strony php.pl koledze ten nie zna jezyka pl wiec musi wybrac jezyk poprzez podanie mu adresu w stylu www.php.pl/index.php/en/ lub www.en.php.pl user nie musi juz nic zmieniac.
Wedlug mnie zalezy tez ile subdomen masz do dyspozycji i ile jezykow chcesz zaimplementowac.
Jednak sam wyslucham opini innych by wiedziec w czym jeszcze moze sie przydac.
Język w ogóle nie musi być widoczny w adresie. Dla użytkownika nie będzie to miało znaczenia, bo przed wyświetleniem czegokolwiek trzeba sprawdzić jakie języki akceptuje przeglądarka usera, w jakiej kolejności itd. A jak był na naszej stronie to odczytujemy jego ciasteczko. Czyli ten sam adres pokaże stronę w różnych językach w zależności od użytkownika. Ale myślę, że dla google lepiej rozróżniać język w adresie. Choć mechanizm pozostaje ten sam: użytkownik trafia na stronę strona.com i tam jest przekierowywany na np strona.com/pl/. Ale właśnie czy lepiej język do adres dodac jako subdomenę czy po nazwie domeny? Co o tym myślicie?
Ja jestem za subdomenami, ale tylko ze względów estetycznych. Nie widzę różnicy między pl.strona.com en.strona.com a strona.com/pl/ strona.com/en/
Język powinien być w adresie,a moim zdaniem najlepiej jak jest w subdomenie, szczególnie dla wyszukiwarek : szukamy na angielskim google mamy en.adresstrony.xx a na polskim pl.adresstrony.xx itp więc moim zdaniem jest to największa przewaga tego typu rozwiązania + indeksowanie treści, google będzie miało ten sam adres przy zmianie treści więc zaindeksuje tą treść raz (w przypadku braku języka w adresie).
P.S. Nie jestem w tym specjalistą i to są tylko moje luźne spostrzeżenia
P.S. Szczerze chciałbym usłyszeć pogląd specjalisty od pozycjonowania na temat : "Językowość, a wyszukiwarka."
A może jednak w ogóle nie uwzględniać języka w adresie strony? Wystarczyłoby sprawdzić jaki jest język przeglądarki i na podstawie tego poprzez sesje albo ciasteczka automatycznie wyświetlać treść w odpowiednim języku. I też user nie musi nigdzie klikać, chyba, że zechce. Wtedy wszystkie linki przychodzące byłyby do jednej strony a nie byłyby rozdzielone na dwie strony o różnych adresach. Ale co z indeksacją strony? Czy google będzie raz indeksować dla en a raz dla pl?
pozdro
Będzie zmienna treść co jest trochę bez sensu. Można wykorzystać język przeglądarki, ale nie jest do pewne rozwiązanie. Najlepsze to dwie oddzielne pod/strony - łatwe zarządzanie i obie z nich mogą mieć różną zawartość.
Riklaunim treści przecież mogą być różne. W bazie mogą być pole z treścią w kilku językach. A i szablony i style mogą być ładowane różne dla różnych języków. I to nawet dobrze działa, ale ma ten minus zmiennej treści, o czym pisałeś. Czy wiesz jak google indeksuje taką stronę?
pozdrawiam
Tego chciałem się dowiedzieć, czy da się dobrze taką stronę zaindeksować -jeśli nie to sprawa jest oczywista. Ale chyba dla domyślnego języka nie ma potrzeby tworzenia subdomeny?
strona.com - dla poslkiej strony
en.strona.com - dla angielskiej
fr.strona.com - dla francuskiej
pozdro
według mnie, sprawdzać język przeglądarki można wtedy, kiedy się chce na wejściu ustawić domyślny język strony czyli:
język przeglądarki: polski, treść domyślna: polska
język przeglądarki: angielski - redirect na en.site.pl
język: chiński - redirect ch.site.pl
no a jeżeli domyślny język nie byłby polski no to
język przeglądarki: polski - redirect pl.site.com
obojętnie
Witam,
Trochę odgrzebię temat, ale mam problem ze zrozumieniem pewnej rzeczy... Były tutaj podawane sposoby zapisywania dynamicznych treści do bazy i jedną z nich była jedna tabela z kolumną lang, w której był określony język wpisu... Co w przypadku, gdy użytkownik wejdzie w taki wpis, zobaczy, że jest też jego polska wersja i będzie chciał się na nią przełączyć, bo np. zna jako tako polski, a może być tam więcej informacji? ID takich wpisów jest inny, a subdomeny nie wchodzą w grę...
Pozdrawiam.
@kuzdo
Tu nie ma problemu. Masz np taka strukturę tabeli:
<http://december.com/html/4/element/a.html href="wpis.php?id=2">zobacz wpis w en</http://december.com/html/4/element/a.html> <http://december.com/html/4/element/a.html href="wpis.php?id=3">zobacz wpis w ru</http://december.com/html/4/element/a.html>
Dlaczego? PrimaryKey to może być para kluczy. ID i LANG.
Rozważał ktoś na tych 8 stronach czy w wielu językach lepiej stosować nadmiarowe dane w tabelach czy normalizacje i podział na dwie tabele?
Chodzi mi o sytuację, gdy jakiś zasób ma cechy wspólne dla wielu wersji (np. grafika, przypisanie do kategorii, parametry systemowe) oraz różne (tytuł, opis, itd.).
Normalizacja w tym przypadku wydaje się mieć dużo wad: JOIN przy każdym zapytaniu, ograniczone stosowanie indeksów, jednak w cms firmy, w której pracuje tak właśnie sa zaimplementowane wersje językowe (!?)
Wiem, że ostatnia odpowiedź była w zeszłym roku, lecz nie chcę zaśmiecać forum.
Skorzystałem z opisanych tu sposobów tzn. mam plik załóżmy pl.php
str_replace()
Do maili najlepiej zrobić sobie specjalny systemik który będzie obsługiwał do nich szablony, a w szablonie maila użyć systemu językowego to nie problem.
przekopałem cały temat, ale nie znalazłem odpowiedzi na swoje pytanie.. piszę prosty sklep internetowy i stanąłem przy wrzucania produktów z panelu administracyjnego. Mam kilka języków w sklepie i chciałbym, żeby do każdego produktu można było dodać opis i cenę w innym języku. Myślałem, żeby dodać kolumnę do tabeli "LANG", coś takiego:
id | cat | name | desc | price | LANG
i przy dodawaniu produktu wrzucać tyle rekordów ile jest języków, tylko w ostatniej kolumnie zmieniać LANG
chyba, że znacie jakieś lepsze rozwiązanie
Witajcie.
Przekopałem się przez temat i kilka razy padła odpowiedź na moje pytanie ale może jednak coś się zmieniło gdyż temat dawno zamarł.
Stworzyłem w miarę uniwersalny sklep w którym admin (owner) ma możliwość dodawania dowolnej ilości języków, treści stałych jak i opisów produktów, newsów itp i jest to rozwiązane wydaje mi się w najlepszy możliwy sposób.
Ogólne teksty na stronie:
Tabela jezyk = id | nazwa | skrot
Tabela fraza = id_jezyk | fraza // id jezyk 0 to opis frazy w języku polskim
Dla produktów, kategorii i newsów jest
Tabela produkt id,nazwa i inne | id_jezyk
Użytkownik ma domyślny język w sesji.
Tabele związane z językiem są cachowane więc baza nie jęczy.
Dzięki temu wszystko dzieje się szybko. Admin ma możliwość zmieniać tłumaczenia przez CMS dla każdego języka i frazy.
Jeżeli chodzi o produkty to rozwiązania są 2:
1 - dla innego języka inny produkt
2 - produkt ten sam ale opis, nazwa, cena (waluta, vat) z tabeli łączonej
ale to już zależy od klienta, mam zrobione 2 opcje łatwo przełączalne.
Co o tym myślicie?
A jak rozwiązujesz tłumaczenie treści z bazy? Tzn. produkty i opisy w innych językach.
Bo cache cachem, ale nieskończonej pojemności też nie ma.
Ostatnio napisałem na szybkości coś takiego co do samego wyboru języka, może komuś się przyda
$langs_array = ['pl', 'en', 'fr']; $default_lang = 'pl'; if(http://www.php.net/isset($_SESSION['SESSION_LANG'])): if(!http://www.php.net/in_array($_SESSION['SESSION_LANG'], $langs_array)): $_SESSION['SESSION_LANG'] = $default_lang; endif; else: $input = http://www.php.net/strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE']); $pattern = '/;q=([0-1]{0,1}.\d{0,4})/i'; $user_languages = []; foreach(http://www.php.net/explode(',', $input) as $lang): $user_languages[] = http://www.php.net/preg_replace($pattern,'',$lang); endforeach; http://www.php.net/unset($input, $pattern, $lang); $selected_language = ''; foreach($user_languages as $lang): if(http://www.php.net/in_array($lang, $langs_array)): $selected_language = $lang; break; endif; endforeach; if(http://www.php.net/empty($selected_language)): $_SESSION['SESSION_LANG'] = $default_lang; else: $_SESSION['SESSION_LANG'] = $selected_language; endif; http://www.php.net/unset($user_languages, $selected_language); endif; $lang = filter_input(INPUT_GET, 'lang'); if(!http://www.php.net/empty($lang)): if(http://www.php.net/in_array($lang, $langs_array)): $_SESSION['SESSION_LANG'] = $lang; else: $_SESSION['SESSION_LANG'] = $default_lang; endif; endif; include $_SESSION['SESSION_LANG'] . '/index.php'; http://www.php.net/unset($lang);
Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)