【问题标题】:Multi-language routes in express.js?express.js 中的多语言路由?
【发布时间】:2012-08-29 21:15:55
【问题描述】:

我想知道是否有关于如何在 express.js 中实现多语言路由的最佳实践示例。我想使用accept-language 标头来获取浏览器语言,然后自动重定向到相应的语言路径,例如

www.foo.bar/de/startseitewww.foo.bar/en/home

对此有何建议?

【问题讨论】:

    标签: node.js express localization


    【解决方案1】:

    我做了以下事情: 安装 i18n-node 模块并在 express js 中注册。这是代码。

    var express = require('express')
      , routes = require('./routes')
      , http = require('http')
      , i18n = require("i18n");
    
      var app = express();
    
    i18n.configure({
        // setup some locales - other locales default to en silently
        locales:['de', 'en'],
        // disable locale file updates
        updateFiles: false
    });
    
    app.configure(function(){
      ...
      app.use(i18n.init);
      ...
    });
    // register helpers for use in templates
    app.locals({
      __i: i18n.__,
      __n: i18n.__n
    });
    

    在此之后设置以下以获取所有请求

    // invoked before each action
    app.all('*', function(req, res, next) {
        // set locale
        var rxLocal = /^\/(de|en)/i;
        if(rxLocal.test(req.url)){
            var arr = rxLocal.exec(req.url);
            var local=arr[1];
            i18n.setLocale(local);
        } else {
            i18n.setLocale('de');
        }
        // add extra logic
        next();
    });
    
    app.get(/\/(de|en)\/login/i, routes.login);
    

    也许这有帮助。

    【讨论】:

      【解决方案2】:

      我会直接以检测到的语言提供内容。

      例如,example.com/home 在可用的最佳 Accept-Language 中提供主页(如果您在网站本身上提供语言选择选项,可能会被 cookie 覆盖)。

      您需要确保您的回复的 Vary: 标头包含 Accept-Language

      IMO,在 URI 中包含语言代码是一种丑陋的 hack。 RFC 的意图是单个资源(您的主页)普遍由单个 URI 表示。为 URI 返回的实体可能会因其他信息(例如语言首选项)而异。

      考虑当讲德语的用户复制 URL 并将其发送给讲英语的用户时会发生什么。该收件人更愿意以英文查看您的网站,但由于他收到了指向 example.com/de/startseite 的链接,因此他直接访问了德文版本。

      显然,这对于用户在地址栏中看到的内容的完全国际化并不理想(因为 home 是英文),但它更符合 RFC 的意图,而且我' d 认为它对用户更有效,尤其是当链接在电子邮件/社交/其他地方传播时。

      【讨论】:

      • 有点晚了,但是:那么对于多语言支持,您会推荐什么而不是此处作为解决方案提供的内容?
      • 使用 Accept-Language 标头(加上一个 cookie 以允许用户覆盖默认值)。 express-request-language 看起来是一个很好的模块来为你处理这个问题。
      【解决方案3】:

      中间件推荐

      @miro 的答案非常好,但可以在单独文件中的以下中间件中进行改进(正如@ebohlman 建议的那样)。

      中间件

      module.exports = {
        configure: function(app, i18n, config) {
          app.locals.i18n = config;
          i18n.configure(config);
        },
        init: function(req, res, next) {
          var rxLocale = /^\/(\w\w)/i;
          if (rxLocale.test(req.url)){
            var locale = rxLocale.exec(req.url)[1];
            if (req.app.locals.i18n.locales.indexOf(locale) >= 0)
              req.setLocale(locale);
          }
          //else // no need to set the already default
          next();
        },
        url: function(app, url) {
          var locales = app.locals.i18n.locales;
          var urls = [];
          for (var i = 0; i < locales.length; i++)
            urls[i] = '/' + locales[i] + url;
          urls[i] = url;
          return urls;
        }
      };
      

      也在github的示例项目中。

      说明

      中间件具有三个功能。第一个是配置i18n-node的小帮手,还将设置保存在app.locals中(还没有弄清楚如何从i18n-node本身访问设置)。

      主要的是第二个,它从 url 中获取语言环境并将其设置在请求对象中。

      最后一个是帮助器,对于给定的 url,它返回一个包含所有可能语言环境的数组。例如用'/about' 调用它,我们会得到['/en/about', ..., '/about']

      如何使用

      app.js:

      // include
      var i18n = require('i18n');
      var services = require('./services');
      
      // configure
      services.i18nUrls.configure(app, i18n, {
        locales: ['el', 'en'],
        defaultLocale: 'el'
      });
      
      // add middleware after static
      app.use(services.i18nUrls.init);
      
      // router
      app.use(services.i18nUrls.url(app, '/'), routes);
      

      Github link

      可以从任何具有i18n-nodereq.getLocale() 的控制器访问区域设置。

      RFC

      @josh3736 推荐的内容肯定符合 RFC 等。尽管如此,这对于许多 i18n 网站和应用程序来说是相当普遍的要求,甚至 Google 也尊重本地化并在不同 url 下提供的相同资源(可以在网站管理员工具中验证这一点) .不过我建议在 lang 代码后使用相同的别名,例如 /en/home/de/home 等。

      【讨论】:

        【解决方案4】:

        不确定您计划如何组织或共享内容,但您可以将正则表达式与快速路由一起使用,然后提供不同的模板。像这样的:

        app.get(/^\/(startseite|home)$/, function(req, res){
        
        });
        

        我做的一件事是用子域组织我的内容,然后使用中间件从基于拆分 url 的数据库中获取内容,但它们都共享相同的路由和模板。

        【讨论】:

          【解决方案5】:

          编写一个中间件函数,解析任何“Accept-Language”标头,并将请求级局部变量设置为具有默认值(如“en”)的适当代码(如两个字母的语言代码)(如果有)没有这样的标题,或者您不支持列出的任何语言。在您的路线中,检索本地并将其附加到任何模板文件名上,如果除了模板选择之外还有任何与语言相关的处理,则在其上进行分支。

          【讨论】:

            猜你喜欢
            • 2018-01-26
            • 2015-04-12
            • 2013-12-19
            • 1970-01-01
            • 2013-09-13
            • 2017-10-09
            • 1970-01-01
            • 1970-01-01
            • 2011-08-17
            相关资源
            最近更新 更多