Предложение по структуре базы данных для многоязычия

#php #database-design

#php #база данных-дизайн

Вопрос:

Использование PHP 5.x и MySQL 5.x

Итак, вчера я задал вопрос о наилучшем способе обработки динамических данных в многоязычии, этот вопрос заключается в том, что было бы хорошим решением для структуры базы данных, чтобы справиться с этим. У меня есть записи в базе данных для таких вещей, как stories. Мой план состоит в том, чтобы хранить разные версии истории для каждого языка, доступного в БД. Итак, если сайт поддерживает английский и испанский языки, то в инструменте администрирования они могут добавить английскую версию истории и испанскую версию истории.

Мои мысли по этому поводу заключались в том, чтобы иметь отдельные таблицы в БД, по одной для каждого языка. Итак, одна таблица истории для английской версии, одна для испанского и одна для любых других языков. Затем во внешнем интерфейсе я просто разрешаю посетителю выбрать, на каком языке просматривать сайт, и через переменные узнаю, к какой таблице запросить, чтобы получить эту версию истории. Но одна проблема заключается в том, что, если нет испанской версии, но они выбрали испанский? Это хорошее решение или есть лучший способ сделать это? Ищу предложения.

Ответ №1:

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

Например, история может быть такой

таблица «история»

 id INTEGER (Primary Key)
creation_date DATE_TIME
author VAR_CHAR(32)
..other general columns..
  

таблица «story_localized»

 story_id INTEGER (Foreign Key of story.id) 
lang CHAR(2)                               -- (Indexed, unique -- story_id lang)
content TEXT
..other localized columns..
  

Выполнение запроса — это просто вопрос JOIN объединения двух таблиц :

 SELECT s.*, sl.*
  FROM story s
  JOIN story_localized sl ON s.id = sl.story_id
 WHERE s.id = 1         -- the story you're looking for here
   AND sl.lang = 'en'   -- your language here
   -- other conditions here
  

Такая конфигурация дает несколько преимуществ :

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

** РЕДАКТИРОВАТЬ **

Просто в качестве бонуса, вот «хитрость», позволяющая легко восстановить историю, независимо от языка, на котором она была написана

 SELECT *
  FROM (SELECT * 
          FROM story s
          JOIN story_localized sl ON s.id = sl.story_id
         WHERE s.id = {storyId}
           AND sl.lang = {desiredLanguage}    -- example : 'es'
        UNION
        SELECT * 
          FROM story s
          JOIN story_localized sl ON s.id = sl.story_id
         WHERE s.id = {storyId}
           AND sl.lang = {defaultLanguage}    -- example : 'en'
        UNION
        SELECT * 
          FROM story s
          JOIN story_localized sl ON s.id = sl.story_id
         WHERE s.id = {storyId}
         LIMIT 1                              -- ..get the first language found
) story_l
LIMIT 1              -- only get the first SELECTed row found
  

Попытается извлечь историю на {desiredLanguage} , если история недоступна на этом языке, попробуйте найти ее в {defaultLanguage} (ie. язык сайта по умолчанию), и если по-прежнему ничего не найдено, тогда не имеет значения, на каком языке извлекать статью, поэтому извлекайте первую найденную. Все в одном запросе, и все, что вам нужно, — это 3 аргумента: идентификатор истории, желаемый язык и запасной язык по умолчанию.

Кроме того, вы можете легко узнать, на каком языке доступна история, с помощью простого запроса :

 SELECT sl.lang
  FROM story_localized sl
 WHERE sl.story_id = {storyId}
  

Ответ №2:

Лучший способ сделать это — сохранить историю как многозначный атрибут. Как показал вам @Yanick. И было бы интерфейсно лучше, если бы вы заполнили свой элемент выбора языка только теми языками, на которых доступна эта история.

Ответ №3:

Еще один хороший подход, когда это не длинный текст: названия недель, месяцы… в моем приложении я локализую музыкальные жанры и музыкальные инструменты. Используйте текстовое поле для хранения данных в формате json.

Итак, в моей таблице музыкальных «жанров» есть текстовое поле с именем «lang». На in у меня есть следующая структура json:

 {"es_gl":"MARCHA ESPAÑOLA", "es_EN" : "SPANISH MARCH"}
  

Тогда с помощью PHP действительно легко получить наши данные из структуры json. Допустим, у меня есть genre в моей переменной $ genre.

 $myJSON = json_decode($genre->lang);
echo $myJSON->es_gl // This echoes MARCHA ESPAÑOLA
echo $myJSON->es_es // This echoes SPANISH MARCH
  

Это хорошее решение, когда ваши данные о локализации невелики… нравится посты или блоги.