2008-11-24 2 views
7

Наличие полностью интернационализированного приложения является необходимостью, если вы хотите продать по всему миру. В Java мы используем пакеты ресурсов, и это решает проблемы для статического текстового кода.Как интернационализировать текст в базе данных?

Но что вы делаете с текстом, который хранится в базе данных? Начиная со статических определений, до пользователей, модифицируемых объектов, заканчивая введенными пользователем данными.

Предполагая, что у вас есть база данных, используемая пользователями с разными языками - как вы справляетесь с этим? Как далеко вы интернационализируете? Где вы проводите линию? Какое обходное решение может препятствовать пользователям получать текст на языке, который они не понимают?

ответ

6

Не храните сгенерированный системой текст в базе данных. Вместо этого сохраните код (например, номер сообщения), а затем интернационализируйте его на уровне GUI. Убедитесь, что единственный текст, который поступает непосредственно из базы данных, - это текст, который пользователь вложил в себя. Убедитесь, что ваша база данных настроена на прием текста в формате Unicode.

0

Статические данные - это самый простой способ создать таблицу переводов, так что представьте таблицу UserStatus, которая имеет StatusId, TranslationToken, тогда у TranslationTable есть токены, язык и текст.

Или вы можете просто вернуть токен приложения для обработки с использованием ваших файлов ресурсов.

Что касается пользовательских входных данных, это намного сложнее. Вы должны принять символы Unicode как минимум, но затем вопрос будет сортировать и сравнивать. Сортировка - самая большая. Многое из того, что вы можете сделать, зависит от вашего приложения. Так что, если ваша база данных имеет только для поддержки одного языка в любой точке (Представьте себе, если ваше приложение было распространено для ваших клиентов), то сверка спорный вопрос, так как вы можете установить его во время установки.

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

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

0

Мы используем XML-файл для нашей системы. Файл содержит ключевые ассоциации с определенной частью наших модулей. Таким образом, мы можем быстро выполнить XPath для получения информации. У нас есть 1 файл для каждого языка (на данный момент мы поддерживаем 2 языка, но добавление языка очень просто, просто скопируйте его в файл). Это решение не является совершенным, но имеет некоторые преимущества:

  1. Нет в базе данных.
  2. Может быть отредактирован кем-то внешним по отношению к программированию.
  3. Простота реализации в нескольких представлениях (у нас есть WinForm и WebForm).
1

Что обходной путь может держать пользователей от получения текста на языке, который они не понимают?

Это было бы проблемой только для введенных пользователем данных.Поэтому, если вы хотите, чтобы другие пользователи не видели контент в langauge, они могут не понимать, хранить код локали вместе с содержимым и отображать только этот контент любому, у кого есть тот же язык/пользователь, который выбрал langauge.

С другой стороны, пользователи могут знать несколько langauges, поэтому я бы не ограничивал их просмотром контента, я бы просто добавил уведомление типа «Этот контент недоступен на выбранном вами языке ...», а затем отобразить содержимое доступного langauge. Таким образом, вы увеличиваете вероятность того, что пользователь получит контент, который она может понять.

2

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

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

Это говорит о том, что вы можете локализовать множество таблиц поиска, раскрывающихся списков и т. Д., Которые управляются базой данных в типичном проекте. В других комментариях уже упоминалось сохранение значений StringId в базе данных, относящихся к файлам или файлам внешних ресурсов, но если вы заинтересованы в том, чтобы сохранить весь свой локализованный текст в базе данных вместе с самими данными, вы можете найти этот подход полезным.

Мы использовали таблицу под названием «Фраза», которая содержит идентификатор и стандартный (английский) контент для каждого фрагмента текста в приложении.

другие ваши таблицы в конечном итоге выглядит так:

CREATE TABLE ProductType (
    Id int primary key, 
    NamePhraseId int, -- link to the Phrase containing the name of this product type. 
    DescriptionPhraseId int 
) 

Создайте вторую таблицу культуры, которая содержит конкретные и нейтральные культуры вы поддерживаете. Для бонусных точек используйте эту таблицу как самореферентное дерево (каждая запись культуры содержит нулевую ссылку на ParentCultureCode), поэтому вы можете отступить от определенных культур («fr-CA» для канадских французов) до нейтральных культур («fr», если ни одна из региональных локализации не существует), к вашей инвариантной/культуре по умолчанию (обычно «ан», потому что он так широко распространен)

ваших фактические переводов в таблице LocalizedPhrase, что выглядит следующим образом:

CREATE TABLE LocalizedPhrase (
    PhraseId int primary key, 
    CultureCode varchar(8) primary key, 
    Content nvarchar(255) -- the actual localized content 
) 

Вы можете распространите эту модель, если вы хотите обеспечить локальную/женскую специфику:

CREATE TABLE GenderedLocalizedPhrase (
    PhraseId int primary key, 
    CultureCode varchar(8) primary key, 
    GenderCode char(1) primary key, -- 'm', 'f' or '?' - links to Gender table 
    Content nvarchar(255) 
) 

Вы захотите кэшировать весь этот табличный график в памяти и соответствующим образом изменить свои стратегии запроса/объединения - кэширование локализаций внутри классов фраз и переопределение метода ToString() для объекта Phrase для проверки текущей культуры потоков - это один из подходов. Если вы попытаетесь сделать этот материал в ваших запросах, вы будете нести существенные расходы производительности и каждый запрос будет в конечном итоге выглядит так:

-- assume @MyCulture contains the culture code ('ca-FR') that we are looking for: 
SELECT 
    Product.Id, 
    Product.Name, 

    COALESCE(ProductStatusLocalizedPhrase.Content, ProductStatusPhrase.Content) as ProductStatus, 
    COALESCE(ProductTypeLocalizedPhrase.Content, ProductTypePhrase.Content) as ProductType, 
    FROM Product 

    INNER JOIN ProductStatus ON Product.StatusId = ProductStatus.Id 
    INNER JOIN Phrase as ProductStatusPhrase ON ProductStatus.NamePhraseId = Phrase.Id 
    LEFT JOIN LocalizedPhrase as ProductStatusLocalizedPhrase 
     ON ProductStatus.NamePhraseId = ProductStatusLocalizedPhrase.Id and CultureCode = @MyCulture 

    INNER JOIN ProductType ON Product.TypeId = ProductType.Id 
    INNER JOIN Phrase as ProductTypePhrase ON ProductType.NamePhraseId = Phrase.Id 
    LEFT JOIN LocalizedPhrase as ProductTypeLocalizedPhrase 
     ON ProductType.NamePhraseId = ProductTypeLocalizedPhrase.Id and CultureCode = @MyCulture 
1

Мы изменяем много текста в нашей базе данных, чтобы быть « key: default text ", а затем посмотрим« ключ »в наших файлах перевода.Это охватывает весь текст, который клиент не изменяет в базе данных (например, что называется «кредитная нота»). Когда клиент меняет текст, он может просто удалить ключ, чтобы он всегда получал там значение.

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

1

Допустим, у вас есть таблица:

create table countries (
    country_id int primary key, 
    short_name text not null unique, 
    official_name text not null unique, 
    iso_code char(2) not null unique 
); 

insert into countries values (12, 'Algeria', 'The People''s Democratic Republic of Algeria' 'DZ'); 

Затем вы создаете таблицу перевода:

create table countries_t (
    country_id int not null references countries(country_id), 
    short_name text not null, 
    official_name text not null, 
    locale varchar(5) not null, 

    primary key (country_id, locale) 
); 

insert into countries_t values 
(12, 'Algérie', 'la République algérienne démocratique et populaire', 'fr'), 
(12, 'Algerien', 'Demokratische Volksrepublik Algerien', 'de-DE'); 

Создайте представление, чтобы вернуть данные, основанные на user - переменной сеанса defined. Ниже PostgreSQL конкретные, но база данных может поддерживать пользовательские переменные сессии, иначе использование температуры в таблице:

create view countries_i18n as 
    select 
    a.country_id, 
    coalesce(c.short_name, b.short_name, a.short_name) as short_name, --default to countries.name if translation not found 
    coalesce(c.official_name, b.official_name, a.official_name) as official_name 
    countries.iso_code 
    from countries a 
    left join countries_t b on b.id = a.id and b.locale = current_setting('my_custom_guc.locale') 
    left join countries_t c on c.id = a.id and c.locale = left(current_setting('my_custom_guc.locale'), 2); --fall-back to 2-letter locale 

запроса таблица на немецком языке, на котором говорят в Германии:

SET my_custom_guc.language_code = 'de-DE'; 

select country_id, iso_code, short_name, official_name from countries_i18n; 

country_id iso_code short_name official_name 
----------------------------------------------- 
12   DZ  Algerien Demokratische ... 

запроса таблицы в канадском французском языке (возвращается к родовым французски):

SET my_custom_guc.locale= 'fr-CA'; 

select country_id, iso_code, short_name, official_name from countries_i18n; 

country_id iso_code short_name official_name 
----------------------------------------------- 
12   DZ  Algérie  la République ... 

запрос таблицы на испанском языке (нет перевода, возвращается на английском языке):

SET my_custom_guc.language_code = 'es'; 

select country_id, iso_code, short_name, official_name from countries_i18n; 

country_id iso_code short_name official_name 
----------------------------------------------- 
12   DZ  Algeria The People's D ... 
Смежные вопросы