适当的多语言模式,还是矫枉过正?

Tim*_*ack 8 mysql database-design

更新 2:我实际上最终使用了它,经过几次调整后效果很好。这是我关于其实际设计和实际设计的帖子:http : //tim.hithlonde.com/2013/lemon-schema-works/

我正在构建一个网络应用程序,我希望它支持多种语言。这种结构有两个组成部分:

  1. 将语言环境('english'、'Deutch' 等)与术语联系起来,并用罗塞塔石碑连接术语和特定语言中的术语。
  2. 按页面对术语进行分组。我不想说,通过页面上我可能需要的 30 多个术语来选择 term1、term2 等。我想通过他们连接的页面询问。

这是我建议的表结构(注意所有 id 之间都有关系/索引以进行非常有效的查询):

架构图

  * locale
      * id
      * value //English, Deutch, etc//
  * terms
    * id
    * value //In English//
  * page 
    * id
    * value //Think add entry, menu//
  * page_group //group all terms to a page, for easy pulling//
    * id
    * page.id
    * term.id
  * rosetta
    * id
    * locale.id
    * term.id
    * value //french word for amount, description, etc//
Run Code Online (Sandbox Code Playgroud)

这将允许查询,如:

SELECT localization.value,
        terms.value
FROM localization
INNER JOIN terms ON terms.id=localization.termid
INNER JOIN page_group ON page_group.termid=localization.termid
INNER JOIN page ON page.id=page_group.pageid
INNER JOIN locale ON locale.id=localization.localeid
WHERE page.value='add_entry' AND locale.id=custlangid
ORDER BY terms.id
Run Code Online (Sandbox Code Playgroud)

我只需要问两个项目;我需要的语言 ID,以及我需要的页面。它将以指定的语言提供所有条款,这些条款属于该页面的条款组的一部分。

我认为这是一个非常好的结构,但我希望得到一些反馈。

更新:澄清一下,我们只是在谈论UI 组件的本地化。(标签、导航、有用的文本)用户输入的所有信息都将存储在 unicode 中,而不是在这个模式中。

更新 2:我实际上最终使用了它,它很棒。这是我关于它的实际设计和实际设计的帖子:http : //tim.hithlonde.com/2013/lemon-schema-works/

Cad*_*oux 6

我们已经做了很多这样的工作,并且(管理)用户被允许实时修复翻译。(您可能仍然需要一个缓存层,但我完全不愿意使用真实的数据库而不是资源文件来驱动它 - 它为您提供了查询和查找需要翻译的内容等的强大功能)。我认为你的模式可能很好,所以我会传递一些我们学到的东西,希望它有用。

您遗漏的一件事是带有插入点的短语。在下面的例子中,顺序颠倒了,语言仍然是英语,但这很容易是两种不同的语言 - 假设这只是两种通常将事物按不同顺序排列的语言。

Hello, <username> you have <x> points!

You've got <x> points to spend, <username>!
Run Code Online (Sandbox Code Playgroud)

在我们的 .NET 之前,我们有一个执行插入的例程,因此短语看起来像这样:

Hello, {0:username} you have {1:points} points!

You've got {1:points} points to spend, {0:username}!
Run Code Online (Sandbox Code Playgroud)

这显然只会在您的代码中用作<%= String.Format(phrase, username, points); %>或类似的

这对翻译有点帮助。但不幸的是,.NET String.FOrmat 不支持在格式字符串中进行注释。

正如您所说,您不希望在具有区域设置意识或元短语的 php 中处理该问题。

所以我们有一个主短语表:

短语,英语,补充信息

和本地化表:

短语,localeid,翻译

您还使用 INNER JOINS 假设本地化版本存在 - 我们倾向于将它们排除在外,直到它们被翻译,因此您的查询一开始不会返回任何内容(甚至不是默认值)

如果翻译不存在,我们的默认为英语,然后回退到代码提供(以防数据库没有 ID,并且从代码中也清楚什么短语标识符“TXT_LNG_WRNNG_INV_LOW”实际上试图获得) - 所以这个查询的等价物是我们使用的:

SELECT COALESCE(localized.translation, phrase.english, @fallback)
FROM DUAL
LEFT JOIN phrase
    ON phrase.phraseid = @phraseid
LEFT JOIN localized
    ON localized.phraseid = phrase.phraseid
    AND localized.localeid = @localeid
Run Code Online (Sandbox Code Playgroud)

显然,您可以使用页面系统一次获得所有内容。

我们倾向于不将内容链接到页面,因为它们在页面之间被重用了很多(不仅仅是在页面片段或控件中),但这当然没问题。

对于我们的 Windows 原生应用程序,我们使用了反射和一个从控件到翻译标签的映射文件,这样翻译就不需要重新编译(在 .NET 之前的应用程序中,我们必须使用标签或其他特殊的标签来标记控件)特性)。这在 PHP 或 ASP.NET MVC 中可能会有点问题,但在 ASP.NET 中可能会有一个完整的服务器端页面模型。

对于测试,您显然可以很容易地查询以找到丢失的翻译。要查找需要标记的地方,请使用 pig-latin 或 Klingon 或类似用 ? - 英语应该脱颖而出,让你知道一些裸露的明文已经悄悄进入你的 HTML。