我正在开发一种多语言软件。就应用程序代码而言,可本地化不是问题。我们可以使用特定于语言的资源,并拥有适合他们的各种工具。
但是,定义多语言数据库模式的最佳方法是什么?假设我们有很多表(100或更多),每个表可以有多个可以本地化的列(大多数nvarchar列应该是可本地化的)。例如,其中一个表可能包含产品信息:
CREATE TABLE T_PRODUCT (
NAME NVARCHAR(50),
DESCRIPTION NTEXT,
PRICE NUMBER(18, 2)
)
我可以考虑在NAME和DESCRIPTION列中支持多语言文本的三种方法:
每种语言的单独列
当我们向系统添加新语言时,我们必须创建其他列来存储翻译后的文本,如下所示:
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)
)
包含每种语言列的翻译表
不存储翻译文本,而是仅存储翻译表的外键。翻译表包含每种语言的列。
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
)
包含每种语言行的翻译表
不存储翻译文本,而是仅存储翻译表的外键。翻译表仅包含一个键,而单独的表包含每种语言翻译的行。
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)
)
每个解决方案都有优缺点,我想知道您对这些方法的体验,您的建议是什么以及如何设计多语言数据库模式。
答案 0 :(得分:108)
您如何为每个可翻译表格提供相关的翻译表?
创建表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)
这样,如果你有多个可翻译列,它只需要一个连接来获取它+因为你没有自动生成翻译,所以可能更容易将项目与相关翻译一起导入。
这方面的负面影响是,如果您有一个复杂的语言回退机制,您可能需要为每个转换表实现这一点 - 如果您依赖某些存储过程来执行此操作。如果你从应用程序那样做,这可能不是问题。
让我知道你的想法 - 我也将为我们的下一个申请做出决定。 到目前为止,我们已经使用了你的第三种类型。
答案 1 :(得分:47)
第三种选择是最好的,原因如下:
- 亚当
答案 2 :(得分:9)
看看这个例子:
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)
)
我认为没有必要解释,结构描述了自己。
答案 3 :(得分:8)
我通常会采用这种方法(不是实际的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'
因为在一个地方拥有所有可翻译的文本使维护变得更加容易。有时翻译会外包给翻译机构,这样您就可以向他们发送一个大的导出文件,并轻松地将其导回。
答案 4 :(得分:3)
在了解技术细节和解决方案之前,您应该停一分钟并询问有关要求的几个问题。答案可能对技术解决方案产生巨大影响。这类问题的例子如下:
- 是否会一直使用所有语言?
- 谁和什么时候填写不同语言版本的列?
- 当用户需要某种语言的文本且系统中没有文本时会发生什么?
- 只有本地文本或其他项目(例如PRICE可以存储在$和€中,因为它们可能不同)
答案 5 :(得分:3)
我正在寻找本地化的一些技巧并找到了这个主题。 我想知道为什么使用它:
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'
你能不能把表格翻译出去,这样你就明白了:
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'
答案 6 :(得分:1)
我同意随机发生器。我不明白为什么你需要一个表“翻译”。
我认为,这已经足够了:
TA_product: ProductID, ProductPrice
TA_Language: LanguageID, Language
TA_Productname: ProductnameID, ProductID, LanguageID, ProductName
答案 7 :(得分:1)
以下方法是否可行?假设您有超过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)
)
答案 8 :(得分:1)
此document描述了可能的解决方案以及每种方法的优缺点。我更喜欢“行本地化”,因为添加新语言时不必修改数据库架构。
答案 9 :(得分:0)
“哪一个最好”是基于项目情况。第一个很容易选择和维护,性能也是最好的,因为它不需要在select实体时连接表。如果您确认您的项目仅支持2或3种语言,并且不会增加,则可以使用它。
第二个是好的,但很难理解和维护。而且表现比第一次差。
最后一个擅长可扩展性但性能不佳。 T_TRANSLATION_ENTRY表会变得越来越大,当你想要从某些表中检索实体列表时,这很糟糕。
答案 10 :(得分:0)
您需要记住,创建多语言数据库时,您要从产品表中切断诸如名称或描述之类的字段,并将其移至翻译后的资源中。
翻译后的资源可能是另一个表,例如在我的示例中,该表旨在与SQL视图一起使用,以简化查询并简化基础应用程序的开发
我分开了LabelTranslations,因为这是一个包含网页上字段标签的全局翻译的表。您可以根据需要调用它,它们是无状态的,并且不依赖于特定的产品或类别。
ProductTranslations的CategoryTranslations是有状态的,这意味着“名称”的描述符将是实际的产品名称。
使用物化视图来获得比简单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'
使用该应用程序的代码时,我觉得很方便,您可以编写一个非常简单的代码来查询翻译和搜索记录