x
 
Олег Истомин
28 февраля 2013

Конечно, к вёрстке вопрос относится косвенно, но всё же: как вы храните данные для многоязычных сайтов?

Существует масса подходов:

  • когда переводы выносятся в отдельную табличку с id, owner_key, lang_id, string, text, где owner_key — сгенерированный ключ (например, MD5) для связи основной таблицы с таблицей переводов;
  • когда для каждой таблицы делается отдельная таблица с переводами и owner_key — это id основной таблицы;
  • когда таблица переводов имеет вид id, ru, en, de, …;
  • или тупо все поля в основной таблице дополняются полями переводов.

Сам пользуюсь вариантом id, ru, en, de, потому что большинство многоязычных сайтов редко переводятся больше чем на 5 языков, а если и переводятся, то информации на них немного. Но даже в этом варианте неудобно писать запросы, например, для удаления строк, когда нужно удалять все зависимые переводы. Случаи со склонениями по падежам в интерфейсе настолько редки, что можно обрабатывать их отдельно. Подумываю перейти на вариант «тупо писать все переводы в основной таблице», но хотел бы спросить вашего совета.



Олег!

Мне кажется, если избавиться от понятия «перевод», то всё встанет на свои места. У многоязычных сайтов нет основной локализации, значит, все они равноправны. А если они равноправны, то не существует никакой «таблицы переводов». Вместо неё есть таблица с текстом.

Таблица с текстом имеет идентификатор объекта на сайте (siteObjectId), к которому привязаны: кнопка, пункт меню, текст «О компании» и идентификатор языка (languageId): ru, en, de. Это позволит держать все фрагменты текста в одном месте, не размазывая по базе данных.

При такой структуре нужный фрагмент текста легко выбрать:


SELECT `text` FROM `locale` WHERE `siteObjectId` = 'text_aboutCompany' 
  AND `languageId` = 'ru';

Или удалить всю группу:


DELETE `text` FROM `locale` WHERE `siteObjectId` = 'text_aboutCompany';

Когда мы проработали структуру и убедились, что все нужные действия выполняются прозрачно, оптимизируем. Например, совершенно понятно, что можно сгруппировать фрагменты текста по страницам. Но мы не можем просто добавить pageId в нашу таблицу, потому что один и тот же текст может использоваться на нескольких страницах. Поэтому создаём ещё одну таблицу с полями pageId и siteObjectId и заполняем её связями между текстом и страницами.

Теперь выборка всех русских фрагментов текста для страницы «О компании» выглядит так:


SELECT `text` FROM `locale` JOIN `link_page_locale`
  ON `link_page_locale`.`siteObjectId` = `locale`.`siteObjectId` 
  WHERE `link_page_locale`.`pageId` = 'page_aboutCompany'
  AND `languageId` = 'ru';

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

P. S.
Это был совет о разработке веб-интерфейсов. Хотите узнать всё об умной вёрстке, правильных скриптах, грациозной деградации, трюках и работе технолога с дизайнером? Присылайте вопросы.

Поделиться
Отправить

Комментарии

Андрей Ситник
28 февраля 2013

Вообще, не очень понятно, зачем это хранить в базе данных. Есть очень старый формат gettext, есть новый и удобный YAML.

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

Артём Рокет
28 февраля 2013

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

Но если задуматься об оптимизации? Что если нам необходимо вывести на странице, скажем, пятьдесят позиций каталога с их описаниями? Это либо очень много запросов в цикле, либо многоэтажный where, либо запрос по айди страницы, полученные данные которого еще нужно будет правильно распределить по сущностям уже средствами языка.

К тому же хранение связей текстовых констант и страниц в перспективе грозит проблемами с инвалидацией.

Олег Истомин
28 февраля 2013

Спасибо! Похоже на первый способ, но то что к идентификатору привязаны и кнопка и меню, большой плюс. Сразу упрощается работа с зависимостями. Остаётся лишь определить, кто главный по идентификаторам или, другими словами, удалять текст при удалении кнопки или кнопку при удалении текста.


Цель рубрики — обсуждение вопросов дизайна всех видов, текста в дизайне и взаимоотношений дизайнеров с клиентами.

Мы публикуем комментарии, которые добавляют к уже сказанному новые мысли и хорошие примеры. Мы ожидаем, что такие комментарии составят около 20% от общего числа.

Решение о публикации принимается один раз; мы не имеем возможности комментировать или пересматривать свое решение, хотя оно может быть ошибочно. Уже опубликованные комментарии могут быть удалены через некоторое время, если без них обсуждение не становится менее ценным или интересным.

Вот такой веб 2.0.

Сайты для слабовидящих 2 За какими вещами нужно следить, чтобы при загрузке страница выглядела прилично? 1 С чего начать изучение ЦСС? 1 Как сделать, чтобы блок при прокрутке залипал у верхней границы окна браузера? 5




Недавно всплыло

Все уже успели заметить, что вы почти во всех пятничных примерах советуете немного поунижаться 12 Почему дизайнер должен уметь писать текст? 8 Выбранные элементы списка, как не забывать принципы из советов бюро и когда нужен логотип 1 Почему в переписке нельзя использовать «Доброго времени суток»? 2