express.js中的多语言路由?

时间:2012-08-29 21:15:56

标签: node.js express localization

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

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

对此有何建议?

5 个答案:

答案 0 :(得分:7)

我做了以下事情: 安装i18n-node模块并注册快递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);

也许这个帮助。

答案 1 :(得分:6)

我只是直接用检测到的语言提供内容。

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

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

IMO,包括URI中的语言代码是一个丑陋的黑客。 RFC的意图是单个资源(您的主页)通常由单个URI表示。为URI返回的实体可能会根据其他信息(例如语言首选项)而有所不同。

考虑当说德语的用户复制URL并将其发送给讲英语的用户时会发生什么。收件人希望用英语看到您的网站,但由于他收到的链接指向example.com/de/startseite,他会直接使用德语版本。

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

答案 2 :(得分:5)

中间件推荐

@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-node req.getLocale() /en/home的任何控制器访问语言环境。

RFC

@ josh3736推荐的内容肯定符合RFC等。然而,这是许多i18n网站和应用程序的一个相当普遍的要求,甚至Google尊重相同的资源本地化并在不同的网址下提供(可以在网站管理员工具中验证这一点) 。我建议的是在lang代码之后使用相同的别名,例如/de/homearr = [5,6] 等。

答案 3 :(得分:0)

不确定您计划如何组织或共享内容,但您可以使用带有快速路线的正则表达式,然后为不同的模板提供服务。像这样:

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

});

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

答案 4 :(得分:0)

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