Опыт создания мультиязычных приложений

slmark

Новичок
Опыт создания мультиязычных приложений

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

Спасибо.
 
Как вариант - хранить таблицу языков (Lang)
id | sName | ...
1 | Русский
2 | Китайский

И в каждой таблице где нужна поддержка нескольких языков - добавлять поле iLang - ссылка на запись в таблице языков.
Тогда все запросы не сильно усложнятся - всего лишь добавлением одного условия: WHERE другие_условия_выборки AND iLang = "Текущий_язык_сессии".
 

pilot911

Новичок
то есть необходимо, чтобы одна запись в таблице БД была сразу на нескольких языках ?

имхо, такие темы лучше решать через BLOB - хранить в поле сериализованный массив titles, descriptions и тп, а все остальные общие поля записи остаются теми же



то есть, например, структура таблицы


`id` int(6) unsigned NOT NULL AUTO_INCREMENT,
`title` BLOB NOT NULL,
`subheader` BLOB NOT NULL,
`text` BLOB NOT NULL,
`deleted` tinyint(2) unsigned NOT NULL default '0',
`disabled` tinyint(2) unsigned NOT NULL default '0',
`crdate` int(11) unsigned NOT NULL default '0',
`tstamp` int(11) unsigned NOT NULL default '0',


вывод:

htmlspecialchars($row['title'][$this->language])


сохранение:

$array_data['title'] = model_job::serialize($this->job_data['title'], array($this->language => (trim($_POST['title'])?trim($_POST['title']):'_no_title' )));



и две функции для сохранения/извлечения каждой записи:



PHP:
class model_job {

	static function	unserialize(&$row)	{

 		if (isset($row['title']))	{
			$row['title']		=	strlen($row['title'])?unserialize($row['title']):array();
 		}
   	}
	
	
	
	static function	serialize($row, $value)	{
 		return	serialize(array_merge((array)$row, $value));
  	}

}
 

slmark

Новичок
dimagolov
Да, извините. К сожалению, про слово "локализация" я совсем забыл.
pilot911, Loshadka
Спасибо.
 

dimagolov

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

tardis

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

slmark

Новичок
А насколько хороша следующая идея.
хранить статические данные в разных шаблонах:
ru/
- templates/
- images/
- css/
en/
- templates/
- images/
- css/

А в таблицах где нужны локализация, добавить столбец lang, который будет содержать сокрацение языка (en, ru ...), и в соответствии с тем в какой локали юзер находиться, добавлять в выборку язык. Таким образом таблица будет расти не вширь а в длину.
 

phprus

Moderator
Команда форума
В PostgreSQL я решал подобную задачу следующим образом.
В PostgreSQL поля могу хранить массивы, по этому если какое-либо поле таблицы требовало перевода, то создавались 2 поля: Первое поле - текст на основном языке, второе поле - это двумерный массив в котором хранились пары <код языка, перевод>.
Для получения перевода была написана простая хранимая функция. В запросе получение переводов выглядело примерно так:
SELECT ..., translate('ru', field_default, field_translates) as field FROM ...

В моей ситуации поиск по таким полям не предполагался, по этому я не очень уверен в том, что такая система подойдет в случае если нужен поиск по переводам.

Так-же не могу гарантировать оптимальность подобного решения.
 

pilot911

Новичок
Автор оригинала: tardis
ну, навскидку, есть у тебя английский и немецкий язык
и слово, встречающееся в обоих языках
и задача найти только на английских страницах это слово
и что тебе выдаст твой поиск
ну во-первых, HTML страница парсится встроенным/внешним пауком в момент первой генерации перед выдачей броузеру

найденные словоформы заносятся в соответствующую таблицу с указанием урла и тп.. в самом простом варианте

тут просто

если уж действительно нужна атомарность - флаг в руки, я разве против ?
 

phprus

Moderator
Команда форума
pilot911
ну во-первых, HTML страница парсится встроенным/внешним пауком в момент первой генерации перед выдачей броузеру
А зачем? Зачем делать двойную работу, если данные уже есть в СУБД?
 

slmark

Новичок
dimagolov
не совсем понял ответ... Я имел ввиду что новые столбцы не будут добавляться, т.е. не будет title_en, title_ru, title_jp и т.д., а будут добавляться только строки с разными локализациями.
 

tardis

lazy
Автор оригинала: pilot911
ну во-первых, HTML страница парсится встроенным/внешним пауком в момент первой генерации перед выдачей броузеру

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

-~{}~ 21.10.08 17:53:

да, кстати, в этом случае получается, что если страничку никто не открывал, то ее никто и найдет))
 

pilot911

Новичок
Автор оригинала: slmark
А насколько хороша следующая идея.
хранить статические данные в разных шаблонах:
ru/
- templates/
- images/
- css/
en/
- templates/
- images/
- css/

А в таблицах где нужны локализация, добавить столбец lang, который будет содержать сокрацение языка (en, ru ...), и в соответствии с тем в какой локали юзер находиться, добавлять в выборку язык. Таким образом таблица будет расти не вширь а в длину.
я выбрал такой вариант: для каждого экстеншена иметь такую структуру

- locallang/
- templates/
- images/
- css/


в папке - locallang/ хранить лейблы и тп в файлах

en.locallang.xml
ru.locallang.xml


внутри этих файлов xml имеет такой вид



PHP:
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<S3locallang>
	<meta type="array">
		<description>Web module.</description>
		<type>module news_manage</type>
	</meta>
	<data type="array">
 
			<label index="ext.title">Bond</label>
			<label index="mod.table">Bonds</label>
			<label index="_save">Save</label>
 			<label index="_deleted">Delete</label>
			<label index="_disabled">Hide</label>
			<label index="_showed">Showed</label>
			<label index="_edit">Edit</label>
			<label index="_search_by_id">by id</label>

...........

все это парсится в массив, который легко можно закэшировать

и в итоге система работает так

$this->getLL('_save');

PHP:
	function initLL($pathLL='')	{
		$this->lang_labels	=	cmf_div::xml2array(file_get_contents($pathLL));
			 
  	}
 
 
	function	getLL($word='')	{
 		return	(isset($this->lang_labels['data'][$word]) ? $this->lang_labels['data'][$word] : '');
 	}
-~{}~ 21.10.08 17:55:

Автор оригинала: tardis
поисковичок-с решили написать, рановато вы свой флаг в чужие руки отдаете

-~{}~ 21.10.08 17:53:

да, кстати, в этом случае получается, что если страничку никто не открывал, то ее никто и найдет))
обычно для этих целей пауки существуют
 

pilot911

Новичок
Автор оригинала: phprus
pilot911

А зачем? Зачем делать двойную работу, если данные уже есть в СУБД?
какая двойная работа, если страница генерится из данных, взятых из разных таблиц ?
 
pilot911
Поиск по сайту это одно. А поиск по таблице это другое.

з.ы. В вашем примере есть один существенный недочет. Если у нас на сайте, скажем, 10 языков, то при запросе всего одной страницы, мы будем гонять в 10-ть раз больше данных чем нам нужно реально.
Да и неправильно это плодить в БД какие-то внутренние массивы данных - будь то serialize или что-то в этом духе.
 
Сверху