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

但是,定义多语言数据库模式的最佳方法是什么?假设我们有很多表(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'

第三种选择是最好的,原因如下:

Doesn't require altering the database schema for new languages (and thus limiting code changes) Doesn't require a lot of space for unimplemented languages or translations of a a particular item Provides the most flexibility You don't end up with sparse tables You don't have to worry about null keys and checking that you're displaying an existing translation instead of some null entry. If you change or expand your database to encompass other translatable items/things/etc you can use the same tables and system - this is very uncoupled from the rest of the data.

亚当

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

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

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

看看这个例子:

PRODUCTS (
    id   
    price
    created_at
)

LANGUAGES (
    id   
    title
)

TRANSLATIONS (
    id           (// id of translation, UNIQUE)
    language_id  (// id of desired language)
    table_name   (// any table, in this case PRODUCTS)
    item_id      (// id of item in PRODUCTS)
    field_name   (// fields to be translated)
    translation  (// translation text goes here)
)

我认为没有必要解释,结构本身就说明了这一点。

下面的方法是否可行?假设您有多个表,其中有超过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)
    )