Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: ?tagi i tłumaczenia stron - wady i zalety różnych rozwiązań?
Forum PHP.pl > Forum > PHP
nowy_pehapowiec
Cze!
Przewertowałem wujaszka google i nadal nie wiem które rozwiązanie wybrać.



Tagi
1 Dodatkowa kolumna 'tags' nie spełniająca warunku normalności. Pojedyncze tagi rozdzielone przecinkiem albo średnikiem i wszystkie zapisane w jednym polu.
2 Dodatkowo tabela z kolumnami id, tag. Taka tabela tez nie jest normalna bo jeśli jeden id ma kilka tagów to id musi się powtarzać w następnych wierszach.

Jak widać ani jedno ani drugie rozwiązanie nie jest idealne. Pierwsze jest prostsze w realizacji. Drugie minimalnie trudniejsze, ale czy lepsze? Można to drugie zmodyfikować dodając dodatkową tabelę łączącą id, tag_id, a w tabeli tags trzymać tag_id i tag. Ale ideologia pozostaje ta sama.

Które rozwiązanie się sprawuje lepiej? Bo oba są złe - powtórzenia w poziomie albo w pionie.



Tłumaczenia
A dokładniej statyczne tłumaczenia. Czy lepiej tłumaczyć fragmenty stron, te które się zmieniają w różnych językach, czy lepiej całe strony?

1 Jak tłumacze całe strony, to minusem jest konieczność pamiętania o aktualizacji obu stron. Bo jak zmienię jedna stronę to druga działa bez problemów ale jest nieaktualna.

2 Jak tłumacze tylko fragmenty, to przy każdym fragmencie tekstu, czy to paragraf, czy podpis pod zdjęciem, czy element menu muszę użyć jakiejś funkcji, która z bazy pobierze tekst w odpowiednim języku. Czyli kod strony się robi bardziej nieczytelny i liczba selectów z bazy wzrasta.

Poradzicie coś w tych dwóch tematach? A może coś z zupełnie innej beczki
nospor
TAGI

tabela news
ID
blabla

tabela tagi
ID
TAG

tabela wiąząca news_tag
ID_NEWS
ID_TAG

jest to dosc powszechnie stosowane. Mozesz na tym zrobic wszystko co chcesz smile.gif
cojack
Ja ostatnio robiłem statyczną stronę dla klienta, i wymyślił sobie że chce dodatkowy język, to mu zrobiłem, nowy folder i kopiuj wklej pliki (^^), ale co ładny adres pozostał, strona/en/contact.html winksmiley.jpg

I miałem banie czy robić 2 sitemapa, pod ten folder, ale darowałem sobie ;] Lepiej będzie jak mu dwie strony zindeksuje google haha.gif
krowal
Możesz wszystkie tłumaczone teksty wybrać tak naprawdę tylko jednym selectem. Wiąże się to z użyciem boforowanego wyjścia (ob_start(), ob_end_flush()). Podczas wykonywania skryptu zapisujesz sobie wszystkie użycia tekstów, które powinny być tłumaczone. Po wyrenderowaniu całości do bufora wybierasz selectem użyte teksty i zamieniasz funkcją podaną jako callback w ob_start() wystąpienia szukanych tekstów na te wybrane z bazy danych w zależności od języka wybranego przez użytkownika smile.gif
nowy_pehapowiec
nospor ale wtedy tabela nie jest normalna. Czy nie ma lepszych rozwiązań?

krowal możesz to jakoś bardziej wyjaśnić?

dr_bonzo
@nowy_pechapowiec:
to jest normalna tabelka (pomijam brak definicji tego wyrazenia smile.gif).

I jakie chcesz lepsze rozwiazanie. Bo jak chcesz tylko wyswietlac artykul i jego tagi to wystarczy ci zapisac je w jednym polu po przecinku.
Jak chcesz czegos wiecej to zrob jak proponowal nospor, to rozwiazanie jest w dodatku ZNORMALIZOWANE. Jak chcesz tag cloud szybko rysowac to zapewne przyda ci sie licznik tagow zapisany w tabeli z tagami (uwaga!!! to ci zdenormalizuje baze, straszne, co?: ))
nowy_pehapowiec
nospor, dr_bonzo to rozwiązanie z 3 tabelami jest popularne i działa. Ale nie mówcie, że taka baza jest znormalizowana, bo nie jest. To znaczy spełnia jedynie warunki pierwszej postaci normalnej. I powiem wprost irytują mnie powtórzenia w tabelach (kilka tagów => powtarzam wiersze z tym samym ID). Zastanawiam się jak to zrobić lepiej. Na pewno już ktoś to dawno wymyślił, tylko ja o tym jeszcze nie wiem. Może jednak Wy coś na ten temat wiecie? smile.gif

krowal poczytałem troszkę o ob_start() iob_end_flush() i wydaje mi się, że te funkcje pozwalają na przetworzenie jakimś zestawem funkcji strony przed jej wysłaniem do przeglądarki. Ale to nadal nie do końca jarzę jaki miałbym z niej pożytek? Wywołać str_replace() a obie tablice (co zamienić, na co zamienić) trzymać w bazie i pobrać je w całości? Jeśli tak to, to owszem jest to wygodne ale mało wydajne. Bo jak mam podstronę na której jest do zamiany np. 10 słów a na innej 70 słów, to za każdym razem muszę pobrać z bazy cały słownik. I kolejny minus, trzy teksty: "She goes crazy", "He goes crazy", "crazy". W zależności od kolejności słów w tablicach albo się uda sensownie zamiana albo się wszystko porypie. Żeby się nie rypało to musiałbym przy każdym tekście mieć osobną zamianę:
lantrans("She goes crazy") . lantrans("He goes crazy") . lantrans("crazy")
a funkcja lantrans() selectuje z bazy odpowiedni string. No ale jak widac mało to wygodne i kod się robi ......

przeczytałem jeszcze raz ten spory temacik o tłumaczeniach ale akurat tego problema w nim nikt nie porusza.

pozdro
krowal
Po pierwsze schemat tabeli z tlumaczeniami, mniej więcej może być taki:
id, key, lang_en, lang_fr, lang_pl, ... (w zaleznosci od ilosci jezykow)

Po drugie funkcja langtrans('key') ('key' - odpowiednik unikalnego klucza w tabeli) nie robi zapytania do bazy tylko zapisuje klucze do jednej tablicy.

A to przykładowy przebieg wydarzeń:
  1. <?php
  2. function funkcjaTlumaczaca($buffer){
  3. 'SELECT * FROM tlumaczenia WHERE key IN ('key1', 'key2', 'key3')'; // lista kluczy utworzona z tablicy do ktorej zapisuje langtrans()
  4. //zamieniasz wszystkie wystąpienia #translate_XXX# na wartości pobrane z bazy w zależności od klucza
  5. //opcjonalnie mozesz sprawdzać które z kluczy istnieją w bazie i jeśli jakichś nie ma to je dodajesz z pustymi wartosciami w kolumnach jezykow
  6. return srt_replace($listaDoZamiany, $listaZBazy, $buffer);
  7. }
  8.  
  9. ob_start('funkcjaTlumaczaca');
  10. // twoj html z kilkoma wywolaniami wynkcji langtrans('key1') langtrans('key2') langtrans('key3')
  11. // 'echo langtrans('key')' -> powinno wyświetlić cos w rodzaju #translate_key#
  12. ob_flush(); // wysle do przegladarki przerobiony bufor
  13. ?>


Trochę chaotycznie, ale może załapiesz smile.gif
nowy_pehapowiec
krowal no nie jarzę. wstyd się przyznać ale nie jarzę

Mam mieć w kodzie strony coś takiego?

ob_start('funkcjaTlumaczaca');
echo 'a,fnsd,f dskfndskfds dskfdskf' . langtrans('key1') . 'dfvdgvdf fdvfdvdf fdvd dfgvfd' . langtrans('key2') . 'dsfdsfdsfdsfds';
ob_flush();

funkcja langtrans('key') ma zapisywać gdzieś słowa do tłumaczenia i tylko one maja być pobrane przez funkcjaTlumaczaca()? I ta funkcjaTlumaczaca() ma dokonać zamiany? Ale co jeśli wystąpią dwa słowa "painfully" i "full"?

To faktycznie jest o tyle lepsze, że nie trzeba wielu selectów tylko jeden. No ale jak uniknąć pomyłek? Nie, chyba ja jednak zupełnie się w tym nie połapałem.

pozdro
krowal
Nie rozumiem o co Ci chodzi, dwa słowa to dwa oddzielne klucze w bazie i dwa oddzielne tlumaczenia tych słów. langtrans('painfully').langtrans('full') powinny zapisać w tablicy dwa klucze za pomocą których wyciągniesz potem ich tłumaczenia odpowiednie dla wybranego języka.
f1xer
@nowy_pehapowiec

to co nospor napisał jest jak najbardziej znormalizowane, popatrz

content

id|tresc
1|to jest pierwsza treść
2|to jest druga treść
1|to jest trzecia treść

tagi
id|tag
1|php
2|mysql
3|ajax

content_tagi
id_content|id_tag
1 |2
1 |1
2 |1

jak widzisz tabela łącząca nigdy nie ma takiej samej pary content - tag a przynajmniej nie powinna mieć przy dobrym zapisaniu skryptu.

znormalizowana baza powinna spełniać takie wymagania:

1. wiersze są unikalne, tzn w żadnej tabeli nie może się zdarzyć, ze któryś wiersz się powtarza
2. kolumny są unikalne
3. pola są atomowe, tzn ze w każdym polu są dane, których nie da się (nie ma potrzeby) dzielić na mniejsze

Jak widzisz jest to znormalizowana baza danych
nowy_pehapowiec
krowal ale jeśli jedna fraza zawiera się w drugiej? to jeśli "full" będzie zamieniany przed "painfully" to z "painfully" zrobi się painpełnyy. Rozumiesz o co mi chodzi? Albo ja zupełnie nie skumałem tego co mi napisałeś. Może mógłbyś wstawić tutaj przykładowy ale kompletny kod strony i kody funkcji, zapytań do bazy. Wtedy by się wyjaśniło co i jak.

W ogóle bardzo mnie mechanizmy tłumaczenia stron interesują, przecież musi być jakiś dobry na to pomysł.

f1xer
Cytat
content_tagi
id_content|id_tag
1 |2
1 |1
2 |1

to jest zgodne tylko z pierwszą postacią normalną, ale z kolejnymi już nie. Bo masz id_content powtórzone dwa razy to samo (1). Ale mniejsza o to, też tak zrobiłem, bo nic lepszego nie wymyśliłem.

Pozdrawiam
f1xer
NIE MOŻE POWTARZAĆ SIĘ WIERSZ a nie pole, gdyby tak było to nie można byłoby tworzyć relacji wiele do wielu
nowy_pehapowiec
Ponawiam pytanko:
krowal ale jeśli jedna fraza zawiera się w drugiej? to jeśli "full" będzie zamieniany przed "painfully" to z "painfully" zrobi się painpełnyy. Rozumiesz o co mi chodzi? Albo ja zupełnie nie skumałem tego co mi napisałeś. Może mógłbyś wstawić tutaj przykładowy ale kompletny kod strony i kody funkcji, zapytań do bazy. Wtedy by się wyjaśniło co i jak.
dr_bonzo
Cytat
nospor, dr_bonzo to rozwiązanie z 3 tabelami jest popularne i działa. Ale nie mówcie, że taka baza jest znormalizowana, bo nie jest. To znaczy spełnia jedynie warunki pierwszej postaci normalnej. I powiem wprost irytują mnie powtórzenia w tabelach (kilka tagów => powtarzam wiersze z tym samym ID). Zastanawiam się jak to zrobić lepiej. Na pewno już ktoś to dawno wymyślił, tylko ja o tym jeszcze nie wiem. Może jednak Wy coś na ten temat wiecie?


Łojeb. To moje studia, i kilka ksiazek o bazach ktore przerobilem mnie klamaly? Caly czas mowily ze to jest znormalizowana baza, i tak sie robi
relacje wiele do wielu.

Cytat
I powiem wprost irytują mnie powtórzenia w tabelach

Czlowieku, obudz sie, zyjesz w swiecie gdzie nie ma rzeczy idealnych, mozesz sobie usunac powtorzenia, ale system tagow bedzie ci mulil, i co powiesz klientowi? "No niestety tak musi byc bo nie lubie powtorzen w bazie" ?


Cytat
content_tagi
id_content|id_tag
1 |2
1 |1
2 |1

to jest zgodne tylko z pierwszą postacią normalną, ale z kolejnymi już nie. Bo masz id_content powtórzone dwa razy to samo (1). Ale mniejsza o to, też tak zrobiłem, bo nic lepszego nie wymyśliłem.


No chyba cie pogielo. To jest jak najbardziej prawidlowe rozwiazanie, dla relacji wiele do wielu. Przeciez jeden CONTENT ma miec WIELE tagow, temu sie powtarza w tej tabeli, dopisz sobie jeszcze
Kod
2| 2
i ... o matko, id_tag sie powtarza. I to tez jest ok, bo kazdy tag moze byc przypisany do wielu contentow.

Polecam wrocic do podstaw projektowania baz danych.



============
Zamiana tresci, slowo po slowie jest BEZSENSU. Jezyk, np. angielski, nie przeklada sie na polski co do slowa. Prawie zawsze to samo zdanie buduje sie inaczej, i nie wystarczy przetlumaczyc slow zeby bylo dobrze.

Changing content, word by word is pointless. Language, for example english, no translate itself on polish what to word. Almost always that same sentence builds itself other way, and no enough to translate words to is good.


Cytat
Jak tłumacze całe strony, to minusem jest konieczność pamiętania o aktualizacji obu stron. Bo jak zmienię jedna stronę to druga działa bez problemów ale jest nieaktualna.

To zes problem znalazl. Po prostu MUSISZ strone w innym jezyku przetlumaczyc i kropka. Najlepiej w calosci.
krowal
Ech nie chciało mi się tłumaczyć więc napisałem dla Ciebie działający kod smile.gif
  1. -- Struktura tabeli dla `translations`
  2. -- w bazie forum_php
  3. CREATE TABLE IF NOT EXISTS `translations` (
  4. `key` varchar(250) NOT NULL,
  5. `trans_en` text NOT NULL,
  6. `trans_pl` text NOT NULL,
  7. PRIMARY KEY (`key`)
  8. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;


  1. <?php
  2. mysql_connect('localhost', '', ''); // wpisz usera i pass
  3. mysql_select_db('forum_php');
  4.  
  5. class Trans{
  6. public static $keys = array();
  7.  
  8. public static function getParsedKey($key){
  9. self::$keys[] = $key;
  10. return '#translation_key_'.$key.'#';
  11. }
  12.  
  13. public static function translateContent($content){
  14. $query = 'SELECT * FROM translations AS t WHERE t.key IN (\''.implode("','", self::$keys).'\')';
  15. $result = mysql_query($query);
  16. $results = array();
  17. $existingKeys = array();
  18.  
  19. while($row = mysql_fetch_assoc($result)){
  20. $results[$row['key']] = $row;
  21. $existingKeys[] = $row['key'];
  22. }
  23.  
  24. $keysToAdd = array();
  25. $toChange = array();
  26. $translation = array();
  27.  
  28. if (isset($_GET['lang'])){
  29. $lang = $_GET['lang'];
  30. }else{
  31. $lang = 'pl';
  32. }
  33.  
  34. foreach(self::$keys as $k){
  35. if (!in_array($k, $existingKeys)){
  36. $keysToAdd[] = $k;
  37. }
  38. $toChange[] = '#translation_key_'.$k.'#';
  39. $translation[] = ((isset($results[$k]) && $results[$k]['trans_'.$lang] != '') ? $results[$k]['trans_'.$lang] : $k);
  40. }
  41.  
  42. foreach($keysToAdd as $k){
  43. $query = 'INSERT INTO translations (`key`) VALUES (\''.$k.'\')';
  44. mysql_query($query);
  45. }
  46.  
  47. return str_replace($toChange, $translation, $content);
  48. }
  49. }
  50.  
  51. function __($key){
  52. return Trans::getParsedKey($key);
  53. }
  54. ob_start('Trans::translateContent');
  55. ?>
  56. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  57. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  58. <head>
  59. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  60. <meta name="title" content="Super strona" />
  61. </head>
  62. <body>
  63. jakis text <?php echo __('full') ?><br />
  64. jakis text2 <?php echo __('painfully') ?><br />
  65. a tu jakis kolejny text <?php echo __('skip_me')?>
  66. </body>
  67. </html>
  68. <?php
  69. ?>


Dostępne są takie języki jakie są pola w bazie, w tym przypadku en i pl. Języki można zmienić wywołując skrypt z parametrem ?lang=xx , gdzie xx = (en,pl). Skrypt wykonuje tylko jedno zapytanie do bazy wybierając tłumaczenia. Oprócz tego jeśli wprowadzisz nowe klucze do tekstu za pomocą funkcji __(klucz) to dla każdego klucza zostanie JEDNORAZOWO wykonane zapytanie wstawiające klucz do tabeli.
Btw. to tylko przykład... aby działało to z jakąś większą aplikacją potrzebne są małe modyfikacje smile.gif
Miłego korzystania.

@dr_bonzo, masz rację że tłumaczenie stron słowo po słowie jest bez sensu, ten kod również na to nie pozwala, pozwala jednak na tłumaczenie słów statycznych na stronie, dynamiczny content generowany przez userów to już inna sprawa. Skrypt pozwala na internacjonalizację strony a nie jej lokalizację.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.