一尘不染

最佳实践多语言网站

mysql

我已经在这个问题上苦苦挣扎了好几个月了,但是以前我从来没有需要探索所有可能的选择的情况。现在,我觉得该是时候了解各种可能性并创建自己的个人喜好了,以便在我即将进行的项目中使用。

首先让我勾勒出我要寻找的情况

我将要升级/重新开发已经使用了一段时间的内容管理系统。但是,我觉得多语言是对该系统的巨大改进。在我没有使用任何框架之前,我将在即将到来的项目中使用Laraval4。Laravel似乎是更干净的PHP编码方式的最佳选择。Sidenote: Laraval4 should be no factor in your answer。我正在寻找独立于平台/框架的一般翻译方式。

应该翻译什么

由于我正在寻找的系统需要尽可能地方便用户使用,因此管理翻译的方法应在CMS内部。无需启动FTP连接即可修改翻译文件或任何html / php解析的模板。

此外,我正在寻找最简单的方法来转换多个数据库表,而无需创建其他表。

我自己想到了什么

我一直在寻找,阅读和尝试自己的东西。我有两个选择。但是我仍然不觉得自己已经达到了我真正追求的最佳实践方法。现在,这是我想出的,但是这种方法也有副作用。

  1. PHP解析模板 :模板系统应由PHP解析。这样,我就可以将转换后的参数插入HTML中,而不必打开模板并进行修改。除此之外,PHP解析的模板使我能够为整个网站使用1个模板,而不必为每种语言都拥有一个子文件夹(这是我以前使用过的)。达到此目标的方法可以是Smarty,TemplatePower,Laravel’s Blade或任何其他模板解析器。正如我所说,这应独立于书面解决方案。
  2. 数据库驱动的 :也许我不需要再次提及。但是解决方案应该是数据库驱动的。CMS的目标是面向对象和MVC,所以我需要考虑字符串的逻辑数据结构。正如我的模板将被结构化:模板/控制器/ View.php也许这一结构将最有意义:Controller.View.parameter。数据库表将这些字段与字段长在一起value。在模板内部,我们可以使用某种排序方法,例如echo __('Controller.View.welcome', array('name', 'Joshua'))和参数contains Welcome, :name。因此结果是Welcome, Joshua。这似乎是个好方法,因为编辑器很容易理解诸如:name之类的参数。
  3. 数据库负载低 :如果在旅途中加载这些字符串,上述系统当然会导致数据库负载。因此,我需要一个缓存系统,以便在管理环境中对语言文件进行编辑/保存后立即重新呈现它们。由于生成了文件,因此还需要一个良好的文件系统布局。我猜我们可以选择languages/en_EN/Controller/View.php最适合的是.ini或.ini。最终,.ini文件甚至可能被更快地解析。该数据应包含中的数据format parameter=value; 。我猜这是最好的方法,因为渲染的每个View都可以包含它自己的语言文件(如果存在)。然后,应将语言参数加载到特定视图,而不是在全局范围内加载,以防止参数相互覆盖。
  4. 数据库表翻译 :实际上,这是我最担心的事情。我正在寻找一种创建News / Pages / etc的翻译的方法。尽快。每个模块都有两个表(例如NewsNews_translations)是一个选项,但是要获得一个好的系统感觉很费劲。有一个问题我想出了是基于对事物data versioning系统我写的:有一个数据库表名Translations,这个表有一个独特的组合languagetablenameprimarykey。例如:en_En / News / 1(请参阅ID为1的News项目的英文版本)。但是此方法有两个巨大的缺点:首先,该表往往会在数据库中存储大量数据时变得相当长,其次,使用此设置来搜索表将是一件艰巨的工作。例如,搜索该项目的SEO标记将是全文搜索,这是相当愚蠢的。但是,另一方面:这是一种非常快速地在每个表中创建可翻译内容的快速方法,但是我认为这不会增加缺点。
  5. 前端工作 :前端也需要一些思考。当然,我们会将可用的语言存储在数据库中,并停用所需的语言。这样,脚本可以生成一个下拉菜单来选择一种语言,后端可以自动决定可以使用CMS进行哪些翻译。然后,在获取视图的语言文件或为网站上的内容项获取正确的翻译时,将使用所选的语言(例如en_EN)。

因此,它们在那里。到目前为止,我的想法。它们甚至还不包括日期等的本地化选项,但是由于我的服务器支持PHP5.3.2
+,因此最好的选择是使用国际扩展名,如此处所述:http ://devzone.zend.com/1500/internationalization-in -php-53
/

-但这将在以后的开发中使用。目前,主要问题是如何拥有网站内容翻译的最佳实践。

除了我在这里解释的所有内容之外,我还有另一件事尚未决定,它看起来像一个简单的问题,但实际上,这让我头疼:

网址翻译? 我们应该这样做吗?又以什么方式?

所以..如果我有这个网址:http://www.domain.com/about- us且英语是我的默认语言。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- ushttp://www.domain.com/about- us…在我看来,这是最好的解决方案,因为当仅针对一种语言设置CMS时,无需在URL中使用此语言标识。

第三个选项是这两个选项的组合:http://www.domain.com/about-us对主要语言使用“无语言标识”
-URL()。并将带有翻译后的SEO代码的URL用于子语言:http://www.domain.com/nl/over- onshttp://www.domain.com/de/uber-uns

希望我的问题能引起您的注意,他们肯定能破解我的问题!它确实帮助我在这里解决问题。让我可以回顾一下以前使用过的方法以及即将推出的CMS所具有的想法。

我已经非常感谢您抽出宝贵的时间阅读这些文本!

// Edit #1

我忘了提到:__()函数是翻译给定字符串的别名。在此方法中,显然应该有某种后备方法,当尚无翻译可用时,将加载默认文本。如果缺少翻译,则应插入翻译或重新生成翻译文件。


阅读 209

收藏
2020-05-17

共1个答案

一尘不染

主题前提

多语言站点包含三个不同方面:

  • 界面翻译
  • 内容
  • 网址路由

尽管它们都以不同的方式互连,但是从CMS的角度来看,它们是使用不同的UI元素进行管理的,并且存储方式也不同。您似乎对自己的实现和对前两个的理解充满信心。问题是关于后一个方面的问题:
“ URL转换?我们应该这样做吗?应该以什么方式进行?”

URL可以由什么组成?

一个非常重要的事情是,不要对IDN感兴趣。取而代之的是支持音译(也:转录和罗马化)。乍一看,IDN似乎是国际URL的可行选择,但实际上,它不能按广告宣传工作,原因有两个:

  • 某些浏览器会将非ASCII字符(例如'ч'或)'ž'转换为'%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']该特定浏览器的价值
  • HTTP Accept-Language (1)(2)标头中的语言列表

首先,您需要将查询与定义的路由模式之一进行匹配(如果您选择的是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个简单的优先选项:

  1. 如果[:language]设置了细分,请使用它
  2. 如果$_COOKIE['lang']设置,使用它
  3. 使用默认语言

使用该语言时,您只需尝试翻译查询,如果翻译失败,请对该特定段使用“默认值”(基于路由结果)。

这不是第三种选择吗?

是的,从技术上讲,您可以将两种方法结合使用,但这会使过程复杂化,并且只适合那些想要手动更改URL
http://site.tld/en/newshttp://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中完成吗?

Kinda,但默认情况下不是。

我不太熟悉它,但是据我所知,Laravel使用简单的基于模式的路由机制。要实现多语言URL,您可能必须扩展核心类,因为多语言路由需要访问不同形式的存储(数据库,缓存和/或配置文件)。

已路由。现在怎么办?

结果,您最终将获得两条有价值的信息:当前语言和查询的翻译段。然后,这些值可用于调度将产生结果的类。

基本上,以下网址:(http://site.tld/ru/blog/novinka或不含的版本'/ru')变成了类似

$parameters = [
   'language' => 'ru',
   'classname' => 'blog',
   'method' => 'latest',
];

您仅用于调度的对象:

$instance = new {$parameter['classname']};
$instance->{'get'.$parameters['method']}( $parameters );

..或它的某些变体,具体取决于特定的实现。

2020-05-17