Как лучше всего обрабатывать I18N в таблицах поиска?

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

Например, для таблицы поиска страны пользователь из США должен видеть английские названия стран, а немец должен видеть немецкие названия. Но все же их идентификаторы должны быть одинаковыми.

Я могу думать о следующем:

  • Добавьте разные таблицы поиска для каждого языка
  • Используйте единую таблицу поиска с несколькими записями для одной и той же страны, помеченной в соответствии с ее языком.
  • Избавьтесь от всех таблиц поиска и выполняйте все поиски по программному коду.
  • [Любая другая идея, о которой я не подумал?]

person Daniel Rikowski    schedule 01.09.2009    source источник


Ответы (6)


Большой вопрос здесь в том, могут ли конечные пользователи изменять переводы?

Если ответ «НЕТ», наборы ресурсов проще и быстрее использовать, чем таблицы. Вместо фактического текста ваши таблицы будут содержать ключ ресурса (или вы можете использовать первичный ключ для этой цели, если он текстовый, а не числовой), а соответствующий пакет ресурсов будет содержать перевод.

Если ответ «ДА», вы должны хранить переводы в базе данных. Однако я обнаружил, что самый простой подход в этом сценарии - имитировать вышеуказанную функциональность пакета ресурсов в базе данных, например. иметь единую таблицу со столбцами «язык», «ключ ресурса», «значение ресурса», которые все другие таблицы будут использовать для поиска фактического локализованного текста.

person ChssPly76    schedule 01.09.2009

Отдельная презентация от программирования. Внутренне используйте идентификаторы для всего; при представлении пользователям представляйте локализованные данные.

person Paul Sonier    schedule 01.09.2009

Однажды я сделал многоязычное приложение. Все должно было быть многоязычным, включая вводимый пользователями контент, а также должно было быть легко сделать перевод этого контента.

Теперь, если это только для статического текста, наиболее рекомендуемые XML-файлы ресурсов делают это. Я считаю, что это хорошо поддерживается платформой .NET.

Если он должен быть динамическим, то я сделал структуру таблицы

Таблица ResourceStrings resourceId GUId PK CultureCode String PK text String

Затем это позволило мне выполнить каскадное чтение кода культуры. Так что, если бы у кого-то был культурный код en-us, я мог бы сделать запрос, где я сделал

SELECT FROM ResourceStrings
WHERE resourceId = <AND ID> AND cultureCode IS IN ('en','en-us')
ORDER BY cultureCode DESC

Таким образом, самый длинный код культуры вернется первым и будет наиболее конкретным. Теперь я бы рекомендовал это ТОЛЬКО, если вы разрешаете пользователям вводить текст и переводить его. Мне это было нужно, потому что контент должен был быть многоязычным, как и само приложение.

person Zoidberg    schedule 01.09.2009

В моем текущем проекте (пользовательская CMS, написанная на django) наше решение для моделей I18N основано на этом фрагменте примера: http://www.djangosnippets.org/snippets/855/, который я расширил, чтобы его было удобнее использовать в шаблонах, и интегрировал в административный интерфейс.

По сути, у каждого типа контента есть две таблицы: одна с общими полями (например, категория статей) и одна с переводимым контентом (заголовок, тело, слаг — уникальная метка, используемая в URL-адресе — и т. д.). Очевидно, что между общей моделью и моделью перевода существует отношение «один ко многим». Вот пример, который приводит автор:

class Article(models.Model):
    author = models.CharField(max_length = 40)

class ArticleI18N(I18NModel):
    title = models.CharField(max_length = 120)
    body = models.TextField()

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

Но самое сложное — оставаться СУХИМ в коде, иначе каждый раз, когда вам нужно обрабатывать переводимый контент, вы будете сталкиваться с кучей шаблонов. К счастью, гибкость Python очень помогла.

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

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

  • 1) используйте дополнительные столбцы для каждого переводимого столбца и каждого языка: title_en, title_fr, title_de, content_en, content_fr, content_de, ...
  • 2) сериализовать несколько языков в один столбец.
    Например: title = "|EN|Welcome|FR|Bienvenue|DE|Willkommen"
    Мне это особенно не нравится, но что здесь действительно важно заключается в том, хорошо ли он интегрируется в существующую среду, что имело место.
  • 3) Иногда связь между одним и тем же контентом на разных языках не должна быть строгой. Я думаю, что это случай статей в Википедии - переводы - это просто гиперссылки, установленные авторами вручную. Как следствие, эти ссылки менее уязвимы для программного обеспечения, но здесь важно, чтобы пользователь мог их просматривать.
person vincent    schedule 01.09.2009

Вот способ сделать это на уровне базы данных.

Когда мне нужно было это сделать, я разбил каждую таблицу кодов на две таблицы. Один содержал культурно-инвариантные данные: внутренний идентификатор кода, конечно, сам код, если код был культурно-инвариантным, и, возможно, другие столбцы (например, категории сортировки/группировки). Другой содержал данные, относящиеся к культуре: описания, коды, относящиеся к культуре, если это уместно, и так далее.

(Коды, зависящие от культуры, — это осиное гнездо; не пинайте его, если в этом нет необходимости. Может быть немного сложно уложить в голове мысль, что US и EU — это один и тот же код в разных языках. Но есть это страны, в которых может быть политически неприемлемо заставлять франкоязычных пользователей использовать US в качестве аббревиатуры для États-Unis. Ну, страна.)

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

SELECT m.*, c.Code, ISNULL(s.Description, lf.Message)
FROM MainTable m
JOIN FooCodeData c ON m.CodeID = c.ID
LEFT JOIN CultureSpecificFooCodeData s ON s.CodeID = c.ID AND s.Culture = @Culture
JOIN LookupFailure lf ON lf.Culture = @Culture

Обратите внимание: если ваши коды зависят от культуры, вам даже не нужно присоединяться к FooCodeData в этом запросе, вместо этого выбирая s.Code.

Обратите также внимание на одну неотъемлемую слабость этого подхода, как показано LEFT JOIN и ISNULL в этом запросе: вы не можете создать ограничение, гарантирующее, что строка, специфичная для культуры, существует для каждой комбинации кода/культуры. Вот для чего предназначен LookupFailure: он получает сообщение, относящееся к культуре, которое указывает, что запись кода, специфичная для культуры, не была введена для данного кода.

person Robert Rossney    schedule 01.09.2009

Ознакомьтесь с чем-нибудь вроде библиотеки исходного кода Adobe' xstring структуры данных и алгоритмы. Локализация там обрабатывается с помощью идентификатора строки, а также контекста, детализирующего локализацию. Таблицы локализации могут храниться в XML, а строки локализуются во время выполнения на основе контекста времени выполнения (язык, страна, платформа и т. д.). Хотя сам код работает, я бы не стал рассматривать его как качество производства. Тем не менее, концепции тверды.

person fbrereto    schedule 01.09.2009