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

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

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


当前回答

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

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,它可能更容易将项目与其相关的翻译一起导入。

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

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

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

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'

下面的方法是否可行?假设您有多个表,其中有超过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视图一起工作,以简化查询和友好地开发底层应用程序

我分离了LabelTranslations,因为这是一个网页上字段标签的全局翻译表。你可以随意称呼它,它们是无状态的,不依赖于特定的产品或类别。

ProductTranslations的CategoryTranslations是有状态的,这意味着“name”的描述符将是实际的产品名称。

与简单的SQL视图相比,使用物化视图可以获得更好的性能(使用存储空间的成本和更多的精力用于底层应用程序开发来刷新它们),或者如果你想要使用更重的SQL视图。

在Postgres中创建类别物化视图:

CREATE MATERIALIZED VIEW VCategories AS (
    SELECT cat.id, lng.iso_639_1_code, ct.descriptor, ct.value
    FROM Categories cat
    JOIN CategoryTranslations ct ON ct.category_id = cat.id
    JOIN Languages lng ON lng.id = ct.language_id
);

查询ID为120的类别的所有翻译

SELECT * FROM VCategories WHERE id = 120 AND iso_639_1_code = 'en'

我觉得在使用应用程序的代码时很方便,您可以编写非常简单的代码来查询翻译和搜索记录