Comments 35
Как осуществляется синхронизация данных? Структуру и контент каждого сайта надо создавать независимо? Как Вы делаете, чтобы не забыть продублировать, скажем, статью на обоих сайтах — чтобы они оставались «синхронизированны»?
0
а зачем что-то синхронизировать? всё в одной СУБД — это в принципе один сайт; просто система знает откуда брать контент. Со стороны администратора это выглядит вот так
0
UFO just landed and posted this here
вы собственный фреймворк используете?
В таком случае расскажу как у нас:
в конфиге — перечисляю языки и язык по-умолчанию.
В модели (используем MVC), у конкретного поля указываем аттрибут multilanguage = true.
Это значит, что в базе создается несколько полей {#имяполя}_{#язык}
А куда язык прикрутить — для фреймворка без разницы (сессия, урл, поддомен)
Пример?
---app.cfg----
…
# Language settings ##
######################
default_language = en
languages = en,it
…
---model----
…
$this->insert_field(array(
«column» => «title»,
«type» => «varchar»,
«value» => "",
«multilingual» => 1,
));
…
хелпер для шаблона edit для отрисовки поля: {%article_title_input%}. Он содержит подшаблон и печатает «язык: инпут»
Для view шаблона — {%article_title%}. Модель берет значение из языка по-умолчанию.
Статический контент — это переменные шаблона {%str_label_article_title%}.
И файлы-переводчики.
…
news_list = News
recent_news_list = Recent news
filter_by = Filter by
article_text = Text
event_text = Text
special_offer_text = Text
installation_text = Text
en = English
it = Italian
ge = Romanian
hu = Hungarian
…
Немножко сумбурно, но надеюсь, yfgbcпонятно.
В таком случае расскажу как у нас:
в конфиге — перечисляю языки и язык по-умолчанию.
В модели (используем MVC), у конкретного поля указываем аттрибут multilanguage = true.
Это значит, что в базе создается несколько полей {#имяполя}_{#язык}
А куда язык прикрутить — для фреймворка без разницы (сессия, урл, поддомен)
Пример?
---app.cfg----
…
# Language settings ##
######################
default_language = en
languages = en,it
…
---model----
…
$this->insert_field(array(
«column» => «title»,
«type» => «varchar»,
«value» => "",
«multilingual» => 1,
));
…
хелпер для шаблона edit для отрисовки поля: {%article_title_input%}. Он содержит подшаблон и печатает «язык: инпут»
Для view шаблона — {%article_title%}. Модель берет значение из языка по-умолчанию.
Статический контент — это переменные шаблона {%str_label_article_title%}.
И файлы-переводчики.
…
news_list = News
recent_news_list = Recent news
filter_by = Filter by
article_text = Text
event_text = Text
special_offer_text = Text
installation_text = Text
en = English
it = Italian
ge = Romanian
hu = Hungarian
…
Немножко сумбурно, но надеюсь, yfgbcпонятно.
+3
да, у меня свой framework — работает в принципе точно так же :) welcome!
-1
тяжело придумать более удобную систему, не потеряв гибкости ;)
Кстати, симфони, например, предлагает создавать отдельную таблицу с именем {#Modelname}I18n
Мультиязычное поле (в нашем примере это «title») исчезает с основной таблицы и попадает во вновь созданную уже размноженным. Естественно, связь таблиц, позволю себе немножко рельсовости — belongs_to/has_one.
Тоже выход, только непонятно зачем еще одна таблица.
Видел еще вариант, когда все мультиязычные поля содержаться в одной отдельной таблице. А в основной таблице — ссылка на элемент I18n-модели. Не очень удачный вариант, но тоже имеет право на жизнь.
Кстати, симфони, например, предлагает создавать отдельную таблицу с именем {#Modelname}I18n
Мультиязычное поле (в нашем примере это «title») исчезает с основной таблицы и попадает во вновь созданную уже размноженным. Естественно, связь таблиц, позволю себе немножко рельсовости — belongs_to/has_one.
Тоже выход, только непонятно зачем еще одна таблица.
Видел еще вариант, когда все мультиязычные поля содержаться в одной отдельной таблице. А в основной таблице — ссылка на элемент I18n-модели. Не очень удачный вариант, но тоже имеет право на жизнь.
+1
это уже явно перебор, ровно как и 5й уровень нормализации данных в БД. я всегда за идеальное сочетание гибкость/удобство — даже в ущерб «теории» :)
0
хорошая вещь, просто надо писать синхронно… а это не всегда удобно.
Если же нет, то этот вариант ничем не отличается от варианта с «несколькими сайтами», в смысле у каждого языка своя структура
Если же нет, то этот вариант ничем не отличается от варианта с «несколькими сайтами», в смысле у каждого языка своя структура
0
что произошло в моем случае. Предо мной встал вопрос
1) или сохранить структуру, но писать пришлось бы синхронно, а делался сайт с 5 языками
2) или писать каждый язык отдельно, но при этом у каждого языка была своя структура
1) или сохранить структуру, но писать пришлось бы синхронно, а делался сайт с 5 языками
2) или писать каждый язык отдельно, но при этом у каждого языка была своя структура
0
Самый кошерный способ — xml, подгрузка xml-файла с контентом на нужном языке, а структура файла остается неизменной. Тут уже реальное разделение и логики и содержания, никто никому не мешает.
+1
Что будет с такой системой, если структура разделов в разных языковых версиях различается?
0
Многоязычные приложения
PHP и GetText — профессиональная работа: php.russofile.ru/ru/authors/multilangual/php_gettext_prof/
Хранение динамических данных: php.russofile.ru/ru/authors/multilangual/dynamic/
PHP и GetText — профессиональная работа: php.russofile.ru/ru/authors/multilangual/php_gettext_prof/
Хранение динамических данных: php.russofile.ru/ru/authors/multilangual/dynamic/
0
Мне понравилась идея разбивать таблицы, так что одна будет содержать поля, которые не зависят от языка, а другая — текстовые.
> 1 таблица (table1)
> news_id
> news_start
> news_stop
> news_visible
> 2 таблица (table2)
> news_id – уникальный номер новости из первой таблицы
> news_lang – уникальный двухбуквенный идентификатор языковых данных
> news_subject – тема (заголовок) новости
> news_short – короткая новость на языке с кодом из news_lang
> news_full – полная новость на языке с кодом из news_lang
В своей статье ты определил, что текстовый контент новости уникален для каждого языка. Т.е. между языками он не пересекается. Поэтому чутье подсказывает, что нужно создавать table2_ru, table2_en и т.д. — индексы меньше, поиск быстрее. Но ты предлагаешь переводы хранить в одной таблице. Каков в этом практический смысл?
> 1 таблица (table1)
> news_id
> news_start
> news_stop
> news_visible
> 2 таблица (table2)
> news_id – уникальный номер новости из первой таблицы
> news_lang – уникальный двухбуквенный идентификатор языковых данных
> news_subject – тема (заголовок) новости
> news_short – короткая новость на языке с кодом из news_lang
> news_full – полная новость на языке с кодом из news_lang
В своей статье ты определил, что текстовый контент новости уникален для каждого языка. Т.е. между языками он не пересекается. Поэтому чутье подсказывает, что нужно создавать table2_ru, table2_en и т.д. — индексы меньше, поиск быстрее. Но ты предлагаешь переводы хранить в одной таблице. Каков в этом практический смысл?
+1
я предлагаю так:
system_languages:lang,name (en-English,ru-Русский,de-Deutsch) -->
news:news_id,created,published,publisher,url,foo,bar
news_content:news_id,lang,subject,teaser,content
И тут у меня появляется гибгость как при поиске так и при отдаче данных, например отдавать контент на языке А если его нет на языке Б :) идея понятна?
system_languages:lang,name (en-English,ru-Русский,de-Deutsch) -->
news:news_id,created,published,publisher,url,foo,bar
news_content:news_id,lang,subject,teaser,content
И тут у меня появляется гибгость как при поиске так и при отдаче данных, например отдавать контент на языке А если его нет на языке Б :) идея понятна?
0
почти то же самое написал :)) относительно поиска — индексирование это отдельная тема и да, в индексе я бы тоже указывал из какого языка оно создавалось
0
А из базы контент выгребается сразу на двух языках: языке юзера и языке по умолчанию? Т.е. так:
SELECT *
FROM news N
INNER JOIN news_contents NC ON N.news_id = NC.news_id
WHERE NC.news_lang IN (?clientUILang, ?defaultLang)
SELECT *
FROM news N
INNER JOIN news_contents NC ON N.news_id = NC.news_id
WHERE NC.news_lang IN (?clientUILang, ?defaultLang)
0
Смысл в том, что считать большим объёмом данных. Экономить на спичках создавая себе геморрой не стоит. к тому же ты усложняешь в разы выборки своей идее, от чего я и предлагал избавиться.
0
я действительно не понял, поэтому прошу привести пример таких выборок.
0
Ну как вы например собирайетесь джойнить сразу две языковые таблицы? Вам не кажется что это будет сильнее напрягать сервер нежели одно но чуть большая таблица?
0
Вы упорно не приводите примеров и я продолжаю непонимать. ㋡
Возможно вот где проблема. Для выборки мультиязычных данных может применяться еще одно правило: «отдавать контент на языке Ⓐ, а если его нет, — на языке оригинала», где язык оригинала это тот, на котором была изначально написана контентина. Тогда версии на всех остальных языках это переводы. А перевод уже _зависят_ от оригинального текста. Наличие такой зависимости влияет на структуру БД.
Для реализации этой идеи на основе Вашего примера, в таблицу news нужно добавить поле news_orig_lang (язык, на котором была изначально написана новость).
news:
news_id, news_orig_lang, news_start, …
news_content:
news_id, news_lang, news_subject, …
Тогда запрос вида: вытащить «перевод» и оригинал будет выглядить так:
SELECT * news_id N
INNER JOIN news_contents NC ON N.news_id = NC.news_id AND NC.lang = N.news_orig_lang
LEFT JOIN news_contents NCtr ON N.news_id = NCtr.news_id AND NCtr.lang = ?userUILang
т.е. через INNER JOIN цепляется язык оригинала, а через LEFT JOIN — перевод.
Возможно вот где проблема. Для выборки мультиязычных данных может применяться еще одно правило: «отдавать контент на языке Ⓐ, а если его нет, — на языке оригинала», где язык оригинала это тот, на котором была изначально написана контентина. Тогда версии на всех остальных языках это переводы. А перевод уже _зависят_ от оригинального текста. Наличие такой зависимости влияет на структуру БД.
Для реализации этой идеи на основе Вашего примера, в таблицу news нужно добавить поле news_orig_lang (язык, на котором была изначально написана новость).
news:
news_id, news_orig_lang, news_start, …
news_content:
news_id, news_lang, news_subject, …
Тогда запрос вида: вытащить «перевод» и оригинал будет выглядить так:
SELECT * news_id N
INNER JOIN news_contents NC ON N.news_id = NC.news_id AND NC.lang = N.news_orig_lang
LEFT JOIN news_contents NCtr ON N.news_id = NCtr.news_id AND NCtr.lang = ?userUILang
т.е. через INNER JOIN цепляется язык оригинала, а через LEFT JOIN — перевод.
+1
Именно так мы в нашем проекте и делали.
Только «news_orig_lang» одинаков для всего проекта (ну IRL так обычно и бывает), в нашем случае это был английский. Его мы сразу задаем мускульной константой SET LANG = 'en'
Отдельный минус — вагон и маленькая тележка ифов внутри селекта, то б получить только переведенные данные.
Иначе говоря, описанная вами структура имела бы вид:
SELECT
IF (nc.news_subject != '', nc.news_subject, nc_en.news_subject),
…
FROM news n
JOIN news_content nc_en ON nc_en.news_id=n.news_id AND nc_en.lang=@LANG_ID
LEFT JOIN news_content nc ON nc.news_id=n.news_id AND nc.lang=?userUILang
Запросы получаются довольно большие, но работает все это весьма шустро.
Только «news_orig_lang» одинаков для всего проекта (ну IRL так обычно и бывает), в нашем случае это был английский. Его мы сразу задаем мускульной константой SET LANG = 'en'
Отдельный минус — вагон и маленькая тележка ифов внутри селекта, то б получить только переведенные данные.
Иначе говоря, описанная вами структура имела бы вид:
SELECT
IF (nc.news_subject != '', nc.news_subject, nc_en.news_subject),
…
FROM news n
JOIN news_content nc_en ON nc_en.news_id=n.news_id AND nc_en.lang=@LANG_ID
LEFT JOIN news_content nc ON nc.news_id=n.news_id AND nc.lang=?userUILang
Запросы получаются довольно большие, но работает все это весьма шустро.
0
Зачем придумывать такой велосипед жестокий, да еще и в запросе делать кучу ифов? Когда можно запросить сразу две записи — дефолтную и на нужном языке? И тупо отфильтровать по null?
0
Все примеры есть в статье, каких еще вы от меня примеров хотите?
Не надо туда ничего добавлять — прочитайте уже внимательно статью.
Не надо туда ничего добавлять — прочитайте уже внимательно статью.
0
кстати, можно задать еще один вопрос про статью? ;)
в части «Общий контент» Вы предложили формат и набор процедур для сохранения мультиязычных данных в общем поле БД. Почему не используете стандартные serialize()/unserialize()? На первый взгляд это было бы проще.
в части «Общий контент» Вы предложили формат и набор процедур для сохранения мультиязычных данных в общем поле БД. Почему не используете стандартные serialize()/unserialize()? На первый взгляд это было бы проще.
0
Принцип работы таков:
Преимущества такого подхода:
— Каждая языковая версия может кардинально отличаться по структуре. Пример: Компания — официальный дилер фирм на территории Украины, которые имеют свои представительства в России, Польше, Беларуси и т.п. Кроме того, Компания — производитель продукции, которой интересуются не только жители Украины, но и зарубежья. Соответственно для сайта на укр. языке нужно показывать весь каталог товаров (дилерские в т.ч.). На сайте в зоне .ru, который рассчитан на Россию, нужно продвигать только собственную продукцию, потому как дилерская не интересна. Сайт на английском языке — сайт, скажем для инвесторов, который должен быть только с общей информацией о Компании, чтобы дать возможность ознакомиться с производственными мощностями.
— Не будет «многоязычности» на локализированом сайте: когда весь сайт на русском, а некоторые товары либо блоки на английском, потому что не дописаны.
— Возможность четко распределить обязанности по поддержке каждой языковой версии сайта на отдельных людей в Компании.
— Если поломают структуру на одной версии — на другой все будет в порядке.
Минусы подхода:
— Если сайты не сильно различаются на разных версиях — производится дублирование контента (картинки для товаров загружаются по нескольку раз)
— Добавить еще один язык не сможет Компания сама — необходимо участие разработчика.
Может еще какие-то минусы видите? Прошу комментировать.
- — каждый язык на отдельном домене, например: site.ru, site.ua, site.com
- — движок у всех сайтов один — все лежит в одном DOCUMENT_ROOT (все домены — алиасы для основного)
- — по домену определяем язык
- — для выбранного языка используем свой локализированный конфиг
- — подгружаем свои CSS (если, скажем, есть заголовки-картинки с текстом)
- — подключаемся к БД и пользуем таблицы с префиксом языка ru_, en_ ua_, либо вообще к другой БД
- — включаем свой google analytics
- — ЧПУ для каждого сайта можно делать свой, так как структура сайта и контент независимы у каждой версии
- — Все картинки лежат в том же DOCUMENT_ROOT
Преимущества такого подхода:
— Каждая языковая версия может кардинально отличаться по структуре. Пример: Компания — официальный дилер фирм на территории Украины, которые имеют свои представительства в России, Польше, Беларуси и т.п. Кроме того, Компания — производитель продукции, которой интересуются не только жители Украины, но и зарубежья. Соответственно для сайта на укр. языке нужно показывать весь каталог товаров (дилерские в т.ч.). На сайте в зоне .ru, который рассчитан на Россию, нужно продвигать только собственную продукцию, потому как дилерская не интересна. Сайт на английском языке — сайт, скажем для инвесторов, который должен быть только с общей информацией о Компании, чтобы дать возможность ознакомиться с производственными мощностями.
— Не будет «многоязычности» на локализированом сайте: когда весь сайт на русском, а некоторые товары либо блоки на английском, потому что не дописаны.
— Возможность четко распределить обязанности по поддержке каждой языковой версии сайта на отдельных людей в Компании.
— Если поломают структуру на одной версии — на другой все будет в порядке.
Минусы подхода:
— Если сайты не сильно различаются на разных версиях — производится дублирование контента (картинки для товаров загружаются по нескольку раз)
— Добавить еще один язык не сможет Компания сама — необходимо участие разработчика.
Может еще какие-то минусы видите? Прошу комментировать.
+1
Sign up to leave a comment.
Мультиязычность