几个月来我一直在为这个问题苦苦挣扎,但我之前没有遇到过需要探索所有可能选择的情况。现在,我觉得是时候了解这些可能性并创建我自己的个人偏好,以便在我即将进行的项目中使用。
让我先勾勒一下我正在寻找的情况
我即将升级/重新开发我已经使用了很长一段时间的内容管理系统。但是,我觉得多语言是对这个系统的一个很大的改进。在我没有使用任何框架之前,我将在即将到来的项目中使用 Laraval4。 Laravel 似乎是一种更简洁的 PHP 编码方式的最佳选择。 Sidenote: Laraval4 should be no factor in your answer
。我正在寻找独立于平台/框架的通用翻译方式。
应该翻译什么
由于我正在寻找的系统需要尽可能用户友好,因此管理翻译的方法应该在 CMS 内部。应该不需要启动 FTP 连接来修改翻译文件或任何 html/php 解析的模板。
此外,我正在寻找翻译多个数据库表的最简单方法,也许不需要制作额外的表。
我自己想出了什么
正如我自己一直在搜索、阅读和尝试的那样。我有几个选择。但我仍然不觉得我已经达到了我真正寻求的最佳实践方法。现在,这是我想出的,但这种方法也有副作用。
- PHP Parsed Templates : 模板系统应该被 PHP 解析。这样我就可以将翻译后的参数插入到 HTML 中,而无需打开模板并修改它们。除此之外,PHP 解析的模板使我能够为完整的网站拥有 1 个模板,而不是为每种语言(我以前有过)拥有一个子文件夹。达到这个目标的方法可以是 Smarty、TemplatePower、Laravel’s Blade 或任何其他模板解析器。正如我所说,这应该独立于书面解决方案。
- 数据库驱动:也许我不需要再提这个了。但解决方案应该是数据库驱动的。 CMS 的目标是面向对象和 MVC,所以我需要考虑字符串的逻辑数据结构。由于我的模板是结构化的:templates/Controller/View.php 也许这种结构最有意义:
Controller.View.parameter
。数据库表将包含这些字段,并带有value
字段。在模板中,我们可以使用某种排序方法,例如echo __('Controller.View.welcome', array('name', 'Joshua'))
并且参数包含Welcome, :name
。因此结果是Welcome, Joshua
。这似乎是一个很好的方法,因为 :name 等参数很容易被编辑器理解。 - 低数据库负载:当然,如果在旅途中加载这些字符串,上述系统会导致数据库负载负载。因此,我需要一个缓存系统,一旦语言文件在管理环境中被编辑/保存,就会重新呈现它们。因为文件是生成的,所以还需要一个好的文件系统布局。我想我们可以使用
languages/en_EN/Controller/View.php
或 .ini,无论哪种最适合您。也许.ini 最终会被更快地解析。这个犯规应该包含format parameter=value;
中的数据。我想这是最好的方法,因为渲染的每个视图都可以包含它自己的语言文件(如果存在)。然后应该将语言参数加载到特定视图而不是全局范围内,以防止参数相互覆盖。 - 数据库表翻译:这其实是我最担心的事情。我正在寻找一种方法来创建新闻/页面/等的翻译。尽快。每个模块有两个表(例如
News
和News_translations
)是一种选择,但感觉要获得一个好的系统需要做很多工作。我想出的一件事是基于我写的一个data versioning
系统:有一个数据库表名Translations
,这个表有一个独特的组合language
,tablename
和primarykey
。例如:en_En / News / 1(指的是英文版的 ID=1 的 News 条目)。但是这种方法有两个巨大的缺点:首先,由于数据库中有大量数据,该表往往会变得很长,其次,使用这种设置来搜索表将是一项艰巨的工作。例如,搜索该项目的 SEO slug 将是一个全文搜索,这非常愚蠢。但另一方面:这是在每个表格中非常快速地创建可翻译内容的快速方法,但我不相信这个专业人士超过了骗局。 - 前端工作:前端也需要一些思考。当然,我们会将可用的语言存储在数据库中,并(停用)我们需要的语言。这样,脚本可以生成一个下拉菜单来选择一种语言,并且后端可以自动决定使用 CMS 可以进行哪些翻译。然后,在获取语言文件以供查看或获取网站上内容项的正确翻译时,将使用所选语言(例如 en_EN)。
所以,他们在那里。到目前为止我的想法。它们甚至还不包括日期等的本地化选项,但由于我的服务器支持 PHP5.3.2+,因此最好的选择是使用 intl 扩展,如下所述:http: //devzone.zend.com/1500/internationalization-in -php-53/ - 但这将在以后的任何开发体育场中使用。目前的主要问题是如何对网站内容进行最佳翻译。
除了我在这里解释的一切,我还有一件事我还没有决定,这看起来是一个简单的问题,但实际上它让我很头疼:
网址翻译?我们应该这样做还是不这样做?以什么方式?
所以..如果我有这个网址: http://www.domain.com/about-us
英语是我的默认语言。当我选择荷兰语作为我的语言时,这个 URL 是否应该翻译成 http://www.domain.com/over-ons
?或者我们应该走简单的路,简单地更改在 /about
处可见的页面内容。最后一件事似乎不是一个有效的选项,因为这会生成同一个 URL 的多个版本,这种索引内容将以正确的方式失败。
另一种选择是使用 http://www.domain.com/nl/about-us
代替。这至少会为每个内容生成一个唯一的 URL。此外,使用另一种语言会更容易,例如 http://www.domain.com/en/about-us
并且所提供的 URL 对于 Google 和人类访问者来说更容易理解。使用此选项,我们如何处理默认语言?默认语言是否应该删除默认选择的语言?因此,将 http://www.domain.com/en/about-us
重定向到 http://www.domain.com/about-us
…在我看来,这是最好的解决方案,因为当 CMS 仅设置为一种语言时,无需在网址。
第三个选项是两个选项的组合:对主要语言使用“language-identification-less”-URL ( http://www.domain.com/about-us
)。并使用带有翻译的 SEO slug 的 URL 用于子语言: http://www.domain.com/nl/over-ons
& http://www.domain.com/de/uber-uns
我希望我的问题能引起您的注意,他们肯定会解决我的问题!它确实帮助我在这里解决问题。让我有机会回顾我以前使用过的方法以及我为即将推出的 CMS 的想法。
我要感谢你花时间阅读这堆文字!
// Edit #1
:
我忘了提:__() 函数是翻译给定字符串的别名。在这个方法中,显然应该有某种后备方法,当还没有可用的翻译时加载默认文本。如果缺少翻译,则应将其插入或重新生成翻译文件。
原文由 Joshua - Pendo 发布,翻译遵循 CC BY-SA 4.0 许可协议
题目的前提
多语言网站具有三个不同的方面:
虽然它们都以不同的方式相互连接,但从 CMS 的角度来看,它们使用不同的 UI 元素进行管理并以不同的方式存储。您似乎对前两个的实施和理解充满信心。问题是关于后者—— “URL 翻译?我们应该这样做还是不这样做?以什么方式?”
URL 可以由什么组成?
一件非常重要的事情是,不要对 IDN 有好感。而是倾向于 音译(也:转录和罗马化)。虽然乍一看 IDN 似乎是国际 URL 的可行选择,但它实际上并不像宣传的那样工作,原因有两个:
'ч'
或'ž'
转换为'%D1%87'
和'%C5%BE'
几年前,我实际上在一个基于 Yii 的项目中尝试了 IDN 方法(可怕的框架,恕我直言)。在抓取该解决方案之前,我遇到了上述两个问题。另外,我怀疑它可能是一个攻击媒介。
可用选项…正如我所见。
基本上你有两个选择,可以抽象为:
http://site.tld/[:query]
:[:query]
决定语言和内容选择http://site.tld/[:language]/[:query]
:其中[:language]
URL 的一部分定义了语言的选择,而[:query]
仅用于识别内容查询是 Α 和 Ω ..
假设您选择
http://site.tld/[:query]
。在这种情况下,您有一个主要的语言来源:
[:query]
段的内容;和两个额外的来源:$_COOKIE['lang']
首先,您需要将查询与定义的路由模式之一匹配(如果您选择 Laravel, 请阅读此处)。成功匹配模式后,您需要找到语言。
您必须遍历模式的所有部分。找到所有这些句段的潜在翻译,并确定使用了哪种语言。两个额外的来源(cookie 和标头)将用于解决路由冲突,当(不是“如果”)它们出现时。
举个例子:
http://site.tld/blog/novinka
。那是
"блог, новинка"
的音译,在英语中大约是"blog", "latest"
的意思。正如您已经注意到的那样,俄语中的“блог”将被音译为“博客”。这意味着对于
[:query]
的第一部分,您(在 _最好的情况下_)最终会得到['en', 'ru']
可能的语言列表。然后你采取下一段 - “novinka”。在可能性列表中可能只有一种语言:['ru']
。当列表中有一项时,您已成功找到该语言。
但是,如果您最终得到 2 个(例如:俄语和乌克兰语)或更多可能性 .. 或 0 个可能性,视情况而定。您必须使用 cookie 和/或标头来找到正确的选项。
如果一切都失败了,您选择网站的默认语言。
语言作为参数
另一种方法是使用 URL,它可以定义为
http://site.tld/[:language]/[:query]
。在这种情况下,翻译查询时,您无需猜测语言,因为此时您已经知道要使用哪种语言。还有第二个语言来源:cookie 值。但是这里没有必要弄乱 Accept-Language 标头,因为在“冷启动”(当用户第一次使用自定义查询打开网站时)的情况下,您不会处理未知数量的可能语言。
相反,您有 3 个简单的优先选项:
[:language]
段,使用它$_COOKIE['lang']
,使用它当您拥有该语言时,您只需尝试翻译查询,如果翻译失败,则使用该特定段的“默认值”(基于路由结果)。
这不是第三种选择吗?
是的,从技术上讲,您可以结合使用这两种方法,但这会使过程复杂化,并且仅适用于想要手动将
http://site.tld/en/news
的 URL 更改为http://site.tld/de/news
并希望新闻页面更改为德语的人.但即使是这种情况,也可以使用 cookie 值(其中包含有关先前选择的语言的信息)来缓解这种情况,从而以更少的魔力和希望来实现。
使用哪种方法?
正如您可能已经猜到的那样,我会推荐
http://site.tld/[:language]/[:query]
作为更明智的选择。同样在真实的情况下,您将在 URL 中有第三个主要部分:“标题”。如在线商店中的产品名称或新闻网站中的文章标题。
示例:
http://site.tld/en/news/article/121415/EU-as-global-reserve-currency
在这种情况下
'/news/article/121415'
将是查询,而'EU-as-global-reserve-currency'
是标题。纯粹出于 SEO 目的。可以在 Laravel 中完成吗?
有点,但不是默认的。
我对它不是很熟悉,但是据我所见,Laravel 使用了简单的基于模式的路由机制。要实现多语言 URL,您可能必须 扩展核心类,因为多语言路由需要访问不同形式的存储(数据库、缓存和/或配置文件)。
是路由的。现在怎么办?
结果,您最终会得到两条有价值的信息:当前语言和已翻译的查询段。然后这些值可用于分派给将产生结果的类。
基本上,以下 URL:
http://site.tld/ru/blog/novinka
(或没有'/ru'
的版本)变成了类似的东西您仅用于调度:
..或它的一些变体,取决于特定的实现。