你如何国际化数据库中的文本?

时间:2008-11-24 13:21:36

标签: localization internationalization

如果您想在全球范围内销售,拥有完全国际化的应用程序是必需的。 在Java中,我们使用资源包并解决静态文本代码的问题。

但是你如何处理存储在数据库中的文本呢?从静态定义开始,到用户可修改的对象,以用户输入的数据结束。

假设您拥有使用不同语言环境的用户使用的数据库 - 您如何处理?你有多远国际化?你在哪里划线? 什么解决方法可以阻止用户使用他们不理解的语言接收文本?

7 个答案:

答案 0 :(得分:6)

不要将系统生成的文本存储在数据库中。而是存储代码(如消息号),然后在GUI级别将其国际化。确保直接来自数据库的唯一文本是用户自己放置的文本。确保您的数据库设置为接受unicode文本。

答案 1 :(得分:2)

首先,要非常清楚这些限制。对于用户创建的内容,如果您想要将用户输入的内容本地化到您的应用程序中,您会看到社区翻译(不稳定),机器翻译(不可靠)或支付人工翻译(费用昂贵!)。您可能想要让您的用户提供两个版本 - 一个用于您的默认文化(英语?),另一个用于其本地化文化,因此您可以为其他用户提供后备翻译?

其次,为一些非常冗长的数据库迁移做好准备......如果您在Excel电子表格中有四列文本,突然之间您正在处理将每个值插入翻译系统,检索本地化ID,以及然后将 存储在您实际导入的表中 - 而SELECT *只会为您提供短语ID,您需要通过将它们与翻译表本地化来解析为字符串。

也就是说 - 您可以本地化大量由典型项目中的数据库驱动的查找表,下拉列表等。其他评论已经提到在数据库中存储StringId值引用外部资源文件或电子表格,但如果您有兴趣将数据库中的所有本地化文本与数据本身一起保存,那么您可能会发现这种方法很有用。

我们使用了一个名为Phrase的表,其中包含应用程序中每个文本的ID和默认(英语)内容。

你的其他表最终看起来像这样:

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

创建第二个表格Culture,其中包含您支持的特定和中性文化。对于奖励积分,将此表格实现为自引用树(每个文化记录包含一个可以为空的ParentCultureCode参考),这样您就可以从特定文化(加拿大法语的“fr-CA”)回归到中性文化(“fr”如果不存在区域本地化),对于你的不变/默认文化(通常是'en',因为它被广泛使用)

您的实际翻译位于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)
)

您需要将整个表格图缓存在内存中并相应地修改查询/连接策略 - 缓存Phrase类中的本地化并覆盖Phrase对象上的ToString()方法以检查当前线程文化是一种方法。如果您尝试在查询中执行此操作,则会产生大量的性能成本,并且每个查询最终都会如下所示:

-- 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

答案 2 :(得分:1)

  

哪些解决方法可以阻止用户   用他们的语言接收文本   不明白?

这只会是用户输入数据的问题。因此,如果您想避免其他用户看到他们可能无法理解的语言中的内容,请将语言环境代码与内容一起存储,并仅将该内容显示给具有相同语言环境/用户选择语言的任何人。

另一方面,用户可能会知道几个语言,所以我不会限制他们看到内容,我只会添加一个通知,例如“此内容无法以您选择的语言提供,......”然后显示可用语言中的内容。这样,您就可以增加用户获得她能理解的内容的概率。

答案 3 :(得分:1)

我们正在将数据库中的大部分文本更改为“key:default text”,然后在我们的翻译文件中查找“key”。这涵盖了客户未在数据库中更改的所有文本(例如,称为“信用票据”的内容)。当客户确实更改了文本时,他们只需删除密钥,这样他们就可以获得价值。

我们的系统有一些表包含需要上述配置数据的表,如果每个客户只需要一种语言,那么只包含客户输入文本的表不是问题。

答案 4 :(得分: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 ...

答案 5 :(得分:0)

静态数据是最简单的我会创建一个翻译表,所以想象一个UserStatus表有一个StatusId,TranslationToken,然后TranslationTable有一个令牌,语言和文本。

或者你可以使用你的资源文件返回申请处理的令牌。

对于用户输入数据,这要复杂得多。您需要至少接受unicode字符,然后问题变为排序和比较。排序是最大的。您可以做的很多事情取决于您的应用程序。因此,如果您的数据库只需要在任何时候支持单一语言(想象一下,如果您的应用程序已分发给您的客户),那么整理是一个没有实际意义的点,因为您可以在安装时设置它。

但是,如果您必须在单个数据库中支持多种语言,则需要正确处理排序规则。我们发现动态更改排序规则的唯一方法是在查询中设置它,并且需要生成动态sql。这个例子就是你将俄语,英语和波兰语存储在同一个表中的一个字段中。

我们从未探索过拉丁语和西里尔语校对之外的任何内容,但我认为亚洲语言的作用是相同的。

答案 6 :(得分:0)

我们为系统使用XML文件。该文件包含与我们模块的特定部分的关键关联。这样我们就可以快速执行XPath来检索信息。我们每种语言都有1个文件(目前我们支持2种语言,但添加语言非常简单,只需复制粘贴文件)。这个解决方案并不完美,但有一些优点:

  1. 不在数据库中。
  2. 可由编程以外的人编辑。
  3. 易于在多个视图中实现(我们有WinForm和WebForm)。