在具有查找表的多语言应用程序中,处理翻译的最佳方法是什么?
例如,对于国家/地区查询表,美国用户应该看到英国国家/地区名称,因为德语应该看到德语名称。但他们的ID仍应相同。
我能想到以下几点:
答案 0 :(得分:9)
这里最大的问题是 - 终端用户可以改变翻译吗?
如果答案为“否”,则资源包的使用比表格更容易,更快捷。而不是实际文本,您的表将包含资源键(或者如果它是文本而不是数字,您可以使用主键),并且适当的资源包将包含翻译。
如果答案为“是”,则必须将翻译存储在数据库中。但是,我发现在这种情况下最简单的方法是模仿数据库中的上述资源包功能 - 例如有一个表“locale”,“resource key”,“resource value”列,所有其他表将使用这些列来查找实际的本地化文本。
答案 1 :(得分:3)
编程中不相交的演示。在内部,使用ID作为一切;在向用户展示时,呈现本地化数据。
答案 2 :(得分:1)
我做了一次多语种的申请。一切都必须是多语言的,包括用户输入的内容,并且还必须易于对此内容进行翻译。
现在,如果它仅用于静态文本,则最推荐资源xml文件来执行此操作。我相信.NET框架可以很好地支持它。
如果它必须是动态的,那么我做了
的表结构表ResourceStrings resourceId GUId PK cultureCode String PK 文本字符串
然后这允许我对文化代码进行todo级联读取。因此,如果有人拥有en-us的文化代码,我可以在我做的地方进行查询
SELECT FROM ResourceStrings
WHERE resourceId = <AND ID> AND cultureCode IS IN ('en','en-us')
ORDER BY cultureCode DESC
这样,最长的文化代码将首先回归并且是最具体的。现在,如果您允许用户输入文本并进行翻译,我建议您这样做。我需要这个,因为内容必须是多语言的,以及应用程序本身。
答案 3 :(得分:1)
在我目前的项目(用django编写的自定义CMS)中,我们的I18N模型解决方案基于此示例代码段:http://www.djangosnippets.org/snippets/855/,我将其扩展为更适用于模板并集成在管理界面中。
基本上,每种类型的内容都有两个表:一个具有公共字段(如文章类别),另一个具有可翻译内容(标题,正文,标题 - 网址中使用的唯一标签等)。显然,共同模型和翻译模型之间存在着一种多对多的关系。以下是作者给出的例子:
class Article(models.Model):
author = models.CharField(max_length = 40)
class ArticleI18N(I18NModel):
title = models.CharField(max_length = 120)
body = models.TextField()
我认为这样,数据库布局非常接近于具有共同属性和可翻译字段的内容的概念。
然而,棘手的部分是在你的代码中保留DRY,或者每次你需要处理可翻译的内容时,你最终会得到一堆样板。幸运的是,python的灵活性非常有用。
如果您的编程语言和环境不允许类似的技巧(如动态创建子类,python的metaclasses - 某种继承挂钩等),我想这种数据库布局会更多诅咒而不是祝福。
因此,请牢记YAGNI原则。如果您需要在模型内部进行翻译而且并发性较少,我已经看到了其他有效的方法,只要您能够承受这些替代方案的有限灵活性和缺乏概念完整性,这些方法都很好:
答案 4 :(得分:1)
这是在数据库级别执行此操作的方法。
当我需要这样做时,我将每个代码表分成两个表。一个包含文化不变数据:代码的内部ID肯定,代码本身,如果代码是文化不变的,可能还有其他列(如排序/分组类别)。另一个包含特定于文化的数据:描述,特定文化的代码,等等。
(特定文化的代码是一个大黄蜂的巢;如果你不需要,不要踢它。可能有点难以理解US
和{{1}在不同的语言中使用相同的代码。但是在某些国家/地区,说法语用户使用EU
作为US
的缩写可能在政治上不合适。嗯, a country。)
使用culture-invariant代码表可以在它与使用它的主表之间建立外键约束。构建特定于文化的查询非常简单:
États-Unis
请注意,如果您的代码是特定于文化的,则您甚至无需在该查询中加入SELECT m.*, c.Code, ISNULL(s.Description, lf.Message)
FROM MainTable m
JOIN FooCodeData c ON m.CodeID = c.ID
LEFT JOIN CultureSpecificFooCodeData s ON s.CodeID = c.ID AND s.Culture = @Culture
JOIN LookupFailure lf ON lf.Culture = @Culture
,而是选择FooCodeData
。
还要注意此方法的一个固有弱点,如该查询中的s.Code
和LEFT JOIN
所示:您无法创建约束来保证每个代码都存在特定于区域性的行/文化组合。这就是ISNULL
的用途:它获取特定于文化的消息,指示尚未为给定代码输入特定于文化的代码记录。
答案 5 :(得分:0)
查看类似Adobe Source Libraries'xstring
数据结构和算法的内容。本地化处理时使用字符串的id以及详细说明本地化的上下文。本地化表可以存储在XML中,字符串在运行时根据运行时上下文(语言,国家,平台等)进行本地化。虽然代码本身可行但我不会将其视为生产质量。然而,这些概念是可靠的。