Должен быть лучший способ делать локализованные поля базы данных
До сих пор было несколько вопросов по этому вопросу, и все они пришли к одному и тому же ответу: одна таблица для нейтральных по отношению к региону данных, 1- * к таблице с переводами и индексированному языковому идентификатору.
У этого есть несколько проблем:
- В два раза больше CRUD.
- Необходимость для Ajax CRUD, если вы хотите дружелюбный веб-интерфейс.
- Более чем в два раза валидация - вам нужно убедиться, что отношение равно 1- *, а не 0 - *.
- Различия между языками не учитываются.
- Запросы требуют объединения.
- Если вам нужны пули на разных языках, о мальчик.
Многие люди из базы данных работали над всеми видами теоретических и практических проблем, но на удивление мало кто работает над этим.
Я думаю, что в конечном итоге нам нужно:
- Тип поля, в котором будут храниться несколько версий строк.
- Несколько индексов для каждого такого поля, по одному для каждого языка или вариации, с возможностью указать правильный режим сортировки
- Стандартный объект ORM для этой сумасшедшей вещи
- Элементы пользовательского интерфейса
Overkill? Конечно, возможно, но вся проблема - настоящий кошмар, какой он есть. И это не совсем необычный сценарий.
Мы должны попытаться убедить поставщиков серверов работать над этим.
Изменить:. Кстати, это мой первый раз, используя вики сообщества. надеюсь, я делаю это правильно.
Изменить 2: Что-то в моей формулировке, похоже, заставило людей думать, что я атакую саму концепцию СУБД. Я не; Я просто говорю, что встроенная поддержка локализации является очень необходимой функцией.
Я, вероятно, не должен упоминать о производительности; это, конечно, совершенно незначительно в большинстве случаев. В центре моей озабоченности находится тот факт, что это действительно снижает производительность.
Я приведу пример. Предположим, у меня очень тривиальная таблица для довольно тривиального хранилища:
Products (id, price, description, name, slug)
В EF/MVC я бы бросил это в ORM-дизайнере, возможно, инкапсулировал его в репозиторий, построил контроллер продуктов и имел действия для индекса, деталей, создания, обновления, редактирования и удаления. Чтобы идентифицировать продукт в любом из элементов, я бы просто сделал WHERE (slug = @slug). Я бы сделал модель представления для действий создания/редактирования, разработал элемент управления формой и подключил его прямо к репозиторию. Сделано и сделано. Чтобы получить доступ к деталям для продукта, пользователь перейдет к /products/details/product-slug
.
Но так как остальная часть сайта двуязычна, я решил соответствующим образом изменить таблицу продуктов.
Products (id, price)
ProductsText (productId, language, description, name, slug)
Эй, это не так плохо. Да, еще нет. Затем вы пишете свои отношения и свои ограничения, а затем пишете вы пишете все свои свойства в модели вида, а затем вы создаете полный CRUD-контроллер для данных ProductsText или используете jQuery/Ajax для добавления кнопок создания/обновления/редактирования на вашем контроллере Products, а затем добавьте логику проверки, чтобы убедиться, что пользователь вводит, по крайней мере, основной язык, а затем, когда вы хотите читать данные для страниц конечного пользователя, вы пишете еще один запрос, чтобы присоединиться к ProductsText.slug и ProductsText. язык с продуктами... Я, наверное, что-то пропустил, но вы поняли идею.
Сложность программы просто взрывается с помощью шаблона кода, если вы используете локализацию.
Конечно, я не ожидаю, что проблема будет решена полностью, и это, очевидно, так же, как и проблема интерфейса, поскольку это проблема с базой данных. Но есть так много, что можно сделать, чтобы сделать все это проще. "Многостраничный" тип поля может быть действительно хорошим началом.
Изменить 3: Кто-нибудь слышал о SQL Server Modeling Services? Он имеет некоторые инструменты локализации, которые могут быть шагом в правильном направлении. Тем не менее CTP.
-- Simulate the French locale with the SET LANGUAGE statement.
SET LANGUAGE French
select Id, CountryName,
[System.Globalization].[SessionsString](CountryName, 1) as CountryNameString
from [Location].[CountriesTable]
Ответы
Ответ 1
Что такое локализованное поле базы данных?
Обычно в приложениях, в которых мы работали, пользовательский интерфейс локализуется. Это выполняется с использованием базы данных, и мы помещаем все переводы (и, возможно, мастер-фразы) в таблицу, причем языковой код и фразерирование являются первичным ключом. Это довольно просто, требуется один многоразовый набор хранимых процедур и имеет хорошую производительность, и использование хорошо понято. Мы часто разрешаем перевод "на лету", чтобы интерфейс приложения включал функцию перевода, в которой исправления могут быть сделаны, а другие пользователи будут видеть их в прямом эфире - приложения с богатыми формами или приложения для веб-форм (в зависимости от кеширования - это еще одна ключевая особенность локализации пользовательского интерфейса )
Что касается запросов, требующих объединения, то это просто факт жизни в нормализованной реляционной базе данных и производительность, как правило, управляются с хорошим нормализованным дизайном и правильной индексацией.
В других "данных" было мало смысла локализовать, кроме как в соответствии с требованиями приложения. Например, даже если вы можете предлагать продукт в нескольких странах, SKU и дистрибьютор могут отличаться. Этот уровень локализации очень специфичен для приложений, и мы часто рассматриваем его как отдельную базу данных, и на самом деле нет ничего связанного с каждой отдельно взятой базой данных страны - многие продукты недоступны, хотя в других странах могут быть эквивалентные продукты.
Если вы продаете одни и те же продукты по всему миру, то вы относитесь к первоначальному сценарию в виде многоязычной CMS. Это требует значительной работы, помимо базы данных низкого уровня. Например, если кто-то исправляет описание продукта по умолчанию, какие флажки переводчики должны также корректировать перевод? Эти вопросы нетривиальны. Хотя я могу видеть, где поставщики баз данных могут помочь с функциями, это неотъемлемые трудности требований приложений и дизайна, а не то, что база данных может добавлять в функции, которые будут универсально решать.
Проблема сопоставления действительно немного неудобна. Обычно данные хранятся в nvarchar, и вы не знали бы сортировки, которую вы хотели бы получить в момент написания хранимой процедуры, так как локаль будет параметром. Это влияет только на собираемые коллекции, которые нужно заказывать по контенту, а не обычно по естественному ключу и, конечно же, не извлекать ключ - это не большая проблема, но это тот, который не может быть легко обработан без динамического SQL (литье с использованием предпочтительной сортировки из таблицы в зависимости от местоположения, переданного в, если вы смешиваете данные из разных локалей, вам нужно будет решить, хотите ли вы сначала отсортировать по локали, а затем может быть сложно выбрать сортировку, которая могла бы работать правильно во всех локалях в том же наборе результатов). Вероятно, вам захочется использовать сортировку Windows с таким широким спектром данных.
Аналогично ORM, мы обычно обрабатываем составной уникальный ключ locale/phraseid как ключ для извлечения объектов (обычно у нас также есть первичный ключ суррогатной идентификации). Я знаю, что традиционные ORM не обязательно похожи на это отклонение от поиска бессмысленным суррогатным ключом.
Ответ 2
Я столкнулся со всеми этими проблемами для локализованных веб-сайтов в стиле CRM. Не интересно разрабатывать и оптимизировать, но это можно сделать. Мой 2 ¢ стоит:
1. В два раза больше CRUD.
Это зависит от того, как разработан ваш CRUD. Любая из моих хранимых процедур или функций, которые могут получить возможное локализованное поле, принимает параметр кода локали/культуры. Все эти поля также NVARCHAR
, чтобы избежать проблем с кодировкой.
2. Необходимость в Ajax CRUD, если вы хотите дружеский веб-интерфейс.
Я так полагаю, но это зависит от приложения. Следует отнестись к принципу "внутреннего" CRUD (DRY).
3. Более чем в два раза валидация - вам нужно убедиться, что отношение равно 1- *, а не 0 - *.
Это также предполагает, что весь контент требуется во всех поддерживаемых локалях вместо использования резервного механизма. Например, содержимое Microsoft MSDN доступно в нескольких локальных сетях, но некоторые из них только в одном (обычно это английский язык США, "нейтральный" язык для Microsoft).
Для системы в стиле CRM любая локаль может использоваться для исходного содержимого, пока резервное использование использует это, если нейтральное содержимое недоступно.
4. Различия в сопоставлении между языками не учитываются.
Я нахожу, что проще всего поддерживать сопоставление на уровне пользовательского интерфейса/отчетности. Многоязычные таблицы с параметрами сопоставления/локали, заданные в строке за строкой, были бы очень приятной, но я не хотел бы ждать, пока она станет доступной...
5. Запросы требуют объединения.
Да, определенно делает запрос немного сложнее:-), но нет реального пути. Может стать еще более сложным, если включить резерв локали (здесь помогает поле рейтинга "локальная специфика" ).
6. Если вам нужны пули на разных языках, о мальчик.
Именно поэтому параметры замены .NET в строке формата были спроектированы для индексации, а не позиционные (printf()
и т.д.). В английском формате могут потребоваться замены в порядке 1, 2, 3, в то время как немецкий эквивалент использует 3, 1, 2.
Чтобы облегчить жизнь локализаторам, всякий раз, когда я создаю пакет ресурсов .NET, я документирую параметры, включая индекс, тип данных (включая минимальные и/или максимальные длины строк) и контекстное описание - контекст важен для определения текстового поля в некоторых локалях.
Множественность может также требовать нескольких связанных ресурсов, так как некоторым локалям требуется больше, чем просто "одиночное" и "множественное число" (например, "0 файлов", "1 файл", "2 файла" ).
Те же правила должны применяться к любому локализуемому столбцу в базе данных.
Ответ 3
Ну, ответы пока не так полезны. У меня была та же проблема в различных проектах, которые я делал в прошлом. И никогда не было ярлыка или решения из коробки, которые помогли мне решить эту проблему простым способом. Но ваш подход идет в правильном направлении и с небольшой работой на вашем Уровне доступа к данным вы можете реально абстрагировать всю нагрузку, вызванную этим требованием.
Так что для метаданных, таких как типы, категории, страны и т.д. производительность не является проблемой, поскольку весь материал может быть кэширован. Для записей freetext это совсем другая история. Скорее всего, вы не можете кэшировать их, и они, как правило, довольно длинные.
Возможно, вы уже знаете эти страницы:
http://www.codeproject.com/KB/aspnet/LocalizedSamplePart2.aspx
http://www.sisulizer.com/online-help/DatabaseLocalization.shtml
Рекомендации по локализации базы данных SQL Server (2005/2008)
Ответ 4
По моему опыту я обычно не сталкивался с проблемой, когда данные, хранящиеся в базе данных, имеют много языковых версий одного и того же текста. Как правило, у разработанного приложения будет много языковых файлов для всего текста, который более или менее статически встроен в приложение. Затем мы видим данные базы данных для ввода текстовых пользователей. Хотя приложение может использоваться пользователями со многими языками, ситуация, когда пользователи вводят один и тот же текст на нескольких языках, не так распространена. Обычно использование приложения отображает пользовательский интерфейс на своем языке, а затем вводит и просматривает данные на их языке.
Например, пользователи нашего приложения в США и Нидерландах или Саудовской Аравии будут видеть пользовательский интерфейс на выбранном им языке, но для любой конкретной установки данные, которые они вводят, будут постоянно находиться на их родном языке.
Очевидно, это не относится ко всем случаям. CRM - пример, где у вас будет один и тот же текст с несколькими переводами, например, Википедия, но я думаю, что описанное выше было более распространенным сценарием.
Ответ 5
"Многие люди из базы данных работали над всеми видами теоретических и практических проблем, но на удивление мало кто работает над этим".
Это потому, что в вашем примере не с чем работать, с теоретической точки зрения. Так называемые "проблемы", о которых вы говорите, - все это не что иное, как прямое следствие того, что вы управляете большим количеством данных.
"В два раза больше CRUD."
И почему это проблема? Я знаю, по крайней мере, несколько систем, которые я построил, которые имели намного больше, чем ваш пример.
"Необходимо для Ajax CRUD, если вы хотите иметь приличный веб-интерфейс".
Это действительно так? Я не знаю, но, во всяком случае, как данные обрабатываются на уровне презентации, это не касается СУБД, и если программист считает, что это слишком сложно/громоздко, тогда не обвиняйте СУБД в этом.
Более чем в два раза валидация - вам нужно убедиться, что отношение равно 1- *, а не 0 - *.
И почему это проблема? Если указано больше бизнес-правил, требуется дополнительная проверка.
"Различия в сопоставлении между языками не учитываются".
Как так? В чем смысл сопоставления английского текста с французским? Английский текст с украинским или русским или китайским языком? Или вы имели в виду что-то еще?
"Запросы требуют объединения".
И почему это проблема?
"Если вам нужны пули на разных языках, о мальчик".
В каком контексте? С какой целью?
SELECT language, nllabel FROM...
NATURAL JOIN (SELECT 'EN' как язык UNION SELECT 'FR' как язык)
О, но подождите, я забыл... JOINs тоже проблема.
Ответ 6
", и это, очевидно, та же проблема интерфейса, что и проблема с базой данных."
Я не согласен, что это так. Когда вы смотрите на свою проблему из-за угла базы данных, есть две вещи, которые могут быть небольшим началом решения:
возможность полного обновления содержимого (как через JOIN, так и через GROUP, для вашего случая).
возможность иметь атрибуты типа "таблица" внутри таблиц базы данных. Тогда у вас может быть весь набор применимых локализованных имен-вещей как атрибут sinle в одной строке для вашего продукта /...
Как для полного обновления вида: не задерживайте дыхание. Вы задохнетесь задолго до его прибытия.
Что касается вложенных таблиц: они могут уже существовать, если у кого-то есть их Oracle, я действительно не знаю, но я не уверен, что это действительно облегчит жизнь на стороне интерфейса.
О, и BTW: SQL нигде не близок "теоретически чистый".