Next Generation CMS :: Форум поддержки

Заинтересовала наша система? Тогда этот форум для Вас!

Вы не зашли.

#1 2012-02-12 16:35:08

easmik
VIP забанил этого пользователя.
Зарегистрирован: 2011-02-01
Сообщений: 1,031
Рейтинг :   37 

Создаем полноценный мультиязычный сайт

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

Суть сводиться к клонированию двига. Это дает нам не только контент на другом языке, но также и карту сайта, RSS ленту и т.п. Хочу сразу сказать что данный вариант подходит под любой вид новостных сайтов. Итак начнем:

Сначала нам надо внести изменения из SVN http://trac.assembla.com/ngcms/changeset/891 и http://trac.assembla.com/ngcms/changeset/900, первое это изменения позволяющие в названия категорий использовать символы {}, второе делает доступным языковые блоки iflang

Шаг первый. Первое что нам нужно, разобраться как будут работать заголовки, для этого открываем functions.inc.php и находим там

$tvars = array ( 'vars' => array( 'pagination' => '', 'title' => $row['title']));

перед ней вставляем

if (preg_match_all('/\[iflang\:(.+?)\](.+?)\[\/iflang\]/is', $row['title'], $parr)) {
   foreach ($parr[0] as $k => $v) {
    $row['title'] = str_replace($v,($config['default_lang'] == $parr[1][$k])? $parr[2][$k]:'', $row['title']);
   }
  }

теперь конструкция

[iflang:russian] Описание [/iflang]
[iflang:english] Description [/iflang]  будет работать и для заголовков.

P.S.Если Вы планируете со временем расширение языков, то можно сделать так.
[iflang:russian] Заголовок / [/iflang] Header
Это нужно для того, чтоб при добавлении других языков, старые (уже опубликованные) новости отображали хоть какой то заголовок (если переделать все не представляется возможным)

Выглядеть в админке это будет так:
383e45989bf1d6e1f6c600c2be92fee4.jpg

на сайте так:

f6267759d2d61546aa176b0e2df70b9c.jpg af734f9bc26a42360cab0523bcc4d926.jpg
Xочу заметить что не что не мешает заключить и заголовок на английском в языковой блок.

Сразу же "вычистим" конструкцию iflang из заголовков (для нормального отображения в браузере).
index.php, находим:

$template['vars']['titles'] = join(" : ", array_values($SYSTEM_FLAGS['info']['title']));

Заменяем на:

$titles = join(" : ", array_values($SYSTEM_FLAGS['info']['title']));

if (preg_match_all('/\[iflang\:(.+?)\](.+?)\[\/iflang\]/is', $titles, $parr)) {
 foreach ($parr[0] as $k => $v) {
  $titles = str_replace($v,($config['default_lang'] == $parr[1][$k])? $parr[2][$k]:'', $titles);
 }
}

$template['vars']['titles'] = $titles;

Шаг второй. В движке используются языковые переменные (вида {l_variable}), которые пригодятся и нам. Как в самом контенте, так и в заголовках категорий.

Начнем с категорий, открываем файл engine/core.php в самом низу дописываем следующий код:

$timer->registerEvent('* CORE.PHP is complete');
foreach ($catz as $catid => $catdata) {
  if (preg_match_all('/(?<=\{)l_(.*?)(?=\})/i', $catz[$catid]['name'], $larr)) {
   foreach ($larr[0] as $k => $v) {
    $name_larr = substr($v, 2);
    $catz[$catid]['name'] = str_replace('{'.$v.'}', isset($lang[$name_larr])?$lang[$name_larr]:'[LANG_LOST:'.$name_larr.']', $catz[$catid]['name']);
   }
  }
}

затем открываем /engine/actions/categories.rpc.php :
Находим:

$tvars['vars'] = array(
			'token'		=>	genUToken('admin.categories'),
			'php_self'	=>	$PHP_SELF,
			'rid'		=>	$row['id'],
			'name'		=>	$row['name'],

После вставляем:

// Transcode category name
  		if (preg_match_all('/(?<=\{)l_(.*?)(?=\})/i', $row['name'], $larr)) {
  			foreach ($larr[0] as $k => $v) {
				$name_larr = substr($v, 2);
				$row['name'] = str_replace('{'.$v.'}', isset($lang[$name_larr])?($lang[$name_larr].' <span style="color: red;">(UNIV)</span>'):'[LANG_LOST:'.$name_larr.']', $row['name']);
			}
		}

// Кстати <span style="color: red;">(UNIV)</span> - это дает возможность подсвечивать категории в которых используется переменная а не название (очень удобно)

ВАЖНО: переменные прописываются в папке lang/язык/common.ini имеют вид
nw_unknow = "Категория неизвестна", nw_unknow = "Category unknown" и т.д. по аналогии, а в название категории Вы прописываете {l_nw_unknow}

В админке это будет выглядеть так: 2b2dd6b56df51428ff78c7f8dcd359ec.jpg

на сайте так:
388ec7b0c4bdd2ade269c485d8575dd5.jpg 76a9bb371f7848d2a7270b1c6fcf751b.jpg

Шаг третий. Теперь сделаем так чтоб языковые переменные работали в контенте для этого открываем файл engine\includes\inc\functions.inc.php
Находим там строчку:

function newsFillVariables($row, $fullMode, $page = 0, $disablePagination = 0, $regenShortNews = array()) {

ниже вставляем

 if (preg_match_all('/(?<=\{)l_(.*?)(?=\})/i', $data, $larr)) {
   // Show language variables
   foreach ($larr[0] as $k => $v) {
    $name_larr = substr($v, 2);
    $data = str_replace('{'.$v.'}', isset($lang[$name_larr])?$lang[$name_larr]:'[LANG_LOST:'.$name_larr.']', $data);
   }
  }

Все, двиг начал обрабатывать языковые переменные и в контенте. Теперь пропишем сами переменные
открываем \engine\lang\ЯЗЫК\site\news.ini и вписываем свои переменные.

Например: Если сделать такую запись
archive = "Архив"
то станет доступна переменная {l_archive}

Собственно для чего нужны языковые переменные, когда есть блоки. Иногда внутри новости нам нужно обозначить характеристики (размер) или формат, и пользоваться блоками не очень удобно, т.к. они огромны.
Пример использования в админке:
forum_yp1.jpg
А вот как это будет выглядеть на сайте:
forum_yp2.jpg forum_yp3.jpg

Теперь что касается самих языковых блоков, снова открываем functions.inc.php

Находим:

if ($config['blocks_for_reg'])        { $short = $parse -> userblocks($short);    $full = $parse -> userblocks($full); }

ниже добавляем:

if (preg_match_all('/(?<=\{)l_(.*?)(?=\})/i', $short, $larr)) {
       // Show language variables
       foreach ($larr[0] as $k => $v) {
        $name_larr = substr($v, 2);
       
      if (preg_match_all('/(?<=\{)l_(.*?)(?=\})/i', $data, $larr)) {
   // Show language variables
   foreach ($larr[0] as $k => $v) {
    $name_larr = substr($v, 2);
    $data = str_replace('{'.$v.'}', isset($lang[$name_larr])?$lang[$name_larr]:'[LANG_LOST:'.$name_larr.']', $data);
   }
  }    $short = str_replace('{'.$v.'}', isset($lang[$name_larr])?$lang[$name_larr]:'[LANG_LOST:'.$name_larr.']', $short);
       }
      }
      if (preg_match_all('/(?<=\{)l_(.*?)(?=\})/i', $full, $larr)) {
       // Show language variables
       foreach ($larr[0] as $k => $v) {
        $name_larr = substr($v, 2);
        $full = str_replace('{'.$v.'}', isset($lang[$name_larr])?$lang[$name_larr]:'[LANG_LOST:'.$name_larr.']', $full);
       }
      }
      
       if (preg_match_all('/\[iflang\:(.+?)\](.+?)\[\/iflang\]/is', $short, $parr)) {
   foreach ($parr[0] as $k => $v) {
    $short = str_replace($v,($config['default_lang'] == $parr[1][$k])? $parr[2][$k]:'', $short);
   }
  }
 
    if (preg_match_all('/\[iflang\:(.+?)\](.+?)\[\/iflang\]/is', $full, $parr)) {
   foreach ($parr[0] as $k => $v) {
    $full = str_replace($v,($config['default_lang'] == $parr[1][$k])? $parr[2][$k]:'', $full);
   }
  }

Теперь нам будет доступна следующая конструкция
21e474e047353f1269dba82a06826441_pv.jpg

На сайте будет выглядеть так:
100ac6cad7abe5169f61f41ba837bb87.jpg 9a586020c81e4f3592a5dcc7bac59de4.jpg

Причем как многие наверняка уже поняли конструкция может быть абсолютно любой
например:
[iflang:russian]На русском[/iflang]
[iflang:english]На английском[/iflang]
КАРТИНКА
[iflang:russian]На русском[/iflang]
[iflang:english]На английском[/iflang]
КАРТИНКА
еще КАРТИНКА
[iflang:russian]На русском[/iflang]
КАРТИНКА
[iflang:english]На английском[/iflang]

Шаг четвертый: Убираем конструкцию iflang из RSS
Открываем плагин, находим:

$output .= "   <title><![CDATA[".((extra_get_param('rss_export','news_title') == 1)&&GetCategories($row['catid'],true)?GetCategories($row['catid'], true).' :: ':'').secure_html($row['title'])."]]></title>\n";

перед ней вставляем:

 if (preg_match_all('/\[iflang\:(.+?)\](.+?)\[\/iflang\]/is', $row['title'], $parr)) {
print "<pre>".var_export($parr, true)."</pre>";  
 foreach ($parr[0] as $k => $v) {
    $row['title'] = str_replace($v,($config['default_lang'] == $parr[1][$k])? $parr[2][$k]:'', $row['title']);
   }
  }

теперь лента выглядит так:
040a7cbc331ce5fa161890168b6ca970.jpg 82b80064053a51aba4c502cab6ab42de.jpg

Шаг пятый: Убираем конструкцию iflang из плагина breadcrumbs (спасибо ROZARD)

Открываем breadcrumbs.php, находим

$catids = $SYSTEM_FLAGS['news']['db.categories'];
   
$location_last = $SYSTEM_FLAGS['info']['title']['item'];
после добавить:

if (preg_match_all('/\[iflang\:(.+?)\](.+?)\[\/iflang\]/is', $location_last, $parr)) {
    foreach ($parr[0] as $k => $v) {
     $location_last = str_replace($v,($config['default_lang'] == $parr[1][$k])? $parr[2][$k]:'', $location_last);
    }
   }

и последнее что нам нужно сделать, клонировать двиг. Для этого нам нужно взять "чистый двиг", и из старого взять все файлы кроме папки uloads и скопировать в папку с чистым двигом. Причем тут есть два варианта. Наример eng версия может находиться по адресу http://youdesigner.kz/en/, а старая соответственно http://youdesigner.kz или же как у меня сейчас для eng отдельный домен http://youdesigner.net

Теперь осталось зайти в файл engine/conf/config.php
и заменить следующие строки (допустим вы выбрали вариант, при котром у Вас eng версия храниться в папке en того же домена)
'home_url' => 'http://domain.kz/en/',
'admin_url' => 'http://domain.kz/en/engine',

теперь войдя в админку не забудьте переименовать сайт и указать дефолтный язык.
в плагине rss который уже будет в папке en/engine/plugins/rss_export также переименуйте сайт

Английская карта сайта и rss будут находиться соответственно тут
http://domain.kz/en/plugin/gsmg/
http://domain.kz/en/rss.xml

Ну вот и все, одно оформление на любом из сайтов и инфа доступна сразу на двух.

и еще раз для тех у кого будет строго два языка Вы можете заголовки заключить в два языковых блока и тогда в Русской версии не будет английского названия и наоборот.

P.S. ОГРОМНОЕ СПАСИБО vitaly, ROZARD, Wolverine - эти ребята гении :)

Изменено easmik (2012-06-24 17:55:22)

Не в сети

#2 2012-02-12 21:08:42

Wolverine
Модератор
Откуда Домодедово
Зарегистрирован: 2008-10-13
Сообщений: 3,538
Рейтинг :   160 
Сайт

Re: Создаем полноценный мультиязычный сайт

А зачем два двига? Чтобы у них был разный параметр $config['default_lang']?

Не в сети

#3 2012-02-12 22:35:46

easmik
VIP забанил этого пользователя.
Зарегистрирован: 2011-02-01
Сообщений: 1,031
Рейтинг :   37 

Re: Создаем полноценный мультиязычный сайт

Wolverine, не только, но и для карты сайта и rss ленты

Не в сети

#4 2012-02-12 22:45:12

Wolverine
Модератор
Откуда Домодедово
Зарегистрирован: 2008-10-13
Сообщений: 3,538
Рейтинг :   160 
Сайт

Re: Создаем полноценный мультиязычный сайт

Если ты уже столько пропатчил, то допатчить еще карту сайта и RSS это как-то разумнее, чем делать новую инсталляцию движка.

А switcher вроде переключает языки в зависимости от домена.

Не в сети

#5 2012-02-13 02:48:21

easmik
VIP забанил этого пользователя.
Зарегистрирован: 2011-02-01
Сообщений: 1,031
Рейтинг :   37 

Re: Создаем полноценный мультиязычный сайт

Wolverine, не, устанавливать второй раз не нужно, просто скопировать. Хотя если бы я знал как, то может быть и разумнее smile

Изменено easmik (2012-02-13 07:25:15)

Не в сети

#6 2012-02-13 13:38:44

legenda
Участник
Откуда ua
Зарегистрирован: 2009-12-22
Сообщений: 2,160
Рейтинг :   39 

Re: Создаем полноценный мультиязычный сайт

easmik, как я уже с тобой обсуждать, чето меня немного напрягает это вот штука

[iflang:english]

както не кошерно все это, если б ктото взялся доделать до состояни хорошого юзабилити (хотяби какимито кнопочками или хз), то было б супер

Не в сети

#7 2012-02-13 14:56:25

easmik
VIP забанил этого пользователя.
Зарегистрирован: 2011-02-01
Сообщений: 1,031
Рейтинг :   37 

Re: Создаем полноценный мультиязычный сайт

legenda, это стандартный блок который можно в бб кнопку добавить. Хочешь конечно можешь через xfields решить данный вопрос, чтоб вводить отдельно без блоков.

Не в сети

#8 2012-07-05 23:10:43

vitaly
Администратор
Откуда Россия
Зарегистрирован: 2008-10-08
Сообщений: 2,823
Рейтинг :   118 

Re: Создаем полноценный мультиязычный сайт

Попробовал сегодня сделать патч по этой инструкции.
1. В ней не всё чисто, кое-что пришлось допиливать руками. Но возможно всё связано с различием в версиях (делал патчи для текущей SVN версии)
2. Решение действительно достаточно простое и интересное
3. Поддержка нескольких языков и правда ОЧЕНЬ нужна в NG

А вообще - спасибо за инструкцию!

Не в сети

#9 2012-07-06 05:01:02

easmik
VIP забанил этого пользователя.
Зарегистрирован: 2011-02-01
Сообщений: 1,031
Рейтинг :   37 

Re: Создаем полноценный мультиязычный сайт

vitaly, тебе спасибо smile Ты написал мне первую обработку iflang для контента и от туда я уже начал "плясать"

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

Хотя можно сделать как я уже когда то предлагал http://ngcms.ru/forum/viewtopic.php?pid=23429#p23429 (пункт 4)

А для контента конструкцию лучше чем iflang просто не придумать (очень удобно и понятно даже обычному контент менеджеру), только разве что кнопочки доделать по типу bb кодов (или выпадающий список) как предлагал legenda

p.s. vitaly а в контенте у тебя iflang так и не заработал smile открой любой пост из раздела блог

Не в сети

#10 2013-04-12 19:01:25

FeSs
Участник
Откуда Сызрань
Зарегистрирован: 2010-10-22
Сообщений: 151
Рейтинг :   
Сайт

Re: Создаем полноценный мультиязычный сайт

$template['vars']['titles'] = join(" : ", array_values($SYSTEM_FLAGS['info']['title']));

в functions.inc.php такого не найдено, 0.9.3 Release

И нужно ли делать - http://trac.assembla.com/ngcms/changeset/891 и http://trac.assembla.com/ngcms/changeset/900 для 0.9.3 версии?

Не в сети

#11 2013-10-05 07:12:27

easmik
VIP забанил этого пользователя.
Зарегистрирован: 2011-02-01
Сообщений: 1,031
Рейтинг :   37 

Re: Создаем полноценный мультиязычный сайт

UriyZenkov, скорее всего нет, если копировать один в один.

Не в сети

#12 2013-10-07 07:06:27

easmik
VIP забанил этого пользователя.
Зарегистрирован: 2011-02-01
Сообщений: 1,031
Рейтинг :   37 

Re: Создаем полноценный мультиязычный сайт

UriyZenkov, я не проверял, http://youdesigner.kz работает на 0.9.3 SVN 900, тогда твига еще не было.

Не в сети

#13 2013-10-08 06:20:33

easmik
VIP забанил этого пользователя.
Зарегистрирован: 2011-02-01
Сообщений: 1,031
Рейтинг :   37 

Re: Создаем полноценный мультиязычный сайт

UriyZenkov, круто, я забыл что писал это. У меня как раз в этой версии SVN только это и не работало smile Там на самом деле не много поменялось, если копировать код который я писал и искать в файле, то не найдешь, а если брать часть и искать, то там все легко.
Если время будет то может быть переделаю под последнюю SVN в воскресенье (но нечего не обещаю)

Не в сети

Подвал раздела

Работает на FluxBB