多语言数据库设计的最佳实践是什么?

227
什么是创建多语言数据库的最佳方式?为每个表创建本地化表格会使设计和查询复杂,另一种情况是为每种语言添加列很简单但不够灵活,请帮助我理解什么是企业应用的最佳选择。

请参考以下链接:https://dev59.com/zXE95IYBdhLWcg3wn_Vr https://dev59.com/XnRC5IYBdhLWcg3wYP6h https://dev59.com/xnA75IYBdhLWcg3w1sz2#4745863 - Maxime Pacary
4
我发现这对我非常有帮助:MySQL中的多语言数据库设计 - Siamak Motlagh
5个回答

273
我们所做的是为每个多语言对象创建两个表。例如,第一个表只包含语言中立数据(主键等),而第二个表包含每种语言的一个记录,其中包含本地化数据和该语言的 ISO 代码。在某些情况下,我们会添加一个 DefaultLanguage 字段,以便如果没有指定语言的本地化数据,则可以回退到该语言。示例:
Table "Product":
----------------
ID                 : int
<any other language-neutral fields>


Table "ProductTranslations"
---------------------------
ID                 : int      (foreign key referencing the Product)
Language           : varchar  (e.g. "en-US", "de-CH")
IsDefault          : bit
ProductDescription : nvarchar
<any other localized data>

通过这种方法,您可以处理所需的所有语言(而无需为每种新语言添加其他字段)。


更新(2014年12月14日):请查看这个答案,了解有关将多语言数据加载到应用程序中使用的实现的一些附加信息。


16
如果唯一的语言中立字段是ID,那该怎么办?在插入行时如何精确插入外键引用? - Timo Huovinen
4
很有趣,我正在设计一个多语言 CMS 的数据库方案时也在思考这个问题。结果我选择了这种方法,甚至在看到这个答案之前!谢谢这个答案! - Patrick Manser
6
需要注意的是,这个表要么没有主键,要么需要将ID和语言作为组合主键。否则,你需要添加一个ProductTranslationId字段,通常作为身份识别。 - Daniel Lorenz
1
如果您需要在内容上执行全文搜索,则语言需要分别放置在不同的列中。当然,您也可以将它们放置在带有全文索引的索引视图中。 - Jon49
1
@M4N我认为IsDefault语言标志应该添加到语言表中,而不是ProductTranslations表中,因为对于所有产品来说,默认语言都是相同的。 - MD. IBRAHIM KHALIL TANIM
显示剩余20条评论

25

我推荐 Martin 发布的答案。

但是你似乎担心你的查询语句变得太复杂:

为每个表创建本地化表格会使设计和查询变得复杂......

因此,你可能正在考虑改为编写简单的查询语句,例如:

SELECT price, name, description FROM Products WHERE price < 100

你需要开始编写这样的查询:

SELECT
  p.price, pt.name, pt.description
FROM
  Products p JOIN ProductTranslations pt
  ON (p.id = pt.id AND pt.lang = "en")
WHERE
  price < 100

这并不是一个非常美观的观点。

但是,你可以开发自己的数据库访问类,它可以预解析包含特殊本地化标记的SQL,并将其转换为实际需要发送到数据库的SQL,而不是手动执行此过程。

使用该系统可能类似于:

db.setLocale("en");
db.query("SELECT p.price, _(p.name), _(p.description)
          FROM _(Products p) WHERE price < 100");

我相信你甚至可以做得更好。

关键在于将你的表格和字段以统一的方式命名。


另一个问题是,为产品创建一个业务对象还是创建两个?在第一种情况下,使用该项很容易,在第二种情况下编写CMS很容易。 - Arsen Mkrtchyan
马丁的解决方案在哪里? - Weihang Jian

14

我发现这种方法适合我:

产品        产品详情            国家
=========   ==================   =========
产品编号    产品详情编号         国家编号
- 等等 -    产品编号             国家名称
            国家编号             语言
            产品名称             - 等等 -
            产品描述
            - 等等 -

“ProductDetail”表存储所有需要翻译的内容(例如产品名称、描述等)对应的各种语言版本。根据您的应用程序要求,您可能希望将“Country”表拆分为区域性语言。


我选择了同样的方法来处理我目前正在开发的项目,因为我的不同地区包含有关单位系统和度量标准的非常具体的信息,需要向用户显示。 - califrench
11
国家和语言(本土化)是不同的事情。ISO语言代码是自然键,您可以从语言到国家消除不必要的连接。 - gavenkoa

12

我正在使用以下方法:

产品

产品ID 订单ID,...

产品信息

产品ID 标题 名称 语言ID

语言

语言ID 名称 区域,....


2

Martin的解决方案和我的非常相似,但是如果找不到所需的翻译,你将如何处理默认描述?

这是否需要一个IFNULL()和另一个SELECT语句来处理每个字段?

默认翻译将存储在同一张表中,其中一个标志(例如“isDefault”)表示该描述是否为默认描述,以防当前语言没有找到任何描述。


1
@GorrillaApe:请参考此答案,了解如何在未找到所需语言时回退到默认语言的示例:https://dev59.com/5l8d5IYBdhLWcg3weyM0#27474681 - M4N
马丁的解决方案在哪里? - Weihang Jian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接