我正在开发一个多语言软件。就应用程序代码而言,本地化不是问题。我们可以使用特定于语言的资源,并拥有各种与之配合良好的工具。

但是,定义多语言数据库模式的最佳方法是什么?假设我们有很多表(100个或更多),每个表可以有多个可以本地化的列(大多数nvarchar列应该是可本地化的)。例如,其中一个表可能保存产品信息:

CREATE TABLE T_PRODUCT (
  NAME        NVARCHAR(50),
  DESCRIPTION NTEXT,
  PRICE       NUMBER(18, 2)
)

我可以想到三种方法来支持NAME和DESCRIPTION列中的多语言文本:

Separate column for each language When we add a new language to the system, we must create additional columns to store the translated text, like this: CREATE TABLE T_PRODUCT ( NAME_EN NVARCHAR(50), NAME_DE NVARCHAR(50), NAME_SP NVARCHAR(50), DESCRIPTION_EN NTEXT, DESCRIPTION_DE NTEXT, DESCRIPTION_SP NTEXT, PRICE NUMBER(18,2) ) Translation table with columns for each language Instead of storing translated text, only a foreign key to the translations table is stored. The translations table contains a column for each language. CREATE TABLE T_PRODUCT ( NAME_FK int, DESCRIPTION_FK int, PRICE NUMBER(18, 2) ) CREATE TABLE T_TRANSLATION ( TRANSLATION_ID, TEXT_EN NTEXT, TEXT_DE NTEXT, TEXT_SP NTEXT ) Translation tables with rows for each language Instead of storing translated text, only a foreign key to the translations table is stored. The translations table contains only a key, and a separate table contains a row for each translation to a language. CREATE TABLE T_PRODUCT ( NAME_FK int, DESCRIPTION_FK int, PRICE NUMBER(18, 2) ) CREATE TABLE T_TRANSLATION ( TRANSLATION_ID ) CREATE TABLE T_TRANSLATION_ENTRY ( TRANSLATION_FK, LANGUAGE_FK, TRANSLATED_TEXT NTEXT ) CREATE TABLE T_TRANSLATION_LANGUAGE ( LANGUAGE_ID, LANGUAGE_CODE CHAR(2) )

每种解决方案都有优点和缺点,我想知道您使用这些方法的经验,您有什么建议,以及您将如何设计多语言数据库模式。


当前回答

我通常会选择这种方法(不是实际的sql),这对应于您的最后一个选项。

table Product
productid INT PK, price DECIMAL, translationid INT FK

table Translation
translationid INT PK

table TranslationItem
translationitemid INT PK, translationid INT FK, text VARCHAR, languagecode CHAR(2)

view ProductView
select * from Product
inner join Translation
inner join TranslationItem
where languagecode='en'

因为将所有可翻译文本放在一个地方可以使维护工作更加容易。有时翻译外包给翻译机构,这样你就可以给他们发送一个大的导出文件,然后很容易地导入回来。

其他回答

我正在寻找一些本地化的技巧,并找到了这个主题。 我想知道为什么要用这个:

CREATE TABLE T_TRANSLATION (
   TRANSLATION_ID
)

所以你会得到user39603所建议的:

table Product
productid INT PK, price DECIMAL, translationid INT FK

table Translation
translationid INT PK

table TranslationItem
translationitemid INT PK, translationid INT FK, text VARCHAR, languagecode CHAR(2)

view ProductView
select * from Product
inner join Translation
inner join TranslationItem
where languagecode='en'

你能不能把Translation表去掉,这样你就得到了这个:

    table Product
    productid INT PK, price DECIMAL

    table ProductItem
    productitemid INT PK, productid INT FK, text VARCHAR, languagecode CHAR(2)

    view ProductView
    select * from Product
    inner join ProductItem
    where languagecode='en'

对于每个可翻译表都有一个相关的翻译表,您怎么看?

CREATE TABLE T_PRODUCT (pr_id int, PRICE NUMBER(18, 2))

CREATE TABLE T_PRODUCT_tr (pr_id INT FK, languagecode varchar, pr_name text, pr_descr text)

通过这种方式,如果你有多个可翻译的列,它只需要一个连接就可以得到它+由于你没有自动生成translationid,它可能更容易将项目与其相关的翻译一起导入。

这样做的负面影响是,如果您有一个复杂的语言回退机制,您可能需要为每个翻译表实现该机制——如果您依赖于某个存储过程来实现该机制的话。如果你从应用程序中这样做,这可能不是一个问题。

让我知道你的想法-我也将为我们的下一个申请做出决定。 到目前为止我们使用的是你们的第三种。

下面的方法是否可行?假设您有多个表,其中有超过1个列需要转换。所以对于产品来说,你可能同时需要翻译产品名称和产品描述。你能做到以下几点吗?

CREATE TABLE translation_entry (
      translation_id        int,
      language_id           int,
      table_name            nvarchar(200),
      table_column_name     nvarchar(200),
      table_row_id          bigint,
      translated_text       ntext
    )

    CREATE TABLE translation_language (
      id int,
      language_code CHAR(2)
    )   

“哪一个是最好的”是基于项目的情况。第一种方法易于选择和维护,并且在选择实体时不需要连接表,性能最好。如果你确认你的项目只支持2或3种语言,并且不会增加,你可以使用它。

第二个是可以的,但是很难理解和维护。而且表现比第一个还差。

最后一种方法在可伸缩性方面很好,但在性能方面很差。T_TRANSLATION_ENTRY表将变得越来越大,当你想从一些表中检索一个实体列表时,这是很糟糕的。

我通常会选择这种方法(不是实际的sql),这对应于您的最后一个选项。

table Product
productid INT PK, price DECIMAL, translationid INT FK

table Translation
translationid INT PK

table TranslationItem
translationitemid INT PK, translationid INT FK, text VARCHAR, languagecode CHAR(2)

view ProductView
select * from Product
inner join Translation
inner join TranslationItem
where languagecode='en'

因为将所有可翻译文本放在一个地方可以使维护工作更加容易。有时翻译外包给翻译机构,这样你就可以给他们发送一个大的导出文件,然后很容易地导入回来。