更新:几年后我遇到了这个问题:现在我知道这是一个非常糟糕的方法。请不要用这个。您总是可以为i18n使用额外的表(例如products
和products_lang
),为每个区域设置单独的条目:更好地用于索引,更好地用于搜索等。
我正在尝试在MySQL/PHP站点中实现i18n。
我读过这样的回答:"i18n通常不是数据库的一部分",我认为这是一种有点狭隘的方法。产品名称,或者像我的例子一样,菜单结构和存储在数据库中的内容呢?
考虑到语言应该是可扩展的,我想知道你对我的方法有什么看法,所以我尽量避免"每种语言的解决方案一列"。
一种解决方案是对要翻译的字符串使用引用(id),并且对于每个可翻译列都有一个包含主键、字符串id、语言id和翻译的表。
我认为另一个解决方案是使用JSON。因此,我的数据库中的菜单条目看起来像:
idmenu label
------ -------------------------------------------
5 {"en":"Homepage", "it":"pagina principale"}
你觉得这种方法怎么样?
"一种解决方案是为要翻译的字符串使用引用(id),并且为每个可翻译列都有一个包含主键、字符串id、语言id和翻译的表。"
我实现过一次,我所做的是采用现有的数据库模式,查找所有具有可翻译文本列的表,并为每个这样的表创建一个单独的表,其中只包含这些文本列,以及一个额外的语言id和id,将其与原始表中的"数据"行绑定。所以如果我有:
create table product (
id int not null primary key
, sku varchar(12) not null
, price decimal(8,2) not null
, name varchar(64) not null
, description text
)
我会创建:
create table product_text (
product_id int not null
, language_id int not null
, name varchar(64) not null
, description text
, primary key (product_id, language_id)
, foreign key (product_id) references product(id)
, foreign key (language_id) references language(id)
)
我想这样问:
SELECT product.id
, COALESCE(product_text.name, product.name) name
, COALESCE(product_text.description, product.description) description
FROM product
LEFT JOIN product_text
ON product.id = product_text.product_id
AND 10 = product_text.language_id
(10恰好是你现在感兴趣的语言id。)
正如您所看到的,原始表保留了文本列——如果当前语言没有可用的翻译,这些列将作为默认列。
因此,无需为每个文本列创建单独的表,只需为所有文本列创建一个表(每个原始表)
正如其他人指出的那样,JSON的想法存在一个问题,即查询它是不可能的,这反过来意味着无法只提取特定时间所需的翻译。
这不是一个扩展。您失去了使用关系数据库的所有优势。与您的方式类似,您可以使用serialize()
来获得更好的解码性能,甚至可以将数据存储在文件中。在这种结构中使用SQL并没有什么特别的要求。
我认为将列用于所有语言是没有问题的。这在CMS的编程中更容易。关系数据库不仅仅用于存储数据。它是为了合理地处理数据(例如使用强大的内置机制)并控制数据的结构和完整性。
首先想到的是:这显然会阻碍sql WHERE label='Homepage'中的精确搜索第二:用户在搜索时可以看到不需要的结果(例如,当他的查询是在其他语言字符串中找到的)
我建议在数据库中保留一种主要语言,并使用额外的子系统来维护翻译。这是Drupal等web应用程序的标准方法。在您的软件/应用程序领域中,每个主要语言字符串都可能有一个单独的翻译,因此您不必担心上下文或歧义。(事实上,为了获得最佳的用户体验,您无论如何都应该努力为独特的功能提供独特的标签)。
如果你想自己滚桌子,你可以有这样的东西:
create table translations (
id int not null primary key
, source varchar(255) not null // the text in the primary language
, lang varchar(5) not null // the language of the translation
, translation varchar(255) not null // the text of the translation
)
您可能需要超过2个字符的语言,因为您可能需要en_US、en_UK等。