За последние 24 часа нас посетили 17828 программистов и 1613 роботов. Сейчас ищут 1447 программистов ...

Многоязычный интерфейс php-приложения

Тема в разделе "Решения, алгоритмы", создана пользователем tmanager, 13 мар 2008.

  1. tmanager

    tmanager Активный пользователь

    С нами с:
    12 мар 2008
    Сообщения:
    108
    Симпатии:
    0
    Я сумел реализовать многоязычный интерфейс php-приложения.

    Сразу оговорюсь. Сайту это вряд ли нужно. Речь об офисных программах, написанных на php.

    Так вот у меня получилось. Мне моё решение самому нравится (что со мной бывает редко). Главная фишка: пользователь может сам добавить языковую версию и ввести переводы.

    Если будуто вопросы -- конечно, отвечу. А пока, не будучи уверенным, что обществу эт о интеерсно, только самая суть.

    Есть три таблицы -- phrases, translations и items (пожалуй, items -- "архитектурное излишество", но не стал переисывать).

    phrases -- хранит фразы на русском языке (ввиду невладения иными), которые переводятся на другие. Эти самые переводы хранятся в таблице translations

    Фразы разбиты на виды. Т.е. есть переводы городов, переводы стран, переводы видов услуг, переводы меню (они хранятся в items -- так уж получилось), ну и всех остальных фраз.

    Т.е. вместо того, чтобы написать, скажем,

    PHP:
    1. <?php
    2. print "Здорово, мир!";
    3. ?>
    я пишу

    PHP:
    1. <?php
    2. print phrases::phrase(754, lng, "Здорово, мир!");
    3. ?>
    Здесь 754 -- это id фразы в таблице phrases, lng -- константа, хранящая id языка, ну а третий параметр -- фраза, которая будет написана, если перевод найден не будет (ну и для читаемости -- чтоб быол ясно, что сказать-то хотели).
     
  2. Anonymous

    Anonymous Guest

    Поздравляю. Вы придумали gettext! :)
    Или у вас есть скрытые преимущества над ним?
     
  3. tmanager

    tmanager Активный пользователь

    С нами с:
    12 мар 2008
    Сообщения:
    108
    Симпатии:
    0
    Спасибо. Всегда приятно, что принципы, которые я пидума, совпадают с принципами серьёзных проектов.

    Полагаю, что есть. Это возможность нескольких переводов в одном бланке. Т.е. язык интерфейса -- русский, а бланк -- нужен англоязычный. Просто сообщаешь бланку id языка -- и он переводится на нужный язык.

    Ну и каждый пользователь может включить себе свой язык интерфейса -- он не будет единым для всех пользователей данного сервера. А там -- пишут, что Перевод определяется системной переменной LANG, которая обычно уже установлена в требуемое значение.
     
  4. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    tmanager
    По поподу gettext ты не понял немного. Устанавливается локаль, которая используется для перевода, она глобальна для коркретного запроса и скрипта. У каждого отдельного юзера устанавливается отдельно. А в ней уже как переведёшь, так и будет отображатся. Не обязательно в RU писать только кирилицу - можно писать что угодно если у вас utf-8, так что по сути изобретение gettext, только в сильно более медленном варианте.
     
  5. Anonymous

    Anonymous Guest

    Ну, она сменяется для одного приложения функцией setlocale(), тут говорится о ориентации на эту переменную, для ПЕРВОНАЧАЛЬНОГО определения языка пользователя. Т.е. вот у меня винды нет, и я привык, что ставлю приложение и оно не спрашивает у меня, на каком языке я хочу его видеть. (Отсутствие поддержки gettext в приложениях в линуксе - практически исключение) Но, при желании, я могу, его конечно, сменить.

    Ну, gettext это тоже умеет. :)

    У gettext() как по мне, есть два преимущества, не считая распостраненности, и прочих субьективных для меня факторов - она бинарная (т.е. крайне быстрая), и она умеет (под линуксом это особенно видно) подгружать данные из общих системных! po-файлов. (т.е. вы может быть не делали нужного перевода для вашего приложения, но если в общих файлах есть переводы на языке пользователя, они могут быть задействованы, хотя бы частично) хотя это же и минус.

    Из недостатков, которые побуждают отказаться от Gettext в угоду решению, сходному с вашим, это неудобная привязка к файлам как хранилищу переводов (в частности, неудобная реализация редактирования файлов переводов, для переводчиков) и минус - вытекающий из второго плюса - вероятная подмена контекста фразы при подгрузке системных файлов. Вот, вкратце, мое мнение. :)
     
  6. tmanager

    tmanager Активный пользователь

    С нами с:
    12 мар 2008
    Сообщения:
    108
    Симпатии:
    0
    Не теряем ли мы кроссплатформенность?

    Почему Вы думаете, что в более медленном?
     
  7. RomanBush

    RomanBush Активный пользователь

    С нами с:
    5 дек 2007
    Сообщения:
    798
    Симпатии:
    0
    Адрес:
    200 км от Москвы
    Вопрос:
    хранит где? И в каком виде?

    И вытекающий из первого вопроса ещё один: если перевода какой-то фразы нет и третий параметр не задан - что покажется - пустота или русский вариант? И нет ли механизма, который бы добавлял в таких случаях перевод (если задан третий параметр)?
     
  8. RomanBush

    RomanBush Активный пользователь

    С нами с:
    5 дек 2007
    Сообщения:
    798
    Симпатии:
    0
    Адрес:
    200 км от Москвы
    Psih
    gettext плох уже тем, что он привязан к какому-то переводу, который мне на сайте нафик не нужен. Мне нужен МОЙ перевод, который я могу контролировать, надстраивать и расширять так, как МНЕ нужно. А не какой-то абстрактный, к тому же, по разному себя ведущий на разных платформах. Это "затычка" для ленивых. Я предпочту неделю посидеть, перевести так, как мне нужно, чем полагаться на кого-то, кто про меня даже и не слышал. Зато я получу сайт, который не содержит огрехов перевода (кроме тех, которые мне нужны и я сам сделал) и содержит нужную мне интерпретацию перевода.
    К тому же - кросплатформенную :)
    Он имеет в виду, что бинарники будут быстрее, чем интерпретированный php.
    Да и хрен с ним. Разница в миллисекунды тут роли не играет. На мой взгляд - тут важнее качество, чем скорость.
     
  9. tmanager

    tmanager Активный пользователь

    С нами с:
    12 мар 2008
    Сообщения:
    108
    Симпатии:
    0
    Хранятся фразы и переводы -- в таблицах MySQL. Но для скорости по таблицам создаются файлы php, содержащие php-массивы. Имя такого файла соответствует id языка -- и их страницы линкуют. Не находят -- вновь создают.

    Русский вариант.

    Пока нет. Но стоит подумать над ним.
     
  10. RomanBush

    RomanBush Активный пользователь

    С нами с:
    5 дек 2007
    Сообщения:
    798
    Симпатии:
    0
    Адрес:
    200 км от Москвы
    Классно сделано. У меня примерно похоже, только хуже. Буду думать на тему переделать.
     
  11. tmanager

    tmanager Активный пользователь

    С нами с:
    12 мар 2008
    Сообщения:
    108
    Симпатии:
    0
    Я считаю также преимуществом, что в зависимости от установленной версии меняются мета-теги, отвечающие за кодировку и язык страницы.

    Не могу объяснить свою нелюбовь к Юникоду. Может, уже пора её изживать...
     
  12. tmanager

    tmanager Активный пользователь

    С нами с:
    12 мар 2008
    Сообщения:
    108
    Симпатии:
    0
    Может, что-то из моего класса будет полезно?

    Пояснения потом ещё напишу -- сейчас кое-что надо ещё вчера сделать.

    PHP:
    1. <?php
    2.  
    3. require_once dirname(__FILE__)."/../inc/sezam.php"; //to MySQL
    4.  
    5.  
    6. class phrases
    7. {
    8. public $page;
    9. protected $action;
    10.  
    11.  
    12. //-----------------------------------------------------
    13.  
    14. function __construct($lng,$action,$page=1)
    15.     {
    16.     $this->lng=$lng;
    17.     $this->action=$action;
    18.     $this->page=$page;
    19.     }
    20.  
    21. //------------------------------------------------------------------------------
    22.  
    23. public static function phrase_from_db($id,$lng,$default)
    24.     {
    25.  
    26.     $re="/<span class="no_translate">[^<]+<\/span>/";
    27.     $re2="/<span class=&quot;no_translate&quot;>[^<]+<\/span>/";
    28.     $default=preg_replace($re,"",$default);
    29.     $default=preg_replace($re2,"",$default);
    30.  
    31.     if ($lng==russian)
    32.         {
    33.         return $default;
    34.         }
    35.  
    36.     $phrase=$default;
    37.     global $conn_admin;
    38.     $query="select translation from ".main_db.".translations where phraseID='".addslashes($id)."' and languageID=$lng and phrasetype=1";
    39.     $result=mysql_query($query,$conn_admin);
    40.     while($row=mysql_fetch_array($result,MYSQL_ASSOC))
    41.             {
    42.             $phrase=stripslashes($row["translation"]);
    43.             }
    44.     mysql_free_result($result);
    45.     return $phrase;
    46.     }
    47.  
    48. //-----------------------------------------------------
    49. public static function phrase($id,$lng,$default)
    50.     {
    51.     $re="/<span class="no_translate">[^<]+<\/span>/";
    52.     $re2="/<span class=&quot;no_translate&quot;>[^<]+<\/span>/";
    53.     $default=preg_replace($re,"",$default);
    54.     $default=preg_replace($re2,"",$default);
    55.    
    56.     if ($lng==russian)
    57.         {
    58.         return $default;
    59.         }
    60.  
    61.  
    62.     $phrase=$default;
    63.  
    64. $array="phrases_$lng";
    65. global $$array;
    66.  
    67. if (isset($$array))
    68.     {
    69.     $phrases=$$array;
    70.     if (isset($phrases[$id]))
    71.         {
    72.         $phrase=$phrases[$id];
    73.         }
    74.     }
    75.  
    76.     return $phrase;
    77. }
    78.  
    79. //----------------------------------------------------------
    80.  
    81. public static function create_file($lng) //сочиняем файл с переводами фраз
    82.     {
    83.     $code="<?php
    84.     \$phrases_$lng=array(
    85.     ";
    86.  
    87.     global $conn_admin;
    88.  
    89.     $query="select id,  phrase from ".main_db.".phrases ";
    90.     $query.=" order by phrases.id";
    91.  
    92.  
    93.     $result=mysql_query($query,$conn_admin);
    94.  
    95.     $a="";
    96.     while($row=mysql_fetch_array($result,MYSQL_ASSOC))
    97.             {
    98.             $translate=phrases::phrase_from_db($row["id"],$lng,stripslashes($row["phrase"]));
    99.             $translate=preg_replace("/([^\\\])"/","\${1}\\"",$translate);
    100.             $a.="\n,".$row["id"]."=>"$translate"";
    101.             }
    102.     mysql_free_result($result);
    103.  
    104.     if ($a!="")
    105.         $a=substr($a,2);
    106.  
    107.     $code.=$a."\n);";
    108.     $code.="
    109.     ?>";
    110.  
    111.     $officeDir=dirname(__FILE__)."/../offices/".officeDir;
    112.     if (!file_exists($officeDir))
    113.         {
    114.         $result=mkdir($officeDir);
    115.         if ($result==false)
    116.             return "Error of mkdir() in phrases:create_file()";
    117.         }
    118.     $lngDir=$officeDir."/languages";
    119.     if (!file_exists($lngDir))
    120.         {
    121.         $result=mkdir($lngDir);
    122.         if ($result==false)
    123.             return "Error of mkdir() in phrases:create_file()";
    124.         }
    125.  
    126.     chmod($lngDir, 0777);
    127.  
    128.     $filename=$lngDir."/phrases".$lng.".php";
    129.  
    130.     $result=@file_put_contents($filename,$code);
    131.     if ($result==false)
    132.         return "Error of file_put_contents() in phrases:create_file()";
    133.  
    134.     return "Ok";
    135.  
    136.     }
    137.  
    138.  
    139.  
    140. //--------------------------------------------------------
    141. function pages() //ССылки на страницы -- это для формы редактирования переводов
    142. {
    143.     $count=$this->pages_count();
    144.     if (($count==0) || ($count==1))
    145.             {
    146.             return "";
    147.             }
    148.  
    149.     if ($this->page>$count)
    150.         {
    151.             return "Несуществующая страница";
    152.         }
    153.  
    154.     $html="\n<hr />\n";
    155.     for ($i=1;$i<=$count;$i++)
    156.         {
    157.         if ($i==$this->page)
    158.             $html.="<span style="background:blue;color:white;font-weight:bold">$i</span> ";
    159.         else
    160.             $html.="<a href="".$this->action."?page=$i">".$i."</a> ";
    161.         }
    162.     $html.="\n<hr />\n";
    163. return $html;
    164. }  
    165.  
    166. //--------------------------------------------------------
    167.  
    168. function pages_count()
    169.     {
    170.     global $conn_admin;
    171.  
    172.     $query="SELECT COUNT(id) as n FROM ".main_db.".phrases";
    173.     $result = mysql_query($query,$conn_admin) or die($query);
    174.     $n=mysql_result ($result,0,0);
    175.     mysql_free_result($result);
    176.  
    177.     $count=ceil($n/25);
    178.     return $count;
    179.     }
    180.  
    181.  
    182. //--------------------------------------------------------
    183.  
    184.  
    185. function form() //форма редактирования переводов фраз
    186.     {
    187.     global $conn_admin;
    188.  
    189.     $tr="";
    190.     $re="/<span class="no_translate">[^<]+<\/span>/";
    191.     $re2="/<span class=&quot;no_translate&quot;>[^<]+<\/span>/";
    192.     $query="select id, phrase from ".main_db.".phrases order by id";
    193.     $query.=" limit ".(($this->page-1)*25).",25";
    194.     $result = mysql_query($query,$conn_admin) or die($query);
    195.     while($row=mysql_fetch_array($result,MYSQL_ASSOC))
    196.             {
    197.             $tr.="\n<tr>";
    198.             $tr.="\n<td class="usual">".$row["id"]."</td>";
    199.             $tr.="\n<td class="usual">".stripslashes($row["phrase"])."</td>";
    200.  
    201.             $tr.="\n<td class="usual">";
    202.             $tr.="<input type="text" name="phrase".$row["id"]."" size="70" value="";
    203.             $translate=preg_replace("/"/","&quot;",phrases::phrase_from_db($row["id"],$this->lng,stripslashes($row["phrase"])));
    204.             $translate=preg_replace($re,"",$translate);
    205.             $tr.=preg_replace($re2,"",$translate);
    206.             $tr.="" />";
    207.             $tr.="</td>";
    208.             $tr.="\n</tr>";
    209.             }
    210.     mysql_free_result($result);
    211.     if ($tr=="")
    212.         return "Фраз для перевода не введено";
    213.  
    214.     $html="<form method="post" action="".$this->action."">
    215.     <input type="hidden" name="page" value="".$this->page."" />
    216.     <table class="usual">
    217.         <tr>
    218.             <th class="usual">id</th>
    219.             <th class="usual">".phrases::phrase(744,lng,"Фраза")."</th>
    220.             <th class="usual">".phrases::phrase(745,lng,"Перевод")."</th>
    221.         </tr>
    222.     $tr
    223.  
    224.         <tr>
    225.             <td class="usual" colspan="3" style="text-align:center"><input type="submit" name="phrases_save" value="".phrases::phrase(44,lng,"Сохранить")."" /></td>
    226.         </tr>  
    227.         </table>       
    228.     </form>";
    229.  
    230.     return $html;
    231.  
    232.     }
    233.  
    234. //-----------------------------------------------------
    235.  
    236. function new_form()
    237.     {
    238.     $html="<form method="post" action="".$this->action."">
    239.     <input type="hidden" name="page" value="".$this->page."" />";
    240.     $html.=phrases::phrase(747,lng,"Новая фраза для перевода");
    241.     $html.=":<input type="text" name="new_phrase" size="70" />
    242.     <input type="submit" name="phrases_save" value="".phrases::phrase(45,lng,"Добавить").""/>
    243.     </form>";
    244.     return $html;
    245.     }
    246.  
    247. //-----------------------------------------------------
    248.  
    249. function html() //Отображениее страницы переводов фраз
    250.     {
    251.     $html=$this->new_form();
    252.     $html.=$this->pages();
    253.  
    254.     $html.=$this->form();
    255.  
    256.     $html.=$this->pages();
    257.     return $html;
    258.     }
    259.  
    260. //-----------------------------------------------------
    261.  
    262. function submit($post) //Получение данных из формы редактирования
    263.     {
    264.     if (!isset($post["phrases_save"]))
    265.         return;
    266.  
    267.     global $conn_admin;
    268.  
    269.     $this->page=$post["page"];
    270.     if (isset($post["new_phrase"]))
    271.         {
    272.         $query="insert into ".main_db.".phrases(phrase) values('".addslashes($post["new_phrase"])."')";
    273.         mysql_query($query,$conn_admin);
    274.         return;
    275.         }
    276.  
    277.     //Раз сюда дошли -- сохраняем переводы
    278.  
    279.    
    280.  
    281.     $re="/^phrase(\d+)$/";
    282.     foreach ($post as $name=>$value)
    283.         {
    284.         if (preg_match($re,$name,$m))
    285.             {
    286.             $phraseID=$m[1];
    287.             $query="select id from ".main_db.".translations where phraseID=$phraseID and phrasetype=1 and languageID=".$this->lng;
    288.             $result = mysql_query($query,$conn_admin) or die($query);
    289.             $id=null;
    290.             while($row=mysql_fetch_array($result,MYSQL_ASSOC))
    291.                 {
    292.                 $id=$row["id"];
    293.                 }
    294.             mysql_free_result($result);
    295.             if ($id==null)
    296.                 {
    297.                 $query="insert into ".main_db.".translations(phraseID,phrasetype,translation,languageID) values($phraseID,1,'".addslashes($value)."',".$this->lng.")";
    298.                 }
    299.             else
    300.                 {
    301.                 $query="update ".main_db.".translations set translation='".addslashes($value)."' where id=$id";
    302.                 }
    303.             mysql_query($query,$conn_admin) or die($query);
    304.             }
    305.         }
    306.  
    307.     phrases::create_file($this->lng);
    308.     }
    309.  
    310. //------------------------------------------------------------------
    311.  
    312. public static function  clear_languages($re="/^[^\.]/") //Это уже прикол ТурМенеджера
    313.     {
    314.     $dir=dirname(__FILE__)."/../offices/".officeDir."/languages";
    315.     if ($handle = opendir($dir))
    316.         {
    317.         while (false !== ($file = readdir($handle)))
    318.             {
    319.             if (preg_match($re,$file))
    320.                 {
    321.                 unlink($dir."/".$file);
    322.                 }
    323.             }
    324.         }
    325.  
    326.     closedir($handle);
    327.     }
    328. //------------------------------------------------------------------
    329.  
    330.  
    331.  
    332. } //end class
    333.  
    334. ?>
     
  13. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    У тебя же есть таблица с фразами + .php фаилы как кеш. У gettext тоже фаилы - 1 фаил на один язык. А может вообще не быть, потому-что сам текст фразы вы пишите прямо в коде/шаблоне и он отображается по умолчанию, если нету фаила перевода (поэтому для русского фаила перевода я обычно не делаю даже). Про привязку к фаилу я вообще не вкурил, какое-то идиотически-извращенное у тебя понимание вещей. setlocale набери мануале и почитай. Язык сменить можно в любом месте скрипта на нужный, только вот зачем? Будете показывать часть сайта на английском и часть на немецком на одной странице? Да я такой сайт даже смотреть не буду, так что это не то что-бы притянуто зауши, а просто твоя упёртость в том, что твоя система лучше и тебе ложить с огромной колокольни на опыт людей, которые куда дольше занимаются разработкой и успели перепробовать кучу всяких вариантов.

    А по поводу миллисекунд, незнаю не тестил насколько больше разница, но достанется тебе проэкт когда разница между двумя нижними примерами кода будет душить сервер, тогда и запоешь подругому.
    PHP:
    1. <?php
    2. // $array is 2D array consisting of 30 elements
    3. for ($i = 0; $i < $count($array); $i++){
    4.     $array[$i] = trim($array[$i]);
    5. }
    6.  
    7. /* vs */
    8. array_map('trim', $array);
    9. ?>

    Позволю себе "спиздануть", но какого ты *здесь мат* если даже не знаешь как работает? Какая в *одно место* абстракция, какое разное поведение на разных платформах? Абстракции там 0. Есть фраза и есть для неё перевод в фаиле для конкретного языка. нужный язык указывается через setlocale. И ведёт на всех платформах он себя обсалютно идентично. Так что не надо ляля.

    А что вам нужно для перевода в качестве расширения? о_О Перевод должен делать одну единственную функцию - выводить сообщение на нужном вам языке - gettext с этим справляется на все 100% и весьма элегантным и очень коротким способом
    PHP:
    1. <?php
    2. echo _("Я текст выведенный с помощью gettext");
    3. ?>
    И переводы делаются в спец. програмках, заточенных под это дело. Да и сами вы можете написать на PHP интерфейс для перевода, т.к. структура фаила проста как 2+2, а скомпилировать через системный вызов.

    бУГАЛОЛ, так переводи сам блин. Ставишь poEdit (Windows), открываешь через него фаил перевода gettext и вперёд. Получишь полный список всех фраз в твоём проэкте, где какая лежит в каких фаилах и на каких строчках даже скажет. Вводишь нужный перевод и пошел дальше. Это будет быстрее чем с базой мучатся + в коде наглядно и понятно :)
    PHP:
    1.  
    2. <p><?=_("Я тег p")?></p><br />
    3. <?=_("А я br'ко")?>
    4. <? /* vs */  ?>
    5. <p><?=phrases::phrase(945, $lang, "Я тег p")?></p><br />
    6. <?=phrases::phrase(1056, $lang, "А я br'ко")?>
    7.  
    Ещё id писать, т.е. фраза должна быть в базе до того, как я вообще хочу посмотреть что вышло. Т.е. процедура такая. Пишу код, надо вывести текст. Я думаю текст, проверяю не существует ли уже такая фраза в базе (если да, то иду сразу в код писать), пишу его в базу, беру ID и потом вписываю в код ID перевода, ID языка и саму фразу по умолчанию.
    Вариант gettext: тупо пишу _("фраза") и иду дальше.

    И ещё + gettext'a в том, что он никогда не хранит дубли, только отличающийся текст и мне об этом думать вообще не надо. Т.е. если какой-то текст везде повторяется, то он хранится в единственном экземпляре. У вас же надо постоянно проверять и запоминать кучи ID'ек для особо часто повторяющихся фраз. Ничё если сайт маленький, а если текста на мегабайты в сайте (извините, с маленькими сайтами не работаю - скучно)?


    Я думаю Горбунов Олег со мной согласится, т.к. он gettext тоже поддерживает и использует.
     
  14. RomanBush

    RomanBush Активный пользователь

    С нами с:
    5 дек 2007
    Сообщения:
    798
    Симпатии:
    0
    Адрес:
    200 км от Москвы
    Сегодня день холиваров, чтоли? Меня никто не предупреждал.
    Psih
    Убедил. gettext самая лучшая вещь на свете во веки веков аминь.
    tmanager
    Спасибо большое. Вечером посмотрю - сейчас убегать надо.
     
  15. tmanager

    tmanager Активный пользователь

    С нами с:
    12 мар 2008
    Сообщения:
    108
    Симпатии:
    0
    Напоминаю, что речь идёт не о сайте, а об офисной программе, написанной на php.

    Проблема, о которой Вы говорите, техническая и решается быстро. Ставишь проверочку при добавлении новой фразы (индексы не проканают: тип text) -- и нет проблем. Эта проверка может и как поиск работать. Кстати! Надо сделать. За мысль спасибо! Через полчасика проблема станет историей.

    У меня сейчас под 800 фраз, требующих перевода. Настало время дописать интерфейс.
     
  16. Clone

    Clone Guest

    Да, gettext безусловно рулит... Единственное, что меня пока останавливает - необходимость использовать сторонний extension на сервере, правда сейчас эта проблема становится всё менее актуальной.
     
  17. Anonymous

    Anonymous Guest

    Я соглашусь. Частично. gettext идеальная штука для переводов интерфейсов! приложений!. Но... Имхо, многоязыковые сайты надо делать не всегда на нем.
    gettext спокон веку кусок линукса.
     
  18. tmanager

    tmanager Активный пользователь

    С нами с:
    12 мар 2008
    Сообщения:
    108
    Симпатии:
    0
    Возможно, у моего решения ещё два преимущества

    1. Несколько вариантов перевода. Как у gettext с омонимами?

    2. "Родной" язык не тратит время на перевод.
     
  19. Anonymous

    Anonymous Guest

    Вы же фразы, а не слова переводите :)
    Вот этого не знаю. Английский не переводится, да.

    Зато gettext умеет
    А у вас?

    Одним из преимущаств GetText является то, что это именно перевод - т.е. создание массива переводов происходит после написания программы.

    Прошу принять это не как попытки обхаять ваш вариант, а возможно, подтолкнуть к улучшению.
     
  20. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    Горбунов Олег
    Родной язык не переводится, пишется как есть если к данной фразе нету переводов, так что всё это он тоже умеет и делает уже много много лет :)
     
  21. tmanager

    tmanager Активный пользователь

    С нами с:
    12 мар 2008
    Сообщения:
    108
    Симпатии:
    0
    Случается, что и слова перевожу. И части фраз.

    У меня нужно ввести отдельно единственное, отдельно -- множественное.

    У меня тоже можно после написания программы вводить переводы -- смогу, кстати, нанять переводчиков, не заставляя их изучать спец.редакторы или форматы.
     
  22. GreatWasp

    GreatWasp Активный пользователь

    С нами с:
    11 янв 2008
    Сообщения:
    94
    Симпатии:
    0
    Адрес:
    Узбекистан, Ташкент.
    Незнаю, может я немного в тему. Но на одном из ресурсов нужно было реализовать мультиязычность как всех сообщений JavaScript так и всех шаблонов. Причем шаблоны верстаются не программистом и человек не в курсе где какой ID и т.д - т.е. сделать надо было все максимально просто. Потом, чтобы JS был мультиязычным соотвественно нужно ему подгружать текст перевода. Причем не весь текст на весь модуль (а только на нужную страницу), чтобы клиент не ах***л от того, сколько весит одна страница (в нашей стране почти все на диалапе).

    Было сделано следующее. В Б.Д. создается 1 таблца. В которой прописывается соответствие примерно такое:
    1) " Путь" фразы: \main\payments\proceed
    2) Язык: ru
    3) Перевод: "Превед Мопед, оплати чек."

    Верстка делалась на смарти. Т.е. чтобы вставить нужную фразу в шаблон писалось следующее {translate path='\main\payments\proceed'}. Т.е. не нужно указывать ID и так сказать все человеко-понятно.

    В случае с JS. Была написана тоже функция для смарти которая передавала в спец. подготовленный класс перевода JS JSON массив всех переведенных фраз для текущей страницы. И в JavaScript'e перевод вызывался примерно так: alert(translater.get("\main\payments\proceed"));

    Все работает по сей день, претензий нет никаких.