koa 中的本地化路由
Localized routes in koa
我正在开发一个多语言网站。因此,一些路线也必须本地化,我不确定如何正确地做到这一点。
我正在使用 @koa/router
进行路由。
对于此示例,它只有英语和瑞典语,但该站点将处理更多语言。
我可以设置路由来匹配不同语言的单词,例如
router.get('/(create-account|skapa-konto)/', (ctx, next) => {
ctx.body = translate('signup_welcome');
await next();
});
但是,我希望英文站点只响应“/sign-up”并为“/skapa-konto”发送 404(反之亦然)。
在现实世界中,路由会指向某个控制器函数。因此,如果我为每种语言设置单独的路由,如果将来控制器功能发生变化,我将不得不手动更改所有本地化路由。这是我想避免的事情 ;)
有什么建议吗?
我对这个问题很感兴趣,所以我用一些代码创建了一个小型 github 存储库。我将在这里尝试解释:
我用一些选项创建了一个数组:
const localeConfig = [
{
locale: "en",
routes: [
{
path: "/sign-up",
controllers: [enController],
method: "GET",
},
],
prefix: false,
},
{
locale: "se",
routes: [
{
path: "/skapa-konto",
controllers: [seController],
method: "GET",
},
],
prefix: false,
},
];
然后我将此对象传递给 setupRoutes 函数,该函数基本上迭代数组,根据这些选项生成所有路由。
const setupRoutes = (localeConfig) => {
// Have some check to prevent duplicate routes
localeConfig.forEach((opt) => {
// Adding prefix according to option
const localePrefix = opt.prefix ? `/${opt.locale}` : "";
opt.routes.forEach((route) => {
const path = `${localePrefix}${route.path}`;
router[route.method.toLowerCase()].apply(router, [
path,
...route.controllers,
]);
});
});
};
因此,例如,如果您要更改任何一种语言的控制器,您只需要更新特定的语言环境 object.route.controllers
。我想您甚至可以将每个不同的区域设置放在不同的文件中以具有一定的模块化。
github 存储库是 here,如果您对如何改进它有任何想法,我真的很希望您能为它做出贡献。
干杯!
我最终通过像这样扩展路由器解决了这个问题:
const LocalizedRouter = class extends Router {
/**
* Set up route mapping
* @param {object} options
*/
constructor(options) {
if (!Array.isArray(options.languages)) {
throw new TypeError('Languages must be of type Array');
}
super(options);
this.languages = options.languages;
}
/**
* Router function for GET method
* @param {string | Object<string, string>} RouteCollection
*/
get(routes, func) {
if (typeof(routes) === 'string') {
super.get(routes, func);
return;
}
if (typeof(routes) === 'object') {
for(const key in routes) {
if(!this.languages.includes(key)) {
continue;
}
if(typeof(func) !== 'function') {
throw new TypeError('Middleware must be a function');
}
const checkLanguageAndMount = async (ctx, next) => {
if(ctx.state.lang !== key) {
return next();
}
return func(ctx, next);
};
super.get(routes[key], checkLanguageAndMount);
}
return;
}
throw new TypeError('"Routes" must be a string or an object');
}
};
然后我可以像这样设置我的路线:
const myRouter = new LocalizedRouter({
languages: ['en', 'sv']
});
myRouter.get({
'en': '/create-account',
'sv': '/skapa-konto'
}, (ctx, next) => {
ctx.body = translate('signup_welcome');
await next();
};
这可能会被清理干净,但它确实解决了我想做的事情。
编辑:修复了如果两种语言具有相同路径则导致 404 的错误
我正在开发一个多语言网站。因此,一些路线也必须本地化,我不确定如何正确地做到这一点。
我正在使用 @koa/router
进行路由。
对于此示例,它只有英语和瑞典语,但该站点将处理更多语言。
我可以设置路由来匹配不同语言的单词,例如
router.get('/(create-account|skapa-konto)/', (ctx, next) => {
ctx.body = translate('signup_welcome');
await next();
});
但是,我希望英文站点只响应“/sign-up”并为“/skapa-konto”发送 404(反之亦然)。
在现实世界中,路由会指向某个控制器函数。因此,如果我为每种语言设置单独的路由,如果将来控制器功能发生变化,我将不得不手动更改所有本地化路由。这是我想避免的事情 ;)
有什么建议吗?
我对这个问题很感兴趣,所以我用一些代码创建了一个小型 github 存储库。我将在这里尝试解释:
我用一些选项创建了一个数组:
const localeConfig = [
{
locale: "en",
routes: [
{
path: "/sign-up",
controllers: [enController],
method: "GET",
},
],
prefix: false,
},
{
locale: "se",
routes: [
{
path: "/skapa-konto",
controllers: [seController],
method: "GET",
},
],
prefix: false,
},
];
然后我将此对象传递给 setupRoutes 函数,该函数基本上迭代数组,根据这些选项生成所有路由。
const setupRoutes = (localeConfig) => {
// Have some check to prevent duplicate routes
localeConfig.forEach((opt) => {
// Adding prefix according to option
const localePrefix = opt.prefix ? `/${opt.locale}` : "";
opt.routes.forEach((route) => {
const path = `${localePrefix}${route.path}`;
router[route.method.toLowerCase()].apply(router, [
path,
...route.controllers,
]);
});
});
};
因此,例如,如果您要更改任何一种语言的控制器,您只需要更新特定的语言环境 object.route.controllers
。我想您甚至可以将每个不同的区域设置放在不同的文件中以具有一定的模块化。
github 存储库是 here,如果您对如何改进它有任何想法,我真的很希望您能为它做出贡献。
干杯!
我最终通过像这样扩展路由器解决了这个问题:
const LocalizedRouter = class extends Router {
/**
* Set up route mapping
* @param {object} options
*/
constructor(options) {
if (!Array.isArray(options.languages)) {
throw new TypeError('Languages must be of type Array');
}
super(options);
this.languages = options.languages;
}
/**
* Router function for GET method
* @param {string | Object<string, string>} RouteCollection
*/
get(routes, func) {
if (typeof(routes) === 'string') {
super.get(routes, func);
return;
}
if (typeof(routes) === 'object') {
for(const key in routes) {
if(!this.languages.includes(key)) {
continue;
}
if(typeof(func) !== 'function') {
throw new TypeError('Middleware must be a function');
}
const checkLanguageAndMount = async (ctx, next) => {
if(ctx.state.lang !== key) {
return next();
}
return func(ctx, next);
};
super.get(routes[key], checkLanguageAndMount);
}
return;
}
throw new TypeError('"Routes" must be a string or an object');
}
};
然后我可以像这样设置我的路线:
const myRouter = new LocalizedRouter({
languages: ['en', 'sv']
});
myRouter.get({
'en': '/create-account',
'sv': '/skapa-konto'
}, (ctx, next) => {
ctx.body = translate('signup_welcome');
await next();
};
这可能会被清理干净,但它确实解决了我想做的事情。
编辑:修复了如果两种语言具有相同路径则导致 404 的错误