express.js中的多语言路由?

我想知道如何在express.js中实现多语言路由的最佳实践示例。 我想使用accept-language头来获得浏览器语言,然后自动redirect到相应的语言路线

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

对此有何build议?

我做了以下事情:安装i18n节点模块和registry达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); 

也许这个帮助。

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

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

你要确保你的回应的Vary:头包括Accept-Language

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

考虑一下当讲德语的用户复制一个URL并将其发送给说英语的用户时会发生什么情况。 那个收件人宁愿用英文来看你的网站,但是因为他收到了一个指向example.com/de/startseite的链接,他直接去了德文版本。

显然,这对于用户在地址栏中看到的全部国际化并不理想(因为家庭是英语),但它更符合RFC的意图,我认为它对用户更好,尤其是链接散布在电子邮件/社交/无论什么。

中间件推荐

@miro的答案非常好,但可以像下面的中间件一样在单独的文件中进行改进(就像@ebohlman所build议的那样)。

中间件

 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的示例项目中。

说明

中间件有三个function。 第一个是configurationi18n-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链接

语言环境可以通过任何具有i18n-nodereq.getLocale()控制器来访问。

RFC

Josh3736推荐的方法肯定符合RFC等规范。然而,对于许多国际化的网站和应用来说,这是一个相当常见的要求,甚至Google也尊重本地化和服务于不同URL的相同资源(可以通过网站pipe理员工具进行validation)。 我所推荐的是在lang代码之后有相同的别名,例如/en/home/de/home

不知道你如何组织或共享内容的计划,但你可以使用正则expression式与快递路线,然后服务器上不同的模板。 像这样的东西:

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

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

编写一个中间件函数,parsing任何“Accept-Language”头文件,并在没有这样的头文件的情况下将请求级别的本地variables设置为具有默认值(如“en”)的适当代码(如双字母语言代码)或者您不支持列出的任何语言。 在您的路线中,检索本地并将其粘贴到任何模板文件名称上,如果除了模板select以外还有任何语言相关的处理,则在该文件上进行分支。