Мультиязычность в Smarty — Организация мультиязычности на сайте

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

Существует множество способов реализации мультиязычности ,наиболее простым из них является:

  1.  Создание несколько типов файлов с языковыми константами или переменными. Константы прописываются жестко в файле вида.
  2. «Изощренные» умы создают несколько полных копий сайтов на разных языках.
  3.  Организация мультиязычности через Gettext

Каждый из этих способов имеет как плюсы так и минусы ,мой способ ближе скорей всего к Gettext ,но попроще )

Сегодня мне бы хотелось бы на конкретном примере и отдельно взятом шаблонизаторе Smarty показать свою реализацию мультиязычности.

Алгоритм работы:

  1. Все заключенное между тегами {t}{/t} в шаблонах ,отправляем на проверку.
  2. Проверяем если язык русский то отправляем обратно без перевода ,если не русский отправляем на перевод.
  3. Создаем массив типа ключ — значение ,в котором ключ фраза на русском языке ,в данном случае это данные заключенные между тегов {t}{/t}
  4. Проверяем если данная фраза — ключ имеет непустое значение выдаем значение(т.е перевод данного слова) ,иначе отправляем обратно без перевода.

Преимущества:

  1. Простота ,для перевода просто используем теги {t}{/t} в шаблонах
  2. Если слова нет в базе ,то оно добавиться автоматом ,вам лишь затем следует его дополнительно перевести на другой язык через phpmyadmin, или написать оболочку для админки что очень просто )
  3. Если слово не найдено ,то оно вернется просто без перевода.
  4. При использовании кеширования ,практически отсутствие нагрузки.
  5. Удобство перевода и поддержания его соответствующем состоянии.

Для этого создадим  файл: block.t.php в директории smarty/plugins:

<?php
/**
 * @package Smarty
 * @subpackage {t}{/t}
*/
function smarty_block_t($params, $content, &$smarty)
{
/**
 * Получаем глобальные переменные
 */
$settings = Registry::get('settings');
$cache = Registry::get('cache');
$db = Registry::get('db');
if ($content!=NULL) {
$content=trim($content);
 if ($settings->language_translate)
 {
 /**
 * Русский язык стандартный для всех шаблонов
 * Он не переводится
 */
 if ($settings->lng == 'rus') {
 return $content;
 } else {
 /**
 * Получаем переведенные слова
 */
 return language::get_words($content, $settings, $cache, $db);
 }
 } else {
 return $content;
 }
} else {
return $content;
}
}
?>

В объекте — $settings находятся настройки сайта.
Объект — $cache экземпляр класса кэширования
Объект — $db экземпляр класса соединения с базой

Теперь создадим класс в котором будет выполняться вся работа по переводу. Переводы как вы я думаю догадались будут храниться в базе.

<?php
/**
 * Класс мультиязычности
*/
abstract class Language {
     static function get_words($content ,$settings, $cache, $db)
     {
         /**
         * Для уменьшения нагрузки используем класс для работы с кешированием
         */
	 if (!$language = $cache -> get('language.'.$settings->lng))
	 {
            foreach ($db->query('SELECT `default`, `'.$settings->lng.'` FROM `language_'.$settings>lng.'`') as $row) {
            $language[$row['default']] =  $row[$settings->lng];
            }
	   $cache -> set('language.'.$settings->lng, $language , 3600*24);
	 }
	   if (!empty($language[$content]))
	   {
            /**
            * Если выбранная нами фраза на русском языке существует в базе ,то выдать его аналог на другом языке ,инача или добавить фразу в словарь и вывести слово без перевода
            */
	    return $language[$content];
	   } else {
		  if ($settings->language_add_words)
		  {
                  /**
                  * Сохранение неизвестного нам слова в словаре.
                  */
		   self::save_default_words($content, $settings, $db);
		  }
	   return $content;
	   }
     }
     static function save_default_words($content,$settings, $db)
     {
     /**
     * Добавления слов в словарь
     */
	    if (!$db->query('SELECT COUNT(*) FROM `language_'.$settings->lng.'` WHERE `default` = "'.$content.'" LIMIT 1')->fetchColumn())
	    {
           $db->exec('INSERT INTO `language_'.$settings->lng.'` (`default`) VALUES ("'.$content.'")');
		}
     }
}
?>

Структура таблиц в базе такая ,название таблицы language_’выбранный нами язык в настройках’

CREATE TABLE IF NOT EXISTS `language_eng` (
  `default` varchar(1024) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'Тест',
  `eng` varchar(1024) COLLATE utf8_unicode_ci NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Мой код конечно требует реставрации под ваш код ,я его выдрал кусками у себя из проекта. Но я думаю общий алгоритм понятен и переделка кода не составит труда даже под другой шаблонизатор.

Благодарю за внимание ). Вопросы пишем в комментариях ).