многоязычность - будь она не ладна :)

phpdev2007

Новичок
многоязычность - будь она не ладна :)

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

Вот подход который определен сейчас:
1) интерфейс переводится через gettext
2) все части системы которым также нужна многоязычность, но данные для перевода
содержатся в базе данных, используют отдельную таблицу для переводов, где содержится id записи id языка и значения перевода.

Вопрос возможно есть, более гибкий подход, или может подскажите как луче организовать.
 

phpdev2007

Новичок
2) Каждая часть, имеет отдельную таблицу языковую.

Просто хотелось услышать опыт других, не изобретать велосипед.
 

Апокалипсис

тех дир matras.ru
посмотри как устроено в WordPresse многоязыковая поддержка.
Мне нравится такое решение:)
 

phpdev2007

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

AmdY

Пью пиво
Команда форума
а как насчёт "SELECT IF(title_$lang !='', title_$lang, title) AS title FROM table_name", думаю это вполне нормальный вариант
 

phpdev2007

Новичок
PHP:
-- phpMyAdmin SQL Dump
-- version 2.6.4-pl4
-- http://www.phpmyadmin.net
-- 
-- Хост: localhost
-- Время создания: Дек 20 2007 г., 15:48
-- Версия сервера: 4.1.20
-- Версия PHP: 5.2.0
-- 
-- БД: `phpclub`
-- 

-- --------------------------------------------------------

-- 
-- Структура таблицы `menu`
-- 

CREATE TABLE `menu` (
  `id` int(10) NOT NULL auto_increment,
  `path` varchar(50) NOT NULL default '',
  `url` varchar(255) NOT NULL default '',
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='не содержит языковых данных' AUTO_INCREMENT=3 ;

-- 
-- Дамп данных таблицы `menu`
-- 

INSERT INTO `menu` VALUES (1, '01', '/');
INSERT INTO `menu` VALUES (2, '01/01', '/about/');

-- --------------------------------------------------------

-- 
-- Структура таблицы `menu_lang`
-- 

CREATE TABLE `menu_lang` (
  `id` int(10) NOT NULL auto_increment,
  `idmenu` int(10) NOT NULL default '0',
  `lang` varchar(2) NOT NULL default '',
  `title` varchar(255) NOT NULL default '',
  `name` varchar(255) NOT NULL default '',
  PRIMARY KEY  (`id`),
  UNIQUE KEY `idmenu` (`idmenu`,`lang`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ;

-- 
-- Дамп данных таблицы `menu_lang`
-- 

INSERT INTO `menu_lang` VALUES (1, 1, 'ru', 'На главную страницу', 'Главная');
INSERT INTO `menu_lang` VALUES (2, 2, 'ru', 'О компании', 'О команиии');
INSERT INTO `menu_lang` VALUES (3, 1, 'en', 'home', 'Home');
INSERT INTO `menu_lang` VALUES (4, 2, 'en', 'About', 'About');
Для примера две таблицы, которые содержат навигацию, и языковые данные.
На первый взгляд все просто, есть указатель языка, есть указатель к какому пункту он принадлежит, но есть и проблемы:
1) Если нет нужного перевода, стоновится проблематично вывести запись на языке по умолнчанию в системе.
2) Постоянный повтор кода, допустим так реализовали для меню в системе, точно также прийдется делать для системы статей, и так дальше.

-~{}~ 20.12.07 16:55:

Апокалипсис
А как она реализована можете описать?
 

phpdev2007

Новичок
crocodile2u
так то она так, но ведь при выборке данных с базы
удобно получать массив:
PHP:
Array
(
    [0] => Array
        (
            [name] => Главная
            [title] => На главную
            [url] => /
            [id] => 1
        )

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

p/s
Хотя может это и утопия искать универсальный механизм, для многоязычности....
 

Alexandre

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

Вопрос выборки решается с помощью LEFT JOIN

-~{}~ 20.12.07 20:08:

Код:
Array 
( 
____[0]_=>_Array 
________( 
____________[name]_=>_Главная 
____________[title]_=>_На_главную 
____________[url]_=>_/ 
____________[id]_=>_1 
            [lang_id] => 1 
________) 
 
    [0] => Array 
        ( 
            [name] => Home
            [title] => go to home
            [url] => / 
            [id] => 1 
            [lang_id] => 2 
        ) 
)
используем lang_id=2 если нет такой записи, используем lang_id=1
 

phpdev2007

Новичок
Alexandre
а насколько будет оптимальный такой запрос если надо выводить динамически карту сайта?
можно пример запроса?
И все равно нам прийдется проходить в цикле полученный результат, чтоб получить нужный массив.
Это все ресурсы и время.
Мысль такая например у нас в системе по умолчанию русский, и есть китайский, естественно русский китайцам пофигу, - хотя не всегда :). Потому думаю логично: просто не выводить ту информацию которая не переведена на китайский пользователю - китайцу.
 

Alexandre

PHPПенсионер
а насколько будет оптимальный такой запрос если надо выводить динамически карту сайта?
карта сайта делается один раз и сохраняется в кеше, чтоб не дергать БД каждый раз.
Это все ресурсы и время
используй другие методы...
Потому думаю логично: просто не выводить ту информацию которая не переведена на китайский пользователю - китайцу.
это определяется ТЗ или требованиями Заказчика... что делать с этой информацией. Если не выводить, то делаем простой JOIN, если выводить по умолчанию рус (eng), в случае отсутствия - то делаем LEFT JOIN.

вообще, при проооектировании одного портала, я использовал следующий прием:
все языковые данные хранятся в XML,
мной составляется русский XML, который я отдаю на перевод.
далее делается разовое XSLT преобразование, которое формирует код:
Код:
$lang[1] = array( 
            ['home'] => 'Home',
            ['title'] => 'go to home',
            ['author'] =>  'author',
            . . .
        );
ну а далее сам знаешь... пишется класс $lang = new Lang();
$word = $lang->translate('title');
в случае если отсутствует, то берется из базового массива.
 

phpdev2007

Новичок
Alexandre
Спасибо за ответ, действительно разложили все по полкам.
Вопрос в следующем, мне хотелось просто создать универсальный механизм который бы решал вопросы перевода любой части проекта.
Проблем с переводом интерфейса нет так как есть gettext. Проблема с переводом меню, и например модуля статьи, все верно удобно для таких частей как меню использовать приведенную вами схему, и таким методом унифицировать переводы.

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

becool

Новичок
Учитывая географическое положение, кроме как мультиязычных, других сайтов вообще не делаем-с и самый удобный, а главное шустрый вариант оказался таким.
все тексты сразу в трёх языках хранятся в таблице:
id, RU, EN, DE, LV, author и так далее.
Нужно знать текущий язык и выбирать данные с тем полем, что соответствуют языку например SELECT `RU` as `text`, ....
всякие там title и прочее хранить в поле с текстом например через разделитель.
Под такое дело написали отличную cms. Дико удобно и быстро переводить. Языков может быть хоть 163
 

Alexandre

PHPПенсионер
Но приемлемо ли использовать ее для больших частей которые требуют перевода, например теже статьи ведь их размер может быть очень большим
ну ты загнул, статьи.... Ни одна, из существующих систем не использует просто тупую замену слов... это целая наука - перевести статью... а посему, перевод статьи - ложится в БД и отдается как "контентная" страница. page_id (или content_id) у страниц на рус и чина - должны быть одинаковыми... если на "родном" языке статьи нет, то она не выкладывается на "дефолтном" языке...
где-то в цмске должно быть соответствие контента (одного и второго языков)

Все что я описывал - это исключительно для интерфейсов.

-~{}~ 21.12.07 23:18:

Языков может быть хоть 163
и полей тоже 163...
ну ты даешь... а тогда зачем же придумали реляционность?

PS. Один "изобретатель" придумал таблицу с 1000 полями, в результате чего БД на "небольшой" нагрузке просто умирала... Из них, использовалось максимум - только 5-7% полей. В результате таких выкрутасов этого студента, пришлось переписывать весь проект ;)

100 раз подумай, прежде, чем предлагать такие вот решения.
 

becool

Новичок
я не предлагаю 163 языка =) С таким масштабом реляционность тоже мало поможет.
Тебе нужно отсилы 2 языка. Дополнительное поле самое простое и правельное решение. Нежели создавать доп таблицу с переводами и значениями id к нужным элементам. Потеряешь пару связок, будешь так же парится и востанавливать.
к тому же ты не будешь использовать 5-7% полей. Попробуй пересчитать если это важно ;)
 

dimagolov

Новичок
becool
пойми, СУБД ВСЕГДА читает строку полностью. Если у тебя 3 языка, то минммум 60% трафика СУБД с винта впустую. Если 4 - то уже 75% и т.д. На 10 языках будет 90% и это на запросах, которые вызываются постоянно, для генерации любых эдементов интерфейса. Даже при 2-х языках удвоение нагрузки не выглядит чем-то особо привлекательным.
 
Сверху