Каким способом заложить многоязычность в движок?

WMix

герр M:)ller
Партнер клуба
А зачем ей это знать и зачем с нее поиск делать?
я боюсь моменты, когда я не умею считать или когда простой подсчет занимает много времени...
не знаю по каким причинам (назовем безолаберностью, сбоем .... ), но сложилось так, что в переводе остался и собирается мусор... как его выловить? - бегать по всем табличкам, сравнивать, делать пометки... мне не удобно...

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

но я не настаиваю...

id языка его iso-код
я так и сделал бы, если языков не много, можно даже ENUM встроить, работать будет на ура!
 

Silentland

Новичок
Ну так в моем случае все перводы в одной табличке
translate
id
lang
varchar
text

Все как на ладони
 

Silentland

Новичок
Возникла проблема.
Если хранить переводы в виде id, lang_id, text вместо id, text_ru, text_en, ...

Как в первом случае ссылаться на таблицу с переводами? Т.е., если у нас есть таблица
articles
id, text_id

Что писать в text_id? Ведь в первом случае айдишников для одной статьи в таблице переводов будет несколько?
 

WMix

герр M:)ller
Партнер клуба
у всех переводов будет одинаковый text_id!
 

Silentland

Новичок
Значит он будет не уникальным. И табличку с переводами будет такой:
translates
id, text_id, lang_id, text

И откуда тогда взять этот text_id? Ведь id-то просто инкрементировался

И как тогда написать элементарные запросы:
1. выборки записей из articles для user_id = 1 и lang = 'ru'
2. вставки записи в articles для user_id = 1 и lang = 'ru'
3. обновления записи в articles для user_id = 1 и lang = 'ru'
 

fixxxer

К.О.
Партнер клуба
а зачем id?

primary key (text_id, lang_id)

касаемо инкремента - в нормальных СУБД есть понятие sequence, в mysql его можно легко изобразить.

что такое user_id и откуда он тут взялся?
 

WMix

герр M:)ller
Партнер клуба
уникальность поля это язык+text_id если хочешь добавь еще один столбик c индификатором строчки...
откуда брать? это то что тебе придется решить, если ты выбрал данную структуру...
при вводе нового слова пользуйся max(text_id)+1 при переводе, селект на существующий...
конечно можно сделать также промежуточную табличку... стандарта нет, пологайся на здравый смысл и на поставленную задачу
 

Silentland

Новичок
Забыл...
articles
id, user_id, text_id

Тоже на ум пришло что-то типа sequence... В некоторых движках вмето этого используют md5. Но как-то слишком муторно...
Подумываю перейти на первый вариант
translates
id, text_ru, text_en, ...

Для таблички перевод в пару тысяч строк, наверное, приемлемо...
 

WMix

герр M:)ller
Партнер клуба
главное ты понимаешь преимущества и недостатки... с одной стороны простота с другой стороны повтор...
 

Silentland

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

Ну а первый запрос каким-то таким будет:
SELECT articles.id, translates.text_ru
FROM articles, translates
WHERE translates.id=articles.text_id
AND articles.user_id=1

В запросах плаваю, правда
 

Silentland

Новичок
А как сделать запрос на добавление/обновление/удаление?
UPDATE articles, translates
SET articles.text_id=?, translates.text_ru = 'текст'
WHERE articles.id = 123);

Чтобы, если существует articles.text_id, то обновлялся бы перевод в соответствующей строке translates.text_ru
А если не существует, то в translates создавалась бы новая строка и ее id присваивался бы в articles.text_id

ну и удаление аналогично...
 

Silentland

Новичок
С чем-то разобрался, но с чем-то полный затык, помогайте!

1. В запрос delete для таблицы articles динамически подставляется список полей text1_id, text2_id, text3_id, ... с ссылками на строки таблицы translates. При удалении поля из articles должны удалиться все поля из translates на которые есть ссылки
Так же удаляемая строка из articles может быть чьим-то родителем и нужно рекурсивно удалить всех потомков у которых она в parent_id по тому же алгоритму с удалением всех переводов из translates для каждого

2. При выборке строк из таблицы articles, значения полей text1_id, text2_id, text3_id, ... должны заменяться группировкой соответствующих значений из translates. Как это сделать?
 

WMix

герр M:)ller
Партнер клуба
затыка не вижу, как сказал, так и нужно писать,..
select... подчистил хвосты, delete
 

Тугай

Новичок
Для всех интерфейсных вещей, меню, заголовки, кнопки, ссылки, и т.п.
обычно применяется вариант translations (translation_id, lang_id, value), который предложил fixxxer.

То что разделять новостии и статьи что-то не то, я с этим согласен.
Нужно просто еще одна абстракция, типа
таблица post(post_id, lang_id, post_type, title, user, conetent, ....), где post_type это (news, article, ...).

Добавление новости и статьи практически оно и тоже. Можно конечно дальше нормализовать базу и если у новостей и статей разные поля,
то для них сделать еще post_news(поля которые только у новостей) и post_article(поля которые только у статей). Это вариант Breeze, но только не четыре таблицы, а три или вообще одна.
 

Breeze

goshogun
Команда форума
Партнер клуба
В моем варианте вообще-то никогда не было четырех таблиц.
 

Тугай

Новичок
Прошу прощения. Breeze действительно предложил сразу верное на мой взгляд решение, что соответствует моему post и post_article.
 

Silentland

Новичок
Что за верное решение? Я делаю по-сути так так же как предложено, только храню переводы не в (translation_id, lang_id, value),а (translation_id, ru_val,en_val, de_val, ...), что позволяет избежать проблемы с генерацией дополнительного ключа типа table_which_has_translates_fields_id или создания отдельной таблицы переводов для каждой таблицы сданными. Т.к. языков ограниченное количество... 200 штук, можно даже сразу в translations вбить все. В запросах разница будет только куда подставлять список языков для вывода, в where или во from (как сейчас).

Где у меня написано, что новости и статьи по-разному добавляются? Что касается меню, то там пока два типа: статьи и товары.

затыка не вижу, как сказал, так и нужно писать,..
select... подчистил хвосты, delete
Конечно могу накрутить на одну операцию удаления три запроса в PHP-шной рекурсии, но так же совсем не правильно. Многоязычность используется повсеместно и уж цепочку выборки/удаления сущности и всех ее переводов нужно организовать в один запрос, независящий от кол-ва полей с айдишниками переводов. Ну и операции поиска и удаления всех осиротевших строк тоже надо бы в запросе делать, хотя если тут никто не знает как, то уж и мне точно придется перекладывать все это на плечи ПХП
 

Тугай

Новичок
Что за верное решение?
Мне не нравится вариант, когда
article(id, user_id, title_transvarchar_id, intro_transtext_id, text_transtext_id)
в статье нет фактически данных, а все преводится через
(translation_id, ru_val,en_val, de_val, ...)

title_transvarchar_id, intro_transtext_id, text_transtext_id - хорошо что три поля,
а если 20 будет? Это 20 join или делать 20 select.
Некак сделать полнотекстный поиск. Как искть на нескольких языках?, и т.д.

Усложнение структуры article, приносит много проблем.


Имхо, (translation_id, ru_val,en_val, de_val, ...) - только для элементов интерфейса
и тогда самостоятельно поле lang естественно.


Так как тут
article
id, pid, lang, title, text
pid указывает на оригинал статьи
выбрать все статьи
select * from article where lang="ru"
переводы
select id,lang from article where id=$pid or pid=$pid or pid=$id
лучше.

И запросов на самом деле будет меньше и они более прозрачные и усложнение структуры article не создает проблем.

Все это имхо, решение за тобой :)
 

Silentland

Новичок
Это способ где каждой табличке соответствует своя табличка с переводами. У меня-то как раз в основном интерфейс нуждается в переводе и пришлось бы почти к каждой табличке в БД создавать дубликат. А что с поиском не так? Допустим, мне надо искать в русском поле text таблицы articles, я пишу
PHP:
SELECT articles.id FROM articles INNER JOIN translates ON articles.text = translates.id WHERE translates.ru = 'поисковая фраза'
Обновление тоже одним джойном
PHP:
UPDATE translates FROM articles INNER JOIN translates ON articles.text = translates.id SET translates.ru = 'русский текст' AND translates.en = 'английский текст' AND ... WHERE articles.id = '123';
С удалением, кстати, тоже разобрался. Приведу пример для меню:
PHP:
DELETE menu, translates FROM menu LEFT JOIN translates ON menu.name = translates.id WHERE menu.id = '113'
Остался вопрос, как зациклить этот запрос, чтобы он нашел всех потомков удаляемой строки menu (с parent_id = '113'), удалил бы все их переводы, потом нашел потомков их потомков и т.д. В mySQL есть же рекурсивные процедуры или как-то там это можно сделать?
 
Сверху