$288.21


$724.94


$4.52


Многоязычность в РНР

Что же я имел ввиду, говоря о мультиязычности. Ну, наверняка каждый из моих достопочтенных читателей не раз видели крутые порталы и между всем сбродом информации находили две маленькие иконки, преимущественно со всем известным звёздно-полосатым и родным бело-сине-красным флагами. Безусловно, после нажатия на одну из них привычная нам русская речь превращалась в буржуйский language (), или наоборот. Но задавали ли вы себе когда-либо вопрос о том, как это всё делается. Что ж, именно об этом я и буду вести речь.

Сегодня мы рассмотрим довольно важную тему, которая выдвигается многими работодателями, а именно мультиязычность.


Что же я имел ввиду, говоря о мультиязычности. Ну, наверняка каждый из моих достопочтенных читателей не раз видели крутые порталы и между всем сбродом информации находили две маленькие иконки, преимущественно со всем известным звёздно-полосатым и родным бело-сине-красным флагами. Безусловно, после нажатия на одну из них привычная нам русская речь превращалась в буржуйский language (), или наоборот. Но задавали ли вы себе когда-либо вопрос о том, как это всё делается. Что ж, именно об этом я и буду вести речь.

Сразу скажу, что для работы с тем материалом, который будет здесь изложен вам понадобиться поддержка РНР не ниже 4.39.


Итак, как вы знаете, содержание нашего сайта разделяется на динамическое и статическое. К статическому содержанию мы отнесём то, что не будет изменять своё значение в процессе работы (ключевые слова, текст ошибок, и прочая белиберда). С этого мы и начнём. Но давайте проанализируем, как именно мы будем изменять язык данного текстового значения. Надеюсь, никто не предложил воспользоваться исключениями, ибо это настолько нерационально, что нерациональней и быть не может. Вместо этого я предлагаю воспользоваться константами (о типе данных читайте на php.net). Мы просто будем объявлять служебное слово, которое в зависимости от значения языка соответственно будет менять и своё значение. Как мы это сделаем? Да как и все, создадим два (к примеру) разных файла, имена которых будут носить такой шаблон:
Язык_map.php;

Как вы уже поняли вместо слова `язык` мы подставим значение, характеризующее данный язык. В нашем случае мы будем использовать двухсимвольный код языка (ru, en, ua, pl и т.д.).

Что ж теорию выяснили теперь давайте, применим наши знания на практике. Создаём два файла. Я создал файлы с английским переводом и русским, а как создадите вы это уже на ваш вкус.

Файл: en_map.php

<?
If(!defined(«DEF»)) {
    Define(«DEF»,true);
    Define(«TIME_ELAPCED»,«Time what you can spend in this site was elapced !»);
    Define(«ADMIN_WELCOM»,«Welcom dear administrator !»);
    //И хватит
    }
?>
  
Файл: ru_map.php
<?
If(!defined(«DEF»)) {
    Define(«DEF»,true);
    Define(«TIME_ELAPCED»,«Время которое вы можете проводить на сайте истекло !»);
    Define(«ADMIN_WELCOM»,«Добро пожаловать дорогой администратор !»);
    }
?>
  

Итак, на мой взгляд, ничего сложного нет, и всё написанное подчиняется самым банальным законам РНР. Сначала мы делаем проверку, не были ли константы уже объявлены, если были, то не объявляем, в противном же случае объявляем.

Это была лёгкая часть, теперь давайте перейдём к более сложной теме — к переводу динамической части.

Допустим, у вас есть большая портальная система или простой сайт, но вы, талантливый программист знающий все аспекты РНР, не являетесь его владельцем, а сделали его под заказ. Владельцем же является полным дизайнером (), который не слухом, не духом о каких-то там программистских тонкостях, но у него есть одно лишь желание, чтобы всё работало, и он мог изменять всё. Насчёт всего, это уже другая история, а вот языковые параметры сайта мы ему всё-таки разрешим изменить (да что там, чем бы дитя ни тешилось ).

Но опять возвращаясь к дилемме о «Дизайнерах и Программистах» нужно опять упомянуть что такой сайт должен полностью быть, так сказать «Что Видишь То И Получишь», иначе нельзя. Поэтому я постараюсь сделать всё так, чтобы оно не вызывало нервного тика у программистов, и могло удовлетворить дизайнеров (имеется ввиду юзабилити).

Итак, долой пустые слова и вперёд на Берлин. Мы начнём с теории. Итак, как же мы будем различать языки у динамического содержания, которое в лучшем случае удаляется, изменяется, а то и чего хорошего вообще накроется. Константами тут никак не обойтись, что же делать?

Я уже слышу витающие вокруг вас мысли.

Лично когда я пытался воплотить это в жизнь, то сначала я это сделал самым нерациональным способом, а именно для перевода статей разделил поля в таблице, которые подлежали переводу надвое (то есть, создал поле_eng и поле_ru) таким образом, и так большие по объёму таблицы превратились просто в непристойно огромные. Поэтому я начал искать альтернативу, и не поверите, нашёл её. Чувствуете уже теплее, да, скоро мы подойдём к самому горячему. Я нашёл выхода из этой ситуации, и сейчас намерен объяснить на пальцах его вам, и то поймёте ли вы его или нет, будет зависеть от вас. Сначала давайте, согласуем все детали.

Для начала нам нужна, будет таблица, в которой будут размещаться данные для перевода. Скажем у нас есть таблица `articles` в которой будут размещены некоторые статьи, и они должны иметь, скажем, два перевода, но один обязательно. Нас будут интересовать лишь два ключевых, в нашем случае, поля: название, описание. Мы будем осуществлять структурирование текста таким образом:
<%eng%>Английский вариант статьи</%eng%>
<%ru%>Русский вариант статьи</%ru%>
  

После строка ввиде комбинации из этих двух структур и будет добавляться в поля `title` и `description` таблицы `articles`.

Данный способ будет заключаться в поиске первого вхождения открывающего ключевого слова (допустим
<%eng%>
), после мы найдём первое вхождение закрывающего ключевого слова. Но нужно не забывать что нам нужно не именно вхождение, а длина конструкции. В первом случае мы к первому вхождению открывающей конструкции будем добавлять длину конструкции, вторым шагом будет нахождение длины закрывающей конструкции. Но вы спросите: .

Воспользовавшись функцией substr(). В качестве первого параметра будет сам текст, в качестве второго длина открывающей конструкции, в качестве третьего (самое интересное) разница между первым вхождением закрывающей конструкции и длинной текста. Да, понимаю это не так легко, но это нужно понять. Поэтому мы сейчас это и проделаем на практике. Я создал функцию, которая будет выделять текст между ключевыми тегами. Она будет принимать три параметра: текст для разбора, язык по которому нужно проводить парсинг, массив конструкций.
<?
function subTextByLang($data,$lang,
                       $delimiters=array(«<%»,«%>»,«<%/»,«%>»)) {

    $start_tag=strpos($data,$delimiters[0].$lang.$delimiters[1])+
               strlen($delimiters[0].$lang.$delimiters[1]);

    $count=(strpos($data,$delimiters[2].$lang.$delimiters[3])-strlen($data))

    $data=substr($data,$start_tag,$count);
    if(trim($data)==«»){
        $data=NOT_ENTERED;
        }
    return $data;
    }
?>
  

Как видите довольно длинно и можно запутаться, но если вы и не поняли этого, то это не большая беда, ибо функция для перебора уже есть, а чуть дальше я рассмотрю другой метод для этой же цели. Да, и не забудьте где-нибудь объявить языковую константу NOT_ENTERED, которая будет присваиваться результату работы функции в случае, если длина текста равна нулю.

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

Алгоритм не сложный и заключён в том, чтобы подставить в все языковые конструкции в одну строку. Сначала я в порывах лени я хотел ограничить скрипт определённым числом языков (так его воплотить легче), однако после одумался и получил вот что:
<?
  function compilateLanguageString($data,
   $delimiters=array(«<%»,«%>»,«<%/»,«%>»)) {
   if(!is_array($data)) {
   die(PARAM_CHECK_ERROR);
   }
   $data=«»;
   $temp=«»;
   $count=0;
   foreach($data as $k=>$v) {
   if(!is_string($k)) {
   break;
   }
   $count++;
   if($count>1 & $temp=$k) {
   die(ERROR_CONSTRUCTION_COUNT);
   }
   $temp=$k;
   $data.=$delimiters[0].$k.$delimiters[1].$v.$delimiters[2].$k.$delimiters[3];
   }
   return $data;
   }
  ?>
  

Ну, здесь я немного поясню. В качестве параметра функция принимает массив. Структура массива должна быть такой:
«индификатор языка»=>«текст»;
  

После мы делаем проверку, что если полученный параметр не массив то .

Если же это всё же массив то конечно делаем его перебор, и на место языка в конструкции ставим ключ данного элемента ассоциативного массива, а на место текста безусловно сам текст а то есть значение переменной $v. После сливаем все данные в одну строку. Но я забыл упомянуть об одной важной детали, а другими словами о довольно большом куске текста. Сначала перед циклом мы объявили три переменные: data, temp, count;

Переменная count- это количество итераций цикла, и с каждым следующим кругом цикла счётчик увеличивается. Переменная data- это будущая результирующая строка, в которую будут сливаться все языковые конструкции. Но более интересны переменные count и temp. Для чего они нужны? Ну, наверное, большинство уже догадались, прочтя исходник, но тем до кого ещё не я поясню. Это делается для проверки того, что языковая конструкция не была повторена более раза. Для этого мы и объявили переменную count. Так как её значение по умолчанию равно нулю, то мы проверяем, что цикл был выполнен хотя бы раз, поскольку если мы этого не сделаем то, выйдет что-то подобное 2=2 или 0=0, ведь значение $k ещё не успело измениться. Так как в первый раз проверка будет игнорироваться, мы после проверки присваиваем значение переменной $temp. Это делается так же не просто так. При первой итерации всё пойдёт нормально, но ведь если мы всё же присвоили значение до проверки, то проверка делала бы проверку, о которой уже упоминалось (2=2, 3=3 и т.д.). Вот зачем мы делаем именно так.

Теперь как логическое завершение мы создадим небольшой сайт, где и будет применяться всё вышеизложенное:
<?
  function subTextByLang($data,$lang,
   $delimiters=array(«<%»,«%>»,«<%/»,«%>»)) {
   $data=substr(
   $data,
   (strpos($data,$delimiters[0].$lang.$delimiters[1])+
   strlen($delimiters[0].$lang.$delimiters[1])),
   (strpos($data,$delimiters[2].$lang.$delimiters[3])-strlen($data))
   );
  
   if(trim($data)==«») {
   $data=NOT_ENTERED;
   }
   return $data;
   }
  
  function compilateLanguageString($data,
   $delimiters=array(«<%»,«%>»,«<%/»,«%>»)) {
   if(!is_array($data)) {
   die(PARAM_CHECK_ERROR);
   }
   $data=«»;
   $temp=«»;
   $count=0;
   foreach($data as $k=>$v) {
   if(!is_string($k)) {
   break;
   }
   $count++;
   if($count>1 & $temp=$k) {
   die(ERROR_CONSTRUCTION_COUNT);
   }
   $temp=$k;
   $data.=$delimiters[0].$k.$delimiters[1].$v.$delimiters[2].$k.$delimiters[3];
   }
   return $data;
   }
  
  //Не забываем о <статике>
  if(!isset($_GET[«lang»])) {
   setcookie(«lang»,$_GET[«lang»]);
   header(«Location: index.php?module=home»);
   }
  
  if(isset($_COOKIE[«lang»])) {
   include $_COOKIE[«lang»].«_map.php»;
   }
  else {
   include «ru_map.php»:
   }
  
  if(isset($_POST[«add»])) {
   $description=compilateLanguageString(
   array($_POST[«description_en»],$_POST[«description_ru»]));
   $title=compilateLanguageString(
   array($_POST[«titlte_eng»],$_POST[«title_ru»]));
  
   //Процесс добавления в базу
   }
  
  echo«<html>»;
  echo«<head>»;
  echo«<title>»;
  $title=($_SERVER[«REMOTE_ADDR»]==«127.0.0.1»)? ADMIN_WELCOM: «Гостям- Здрасте !»;
  echo $title;
  echo«</title>»;
  echo«<meta http-equiv=\"Content-Type\" Content=\"text/html; charset=».CURR_CHARSET.«\">»;
  echo«</head>»:
  echo«<body>»;
  
  $conn_id=@mysql_connect(«localhost»,«root»,«»);
  @mysql_select_db(«somedatabase»);
  $q=@mysql_query(«SELECT title, description FROM `articles` LIMIT 0,1»,$conn_id);
  if(@mysql_ num_rows($q)==0){
   ARTCILES_NOT_FOUNDED;
   }
  else {
   $row=@mysql_fetch_array($q);
   $title=subTextByLang($row[«title»],$lang);
   $description=subTextByLang($row[«description»],$lang);
   echo«<table width=\"400\" height=\"50\" align=\"center\">»:
   echo«<tr><td>».ARTICLE_TITLE_TEXT.«</td><td>».
   $title.«</td></tr>»;
   echo«<tr><td colspan=\"2\" style=\"text-align:center\">».
   ARTICLE_DESCRIPTION_TEXT.«</td></tr>»;
   echo«<tr><td colspan=\"2\">».$description.«</td></tr>»;
   echo«</table>»;
   }
  
  @mysql_close($conn_id);
  
  //Это ещё полбеды, теперь нужно создать форму для добавления статьи
  echo«<form action=\"\" method=\"post\">»;
  
  echo«<table width=\"400\" height=\"50\" align=\"center\">»;
  
  echo«<tr><td>».ARTICLE_TITLE_TEXT.
   «(EN):</td><td><input type=\"text\" ».
   «name=\"title\"></td></tr>»;
  
  echo«<tr><td>».ARTICLE_TITLE_TEXT.«
   (RU):</td><td><input type=\"text\" ».
   «name=\"title\"></td></tr>»;
  
  echo«<tr><td colspan=\"2\" style=\"text align:center\">».
   ARTICLE_DESCRIPTION_TEXT.«(EN):</tr></tr>»;
  
  echo«<tr><td colspan=\"2\" >»;
  
  echo«<textarea name=\"description_eng\" rows=\"5\" cols=\"50\"».
   «>English description</textarea>»;
  
  echo«</td></tr>»;
  
  echo«<tr><td colspan=\"2\" style=\"text-align:center\">».
   ARTICLE_DESCRIPTION_TEXT.«(RU):</tr></tr>»;
  
  echo«<tr><td colspan=\"2\" >»;
  
  echo«<textarea name=\"description_ru\" rows=\"5\" cols=\"50\">».
   «Русское описание</textarea>»;
  
  echo«</td></tr>»;
  
  echo«<tr><td colspan=\"2\"><input type=\"submit\" ».
   «name=\"add\" value=\"Добавить\"></td></tr>»;
  
  echo«</table>»;
  
  echo«</form>»;
  ?>
  

Что ж вот и всё. Однако в скрипте есть одно «но», автор не может через форму добавить более двух вариантов перевода. Не буду, как остальные автора, что сделал это для вашей тренировки, поскольку если честно то когда я дошёл до этого места у меня уже голова почти не варила, поэтому я и оставляю это на ваших плечах. Поверьте, вариантов решения полно, и я очень надеюсь, что вы его найдёте. Относительно функций, то не могу сказать на все 100% что они не вызовут сбоя но фатальных ошибок быть не должно, хотя всякое бывает. Но я уверен более чем на 60% что синтаксис нарушен, так как я не тестировал примеры. А вот здесь для вас действительно хорошая тренировка ведь ловля «блох» очень полезное занятие!

Что ж, я считаю, что на этом статью можно окончить. Если у вас не будет получаться, не сгоняйте зло на ваш бедный компьютер, на клавиатуру, и тем более на разработчиков такого замечательного языка как РНР, смело, все свои неудачи адресуйте в мою сторону. Я не думаю, что мне от этого станет хуже, а вот вам будет на кого согнать злость.

 

Интересное

Выпадающие меню с помощью CSS
Каждый, кому хоть раз приходилось создавать выпадающие меню, знаком с тем, какое количество скриптов требуется для этого. Между тем, используя грамотно структурированный HTML-код и несложные...
Подробнее...
Как выбрать телевизор?
Плазменная панель уже давно перестала быть роскошью. И в эпоху технического прогресса, многие выбирают именно этот вид телевизоров. Конечно, плазма значительно дороже, но у нее есть немало...
Подробнее...
Интерполяция изображений в...
Этот алгоритм увеличивает изображение в произвольное количество раз при помощи билинейной интерполяции. При создании нового изображения каждой его точке с целыми координатами (x,y) сопоставляется...
Подробнее...
10 фактов об архивировании...
Резервное копирование данных, конечно, не такая потрясающая штука, как двухъядерные микросхемы Intel, позволяющие установить на компьютере одновременно и Mac OS X, и Windows XP, но...
Подробнее...
Применение терминала сбора...
Терминал сбора данных - функциональное устройство, предназначенное для управления товарооборотом. К потребителю он попадает вместе со встроенным сканером, позволяющим распознавать многочисленные...
Подробнее...
Хакеры тоже заимствуют...
Хакерам по душе многие принципы сообщества open source. Они охотно делятся кодом, заимствуют готовые решения, используют чужие модули. Если бы в сообществе вирусописателей не доминировали идеи...
Подробнее...
Однофазные стабилизаторы
Однофазные стабилизаторы помогут спасти электроприборы и бытовую технику. Ежегодно, возрастает количество бытовых приборов и офисной техники используемой потребителями. Это делает востребованным...
Подробнее...
Трюки и спецэффекты в...
В наше время при помощи PhotoShop реализовывается множество различных проектов и задач, но основными являются несомненно те, которые связаны с созданием собственных изображений и визуальной...
Подробнее...
Установка Windows Server...
Семейство продуктов Windows Server 2003 берет все самое лучшее от технологии ОС Windows 2000 Server, упрощая при этом развертывание, управление и использование.В результате пользователь получает...
Подробнее...
Ставим РНР
Само собой, сначала надо его скачать. Идем на этот раз на официальный сайт http://www.php.net и ищем там раздел downloads.Собственно, искать не приходится, он в самом верху первый. После того, как...
Подробнее...