保存多语言数据的最佳数据库结构是啥? [复制]

Posted

技术标签:

【中文标题】保存多语言数据的最佳数据库结构是啥? [复制]【英文标题】:What's the best database structure to keep multilingual data? [duplicate]保存多语言数据的最佳数据库结构是什么? [复制] 【发布时间】:2011-01-14 17:45:31 【问题描述】:

可能重复:Schema for a multilanguage database

这是一个例子:

[ products ]
id (INT)
name-en_us (VARCHAR)
name-es_es (VARCHAR)
name-pt_br (VARCHAR)
description-en_us (VARCHAR)
description-es_es (VARCHAR)
description-pt_br (VARCHAR)
price (DECIMAL)

问题:每种新语言都需要修改表结构。

这是另一个例子:

[ products-en_us ]
id (INT)
name (VARCHAR)
description (VARCHAR)
price (DECIMAL)

[ products-es_es ]
id (INT)
name (VARCHAR)
description (VARCHAR)
price (DECIMAL)

问题:每种新语言都需要创建新表,并且“价格”字段在每个表中都重复。

这是另一个例子:

[ languages ]
id (INT)
name (VARCHAR)

[ products ]
id (INT)
price (DECIMAL)

[ translation ]
id (INT, PK)
model (VARCHAR) // product
field (VARCHAR) // name
language_id (INT, FK) 
text (VARCHAR)

问题:难吗?

【问题讨论】:

第三种方法或多或少是正确的——有什么难的? 问题是,你找到的每一个解决方案,当你需要修改表格时,你总会找到一个案例——即更多的语言、不同的语言、另一个字段...... 由于用户很可能一次只使用一种语言,我认为应该考虑为每种语言使用单独的数据库。这种方法会占用更多的存储空间,但不会带来性能问题,而且设置起来相对容易。 【参考方案1】:

您的第三个示例实际上是通常解决问题的方式。很难,但可行。

从翻译表中删除对产品的引用,并将对翻译的引用放在您需要的地方(反之亦然)。

[ products ]
id (INT)
price (DECIMAL)
title_translation_id (INT, FK)

[ translation ]
id (INT, PK)
neutral_text (VARCHAR)
-- other properties that may be useful (date, creator etc.)

[ translation_text ]
translation_id (INT, FK)
language_id (INT, FK) 
text (VARCHAR)

作为一种替代方法(不是特别好的),您可以使用一个字段并将所有翻译合并在一起(例如 XML)。

<translation>
  <en>Supplier</en>
  <de>Lieferant</de>
  <fr>Fournisseur</fr>
</translation>

【讨论】:

如果产品表包含多个翻译字段怎么办?检索产品时,您必须对每个翻译字段进行一次额外的连接,这将导致严重的性能问题。插入/更新/删除也有(IMO)额外的复杂性。这样做的唯一优点是表的数量较少。我会选择 Gipsy King 或 Clément 提出的方法:我认为它在性能、复杂性和维护问题之间取得了很好的平衡。【参考方案2】:

有多对多的关系。

你有你的数据表、语言表和一个 data_language 表。

在您拥有的 data_language 表中

id、data_id、language_id

我认为这可能最适合您。

【讨论】:

@AntonioCS - “数据”表不是“产品”表,对吧? @TiuTalk 是。这样,产品表就不必知道有哪些语言,语言表也不必知道。这一切都在 data_language 表上(或者在这种情况下是 'product_language 表)【参考方案3】:

为了减少 JOIN 的数量,您可以将已翻译的和未翻译的分开放在 2 个单独的表中:

[ products ]
id (INT)
price (DECIMAL)

[ products_i18n ]
id (INT)
name (VARCHAR)
description (VARCHAR)
lang_code (CHAR(5))

【讨论】:

@Clément - 这里的问题是当 products 表获得一个新字段时......我也需要更改 products_i18n 表。 :// @TiuTalk - 只有一个表会获取新字段,如果是翻译字段,则进入products_i18n,否则进入products。这样您就不会复制任何信息。 @Clément: product.id 是 products_i18n.id 中的 FK 用户还是您使用第三个连接表? @CoR 是的,products.id 可以是 products_i18n 表中的外键。 products_i18n 表的主键是由(product.id, products_i18n.lang_code) 组成的复合键。【参考方案4】:

我们将这个概念用于我们的网站(每天 60 万次浏览)并且(可能令人惊讶)它很有效。当然还有缓存和查询优化。

[attribute_names]
id (INT)
name (VARCHAR)

[languages_names]
id (INT)
name (VARCHAR)

[products]
id (INT)
attr_id (INT)
value (MEDIUMTEXT)
lang_id (INT)

【讨论】:

那么像价格这样的重复字段呢?【参考方案5】:

在我的 $DAYJOB 中,我们将 gettext 用于 I18N。我向xgettext.pl 写了一个插件,它从数据库表中提取所有英文文本并将它们添加到主messages.pot。

效果很好——翻译人员在翻译时只处理一个文件——po 文件。翻译时无需摆弄数据库条目。

【讨论】:

如果您只想为您的应用程序提供翻译,这可能会起作用。前任菜单条目、标题、帮助文本等【参考方案6】:

类似于方法3:

[languages]
id (int PK)
code (varchar)

[products]
id (int PK)
neutral_fields (mixed)

[products_t]
id (int FK)
language (int FK)
translated_fields (mixed)
PRIMARY KEY: id,language

因此,对于每个表,创建另一个包含翻译字段的表(在我的情况下使用“_t”后缀)。 当您SELECT * FROM products 时,只需... LEFT JOIN products_t ON products_t.id = products.id AND products_t.language = CURRENT_LANGUAGE

没那么难,而且让您免于头痛。

【讨论】:

【参考方案7】:

[语言] id (int PK) 代码(varchar)

[products]
id (int PK)
name
price
all other fields of product
id_language ( int FK )

我其实是用这个方法的,但就我而言,不是从产品的角度来看,对于我的CMS中的各个页面来说,这个工作还算不错。

如果您有很多产品,用 5 或 6 种语言更新单个产品可能会让人头疼……但这是布局工作的问题。

【讨论】:

【参考方案8】:

第四个解决方案呢?

[ products ]
id (INT)
language (VARCHAR 2)
name (VARCHAR)
description (VARCHAR)
price (DECIMAL)
*translation_of (INT FK)*

*Translation_of* 是它自己的 FK。当您添加默认语言时 *translation_of* 设置为 Null。但是当您添加第二语言时,*translation_of* 会采用主要产品语言 id。

SELECT * FROM products WHERE id = 1 AND translation_of = 1

在这种情况下,我们会得到 id 为 1 的产品的所有翻译。

SELECT * FROM products WHERE id = 1 AND translation_of = 1 AND language = 'pl'

我们只得到波兰语翻译的产品。没有第二个表和 JOINS。

【讨论】:

这是一个有趣的方法。我喜欢查询的便利性,但它确实打破了产品表中的任何条目都是一种产品的假设,因此必须牢记这一点。它还允许您继续为字段使用正确的类型(varchar 等)。 我现在正在考虑实施完全相同的事情,但在其他任何地方都没有找到这个解决方案。我看到你的帖子是 2011 年的。你有什么问题吗?您仍然认为这是一个很好的解决方案吗?谢谢。 1) 它允许您同时拥有可翻译和不可翻译的字段; 2) 它不会将您的所有翻译都绑定到特定的翻译(默认语言); 为了回答您的问题,插入、更新、删除操作都做得很好而且很快。问题都在我的脑海里——我知道数据库不是它应该的样子,这让我很烦恼。

以上是关于保存多语言数据的最佳数据库结构是啥? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

使用strings.xml 在数据库上存储多语言值的最佳方法?

多语言支持的最佳状态管理?

多语言数据库设计业务类

多语言反应webapp的最佳方法

c# 在 c# 应用程序中保存配置数据的最佳方法是啥。 [复制]

多语言持久性数据库处理