php - 最佳实践多语言网站

标签 php mysql localization internationalization multilingual

几个月来,我一直在为这个问题苦苦挣扎,但我以前从未遇到过需要探索所有可能选项的情况。现在,我觉得是时候了解可能性并创建我自己的个人偏好以在我即将进行的项目中使用。

让我先勾勒一下我正在寻找的情况

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

应该怎么翻译

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

此外,我正在寻找最简单的方法来转换多个数据库表,而无需制作额外的表。

我是怎么想出来的

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

  • PHP 解析模板 : 模板系统应该由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; 中的数据
    .我想这是最好的方法,因为渲染的每个 View 都可以包含它自己的语言文件(如果存在)。然后应该将语言参数加载到特定 View 而不是全局范围内,以防止参数相互覆盖。
  • 数据库表翻译 : 这其实是我最担心的。我正在寻找一种方法来创建新闻/页面/等的翻译。尽快。每个模块有两个表(例如 NewsNews_translations )是一种选择,但感觉要获得一个好的系统需要做很多工作。我想出的一件事是基于 data versioning系统我写道:有一个数据库表名Translations ,这张表有language的独特组合, tablenameprimarykey .例如:en_En/News/1(指ID=1的英文版News item)。但是这种方法有两个巨大的缺点:首先,由于数据库中有大量数据,这个表往往会变得很长,其次,使用这种设置来搜索表将是一项艰巨的工作。例如搜索该项目的 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-ushttp://www.domain.com/about-us ...在我看来,这是最好的解决方案,因为当 CMS 仅针对一种语言设置时,URL 中不需要此语言标识。

    第三个选项是两个选项的组合:使用“无语言标识”-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 :

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

    最佳答案

    话题的前提
    多语言站点具有三个不同的方面:

  • 界面翻译
  • 内容
  • url路由

  • 虽然它们都以不同的方式互连,但从 CMS 的角度来看,它们使用不同的 UI 元素进行管理并以不同的方式存储。您似乎对前两个的实现和理解充满信心。问题是关于后一方面——“URL 翻译?我们应该这样做还是不这样做?以什么方式?”
    URL 可以由什么组成?
    很重要的一点是,不要迷恋IDN .反而青睐 transliteration (也:转录和罗马化)。虽然乍一看 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] 的内容段;以及另外两个来源:
  • 值(value) $_COOKIE['lang']对于那个特定的浏览器
  • HTTP Accept-Language 中的语言列表 (1) , (2)标题

  • 首先,您需要将查询与定义的路由模式之一匹配(如果您选择的是 Laravel,则为 read here)。成功匹配模式后,您需要找到语言。
    您必须遍历模式的所有部分。找到所有这些段的潜在翻译并确定使用的是哪种语言。两个额外的来源(cookie 和 header )将用于解决路由冲突,当(不是“如果”)它们出现时。
    举个例子:http://site.tld/blog/novinka .
    那是"блог, новинка"的音译,在英语中的意思大约是 "blog", "latest" .
    正如您已经注意到的,在俄语中,“блог”将被音译为“博客”。这意味着对于 [:query] 的第一部分你(在最好的情况下)最终会得到 ['en', 'ru']可能的语言列表。然后你选择下一个部分 - “novinka”。在可能性列表中可能只有一种语言:['ru'] .
    当列表中有一项时,您已成功找到该语言。
    但是,如果您最终得到 2 个(例如:俄语和乌克兰语)或更多的可能性......或 0 个可能性,视情况而定。您将不得不使用 cookie 和/或标题来找到正确的选项。
    如果所有其他方法都失败了,您可以选择站点的默认语言。
    语言作为参数
    另一种方法是使用 URL,可以定义为 http://site.tld/[:language]/[:query] .在这种情况下,在翻译查询时,您无需猜测语言,因为那时您已经知道要使用哪种语言了。
    还有一个次要的语言来源:cookie 值。但是这里没有必要弄乱 Accept-Language header ,因为在“冷启动”(当用户第一次使用自定义查询打开站点时)的情况下,您没有处理未知数量的可能语言。
    相反,您有 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,您可能必须extend core class(es) ,因为多语言路由需要访问不同形式的存储(数据库、缓存和/或配置文件)。
    路由了现在怎么办?
    由于所有这些,您最终会得到两条有值(value)的信息:当前语言和已翻译的查询段。然后,这些值可用于分派(dispatch)到将产生结果的类。
    基本上,以下网址:http://site.tld/ru/blog/novinka (或没有 '/ru' 的版本)变成了类似的东西
    $parameters = [
       'language' => 'ru',
       'classname' => 'blog',
       'method' => 'latest',
    ];
    
    您仅用于分派(dispatch):
    $instance = new {$parameter['classname']};
    $instance->{'get'.$parameters['method']}( $parameters );
    
    .. 或者它的一些变体,取决于特定的实现。

    关于php - 最佳实践多语言网站,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19249159/

    相关文章:

    php - 如何从多个下拉列表创建 OR mySQL 查询?

    ios - 在本地化的 xib 文件中无法识别非本地化图像

    asp.net-mvc - 如何本地化 ASP.NET MVC 应用程序?

    php - Codeigniter:查询在 select/like 语句中返回表中的所有行

    mysql - 当使用与控件交互时动态显示搜索结果

    mysql - MS Access 通配符不适用于 MySQL 后端

    python - Python/Django 数据库本地化(多语言)设计

    php - header 显示在 apache 错误日志中(curl 和 paypal)

    php - foreach 访问索引或关联数组

    php - 在 php 的下拉菜单中保存所选选项