Всем доброго времени суток! И все-таки, как я давно сюда не заходил! Был я последний раз тут аж месяц назад, когда опубликовал статью о кросспостинге, но в общем то я не жалею, что со временем у меня были реальные проблемы. Мои проблемы во времени - это мое счастье. Я устроился на человеческую нефрилансерную работу PHP - девелопером, работаю, радуюсь, и все прямо так и прет - очень везет во всем. К слову, я даже переехал из своего города в другой, в общем, все круто изменилось.
На данный момент моя работа в фирме направлена на мультиязычность наших сайтов - я выкладываю новые переводы сайта, а так же разрабатываю систему автоматизации тиражирования сайта. С учетом всего вышесказанного, я хотел поделиться своими мыслями по поводу "Как сделать мультиязычный сайт?".
Задача: реализовать мультиязычный сайт и выделить в отдельный класс, где: сайт использует шаблоны, сессии и куки; не использует бд для хранения статического контента (если использовать бд - класс модифицируется очень просто); использует файлы для хранения статических страниц и шаблонного контента.
Рассмотрим структуру такого сайта сверху вниз, т.е. начиная с вывода содержимого сайта в шаблоне и заканчивая методами класса.
<?
//указываем, что сайт будет использовать сессии
@session_start();
//подключаем файл класса
require_once 'system/main.class.php';
//создаем объект класса langSys
$langsys = new langSys;
//управление навигацией
if (isset($_GET['do'])) {
$page = $_GET['do'];
$_SESSION['langsys_page'] = $page;
header("Location: " . $langsys->domain . '?page=' . $page);
}
else if (!isset($_GET['page']) && !isset($_GET['lang'])) {
$_SESSION['langsys_page'] = $langsys->startPage;
$langsys->page = $_SESSION['langsys_page'];
}
//если меняем язык
(!isset($_GET['lang'])) ? '' : $langsys->changeLang($_GET['lang']);
?>
//шаблон
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta name="KeyWords" content="">
<meta name="Description" content="">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>I am Language System</title>
</head>
<body>
<div style="width:95%;margin:auto;padding-top:15px;">
//форма для управления языком
<div style="text-align:center;margin-bottom:15px;">
<a href="?lang=ru">Rus</a> |
<a href="?lang=en">Eng</a>
</div>
//вывод содержимого страницы
<div style="float:left;width:80%">
<?=$langsys->getContentByLang($langsys->page, $langsys->lang)?>
</div>
//вывод меню
<div style="width:10%; margin-left:30px;float:right;">
<ul>
<li><a href="?do=about"><?$langsys->translate(1);?></a></li>
<li><a href="?do=faq"><?$langsys->translate(2);?></a></li>
<li><a href="?do=advert"><?$langsys->translate(3);?></a></li>
<li><a href="?do=descript"><?$langsys->translate(4);?></a></li>
</ul>
</div>
</div>
</body>
</html>
Перед вами собственно шаблон сайта, где будет выводиться наш мультиязычный контент. Если идея уже понятна, то хорошо, но все же я хочу пояснить, что же я тут написал и как оно работает.
Организация навигации по сайту.
Всем передвижением по сайту управляет два GET - параметра, передаем мы их в адресной строке, как известно. Первый параметр "do" управляет страницами и хранится он в суперглобальном массиве $_SESSION под индексом "langsys_page". Второй параметр “lang“ управляет используемым языком на сайте, хранится он в куки (суперглобальный массив $_COOKIE) под индексом "langsys_lang".
Как происходит перенаправление по страницам и языкам? В этом, кстати, был основной интерес. Проблема заключалась в том, что как только пользователь решал изменить язык сайта, то ему показывалась стартовая страница, а не просто изменялась на другой язык та, которую он просматривал. Это хорошо, если сайт маленький, а если в нем бесчисленное количество статей - потом попробуй найти ту, которую читал. Проблему решил вариант добавления текущей страницы в сессию, то есть наша функция getContentByLang($page, $lang); смотрела в массив сессий, чтобы знать какую страницу показывать, но никак напрямую не общалась с изменение GET – параметра.
Размещение текущей страницы в массиве сессий решило первую проблему, но привлекло другую – теперь если мы находились на странице http://site.ru/?do=about и вдруг решили перейти на заглавную страницу http://site.ru/, то мы останемся и никуда не перейдем. Почему? – мы не передали никакого значения $_GET[‘do’], соответственно текущая страница не изменилась в сессии и сайт никак не отреагировал. Делать главную страницу под ссылкой, например http://site.ru/?do=main глупо, поэтому существует еще одно условие в управлении навигацией:
else if (!isset($_GET['page']) && !isset($_GET['lang'])) {
$_SESSION['langsys_page'] = $langsys->startPage;
$langsys->page = $_SESSION['langsys_page'];
}
То есть, в случае, когда у нас не установлены GET – параметры page и lang, мы присваиваем элементу массива сессий “langsys_page” значение startPage, которое заранее мы объявили в конструкторе наше класса langSys, но об этом уже далее.
Основные конструкции для хранения данных.
В этой системе я воспользовался двумя методами хранения данных:
1. Ассоциативный массив, где ключ это идентификатор слова, а значение это переведенное слово. Кстати, ключом может быть как целочисленное значение, так и слово, например на русском. Использую я первый вариант, так как пожелания при разработке были таковыми. Выглядит это так:
//английский
<?
$this->arr_lang{$lang} = array(
1=>'About us',
2=>'FAQ',
3=>'Advertisement',
4=>'Descript'
)
?>
//русский
<?
$this->arr_lang{$lang} = array(
1=>'О нас',
2=>'Частые вопросы',
3=>'Реклама на сайте',
4=>'Описание'
)
?>
Если вы обратите внимание на шаблон, то можете увидеть, что мы вызывали функцию translate($id). Эта функция как раз и выводит нужное слово, обращаясь в куку за значением текущего языка:
function translate($id, $lang = '') {
//если язык на передан в функции
if ($lang == '')
$lang = $this->lang;
//загружаем языковой файл
if (!isset($this->loaded[$lang])) {
include_once $this->rootLang.''.$lang.'/'.$lang.'.php';
$this->loaded[$lang] = true;
}
//дополнительная фишка для показа индекса слова на странице
if (isset($this->arr_lang{$lang}[$id]) && (isset($_GET['show_index']))){
($_GET['show_index'] == 'true') ? print '<font color="red" size="5">'.$id.'</font> '.$this->arr_lang{$lang}[$id] : '';
}
//вывод слова на страницу
else if (isset($this->arr_lang{$lang}[$id])) {
print $this->arr_lang{$lang}[$id];
}
//если перевод по id не найден
else {
print $id;
}
}
Функции так же можно передавать напрямую значение текущего языка, а не брать его из куки. Нужно для того, чтобы программист мог вручную выбирать, на каком языке показывать то или иное слово/фразу.
2. Второй вариант хранения информации на сайте предназначен для больших блоков информации, а не отдельных фраз или же слов. По этому методу мы создаем отдельные страницы, например about.php, faq.php и т.д. с обычной html версткой (параграфы, форматирование текста, гиперссылки) и нужным содержимым, которое мы бы хотели видеть на странице. Его можно брать как из этого же файла, так и подгружать из базы. Взял я первое, потому что в моем случае – чем меньше обращений к базе данных, тем лучше. На самом деле, если вы будете использовать подобную структуру на сайте с небольшой нагрузкой, то можно грузить и из базы, если же у вас на сайте до десятков тысяч посещений в день, то соответственно понимаете, что лишняя нагрузка на базу неуместна.
Сама функция, подгружающая нужную страницу:
function getContentByLang ($page, $lang) {
$file = $page.'_'.$lang.'.php';
include_once $this->rootLang.''.$lang.'/'.$file;
}
Ничего замысловатого.
Смена языка.
В начале этой статьи я рассказывал о том, как организуется навигация по сайту и про то, как меняется язык. Еще раз напоминая, текущий язык записывается в куки под индексом “langsys_lang”, после чего им могут воспользоваться функции, выводящие содержимое сайта, чтобы показать информацию на нужном языке.
Для того чтобы изменить язык мы используем простое условие, реагирующее на изменение GET – параметра “lang”:
(!isset($_GET['lang'])) ? '' : $langsys->changeLang($_GET['lang']);
Которое, при получении такового вызывает функцию changeLang($lang) (смена текущего языка):
function changeLang($lang) {
//устанавливаем текущий язык
$this->lang = $lang;
//записываем в куки его значение
setcookie("langsys_lang", $this->lang, time()+60*60*24*30);
//возвращаемся на ту же страницу
$this->page = $_SESSION['langsys_page'];
}
С языками на этом все, теперь можно перейти к конструктору класса langSys.
Конструктор класса langSys.
Когда все вышесказанное было прочитано, можно перейти и к настройкам нашей системы. Для этого используется конструктор, в котором мы можем перечислить все настройки, используемые потом в системе и на сайте в целом, например root – директория или же язык по умолчанию.
Выглядит это так:
function __construct() {
$this->root = $_SERVER['DOCUMENT_ROOT'];
$this->domain = 'http://' . $_SERVER['HTTP_HOST'];
$this->rootLang = $this->root . '/lang/';
$this->startLang = 'ru';
$this->startPage = 'about';
$this->page = $_SESSION['langsys_page'];
if (!isset($_COOKIE['langsys_lang'])) {
setcookie("langsys_lang", $this->startLang, time()+60*60*24*30);
header("Location: " . $this->domain);
}
$this->lang = $_COOKIE['langsys_lang'];
}
Я думаю, в этом случае комментарии не нужны. Но скажу, что это все упрощает модификацию, и использование класса в дальнейшем.
Вот и все, что думал по этому поводу я сказал, надеюсь, это поможет кому-нибудь, с уважением, Я!
Знаете ли вы?
Что человек - единственный представитель животного мира, способный рисовать прямые линии.