feat: Support nested locale keys.
Example: ```js { model: { user: { name: 'Real Name', createdAt: 'Joined At' } } } ``` ```js ctx.__('model.user.name'); ctx.__('model.user.createdAt'); ``` The before: ```js { 'model.user.name': 'Real Name', 'model.user.createdAt', 'Joined At' } ``` Benchmarks: ``` Deeps: 9 2 tests completed. direct read a key x 85,993,593 ops/sec ±1.89% (96 runs sampled) by nested x 4,203,837 ops/sec ±0.98% (93 runs sampled) ```master
parent
1c347630f1
commit
58324a11ff
|
@ -21,7 +21,7 @@ koa-locales
|
|||
koa locales, i18n solution for koa:
|
||||
|
||||
1. All locales resources location on `options.dir`.
|
||||
2. resources file supports: `*.js`, `*.json` and `*.properties`
|
||||
2. resources file supports: `*.js`, `*.json` and `*.properties`, [examples](https://github.com/koajs/locales/tree/master/test/locales)
|
||||
3. One api: `__(key[, value, ...])`
|
||||
4. Auto detect request locale from `query`, `cookie` and `header: Accept-Language`
|
||||
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
var Benchmark = require('benchmark');
|
||||
var benchmarks = require('beautify-benchmark');
|
||||
|
||||
var suite = new Benchmark.Suite();
|
||||
|
||||
function getNestedValue(data, key) {
|
||||
var keys = key.split('.');
|
||||
for (var i = 0; typeof data === 'object' && i < keys.length; i++) {
|
||||
data = data[keys[i]];
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
var resource = {
|
||||
'model.user.foo.bar.aa': 'Hello',
|
||||
model: {
|
||||
user: {
|
||||
fields: {
|
||||
name: 'Real Name',
|
||||
age: 'Age',
|
||||
a: {
|
||||
b: {
|
||||
c: {
|
||||
d: {
|
||||
e: {
|
||||
f: "fff"
|
||||
}
|
||||
},
|
||||
model: {
|
||||
user: {
|
||||
fields: {
|
||||
name: 'Real Name',
|
||||
age: 'Age',
|
||||
a: {
|
||||
b: {
|
||||
c: {
|
||||
d: {
|
||||
e: {
|
||||
f: "fff"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
post: {
|
||||
fields: {
|
||||
title: 'Subject'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
model: {
|
||||
user: {
|
||||
fields: {
|
||||
name: 'Real Name',
|
||||
age: 'Age',
|
||||
a: {
|
||||
b: {
|
||||
c: {
|
||||
d: {
|
||||
e: {
|
||||
f: "fff"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
post: {
|
||||
fields: {
|
||||
title: 'Subject'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
post: {
|
||||
fields: {
|
||||
title: 'Subject'
|
||||
}
|
||||
},
|
||||
model: {
|
||||
user: {
|
||||
fields: {
|
||||
name: 'Real Name',
|
||||
age: 'Age',
|
||||
a: {
|
||||
b: {
|
||||
c: {
|
||||
d: {
|
||||
e: {
|
||||
f: "fff"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
post: {
|
||||
fields: {
|
||||
title: 'Subject'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var fullKey = 'model.user.fields.a.b.c.d.e.f';
|
||||
|
||||
console.log('Deeps: ', fullKey.split('.').length);
|
||||
|
||||
// console.log('getNestedValue:', getNestedValue(resource, fullKey));
|
||||
|
||||
suite
|
||||
|
||||
.add('direct read a key', function() {
|
||||
resource['model.user.foo.bar.aa'];
|
||||
})
|
||||
.add('by nested', function() {
|
||||
getNestedValue(resource, fullKey);
|
||||
})
|
||||
.on('cycle', function(event) {
|
||||
benchmarks.add(event.target);
|
||||
})
|
||||
.on('complete', function done() {
|
||||
benchmarks.log();
|
||||
})
|
||||
.run({ async: false });
|
12
index.js
12
index.js
|
@ -103,7 +103,8 @@ module.exports = function (app, options) {
|
|||
|
||||
var locale = this.__getLocale();
|
||||
var resource = resources[locale] || {};
|
||||
var text = resource[key] || key;
|
||||
|
||||
var text = resource[key] || getNestedValue(resource, key) || key;
|
||||
debug('%s: %j => %j', locale, key, text);
|
||||
if (!text) {
|
||||
return '';
|
||||
|
@ -209,4 +210,13 @@ module.exports = function (app, options) {
|
|||
// support zh_CN, en_US => zh-CN, en-US
|
||||
return locale.replace('_', '-').toLowerCase();
|
||||
}
|
||||
|
||||
// fetch nested key, example: model.user.fields.title
|
||||
function getNestedValue(data, key) {
|
||||
var keys = key.split('.');
|
||||
for (var i = 0; typeof data === 'object' && i < keys.length; i++) {
|
||||
data = data[keys[i]];
|
||||
}
|
||||
return data;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -45,6 +45,8 @@ describe('koa-locales.test.js', function () {
|
|||
arguments6: '1 2 3 4 5. 6',
|
||||
values: 'foo bar foo bar {2} {100}',
|
||||
object: 'foo bar foo bar {z}',
|
||||
"gender": "model.user.fields.gender",
|
||||
"name": "model.user.fields.name"
|
||||
})
|
||||
.expect('Set-Cookie', /^locale=en\-us; path=\/; expires=\w+/)
|
||||
.expect(200, done);
|
||||
|
@ -73,6 +75,8 @@ describe('koa-locales.test.js', function () {
|
|||
arguments6: '1 2 3 4 5. 6',
|
||||
values: 'foo bar foo bar {2} {100}',
|
||||
object: 'foo bar foo bar {z}',
|
||||
"gender": "model.user.fields.gender",
|
||||
"name": "model.user.fields.name"
|
||||
})
|
||||
.expect('Set-Cookie', /^locale=en\-us; path=\/; expires=\w+/)
|
||||
.expect(200, done);
|
||||
|
@ -96,6 +100,8 @@ describe('koa-locales.test.js', function () {
|
|||
arguments6: '1 2 3 4 5. 6',
|
||||
values: 'foo bar foo bar {2} {100}',
|
||||
object: 'foo bar foo bar {z}',
|
||||
"gender": "性别",
|
||||
"name": "姓名"
|
||||
})
|
||||
.expect('Set-Cookie', /^locale=zh\-cn; path=\/; expires=\w+/)
|
||||
.expect(200, done);
|
||||
|
@ -118,6 +124,8 @@ describe('koa-locales.test.js', function () {
|
|||
arguments6: '1 2 3 4 5. 6',
|
||||
values: 'foo bar foo bar {2} {100}',
|
||||
object: 'foo bar foo bar {z}',
|
||||
"gender": "model.user.fields.gender",
|
||||
"name": "model.user.fields.name"
|
||||
})
|
||||
.expect('Set-Cookie', /^locale=de; path=\/; expires=\w+/)
|
||||
.expect(200, done);
|
||||
|
@ -141,6 +149,8 @@ describe('koa-locales.test.js', function () {
|
|||
arguments6: '1 2 3 4 5. 6',
|
||||
values: 'foo bar foo bar {2} {100}',
|
||||
object: 'foo bar foo bar {z}',
|
||||
"gender": "性别",
|
||||
"name": "姓名"
|
||||
})
|
||||
.expect('Set-Cookie', /^locale=zh\-cn; path=\/; expires=\w+/)
|
||||
.expect(200, done);
|
||||
|
@ -163,6 +173,8 @@ describe('koa-locales.test.js', function () {
|
|||
arguments6: '1 2 3 4 5. 6',
|
||||
values: 'foo bar foo bar {2} {100}',
|
||||
object: 'foo bar foo bar {z}',
|
||||
"gender": "model.user.fields.gender",
|
||||
"name": "model.user.fields.name"
|
||||
})
|
||||
.expect('Set-Cookie', /^locale=en\-us; path=\/; expires=\w+/)
|
||||
.expect(200, done);
|
||||
|
@ -188,6 +200,8 @@ describe('koa-locales.test.js', function () {
|
|||
arguments6: '1 2 3 4 5. 6',
|
||||
values: 'foo bar foo bar {2} {100}',
|
||||
object: 'foo bar foo bar {z}',
|
||||
"gender": "性别",
|
||||
"name": "姓名"
|
||||
})
|
||||
.expect(function (res) {
|
||||
assert(!res.headers['set-cookie']);
|
||||
|
@ -217,6 +231,8 @@ describe('koa-locales.test.js', function () {
|
|||
arguments6: '1 2 3 4 5. 6',
|
||||
values: 'foo bar foo bar {2} {100}',
|
||||
object: 'foo bar foo bar {z}',
|
||||
"gender": "性别",
|
||||
"name": "姓名"
|
||||
})
|
||||
.expect('Set-Cookie', /^locale=zh\-cn; path=\/; expires=\w+/)
|
||||
.expect(200, done);
|
||||
|
@ -238,6 +254,8 @@ describe('koa-locales.test.js', function () {
|
|||
arguments6: '1 2 3 4 5. 6',
|
||||
values: 'foo bar foo bar {2} {100}',
|
||||
object: 'foo bar foo bar {z}',
|
||||
"gender": "性别",
|
||||
"name": "姓名"
|
||||
})
|
||||
.expect('Set-Cookie', /^locale=zh\-cn; path=\/; expires=\w+/)
|
||||
.expect(200, done);
|
||||
|
@ -259,6 +277,8 @@ describe('koa-locales.test.js', function () {
|
|||
arguments6: '1 2 3 4 5. 6',
|
||||
values: 'foo bar foo bar {2} {100}',
|
||||
object: 'foo bar foo bar {z}',
|
||||
"gender": "性别",
|
||||
"name": "姓名"
|
||||
})
|
||||
.expect('Set-Cookie', /^locale=zh\-cn; path=\/; expires=\w+/)
|
||||
.expect(200, done);
|
||||
|
@ -282,6 +302,8 @@ describe('koa-locales.test.js', function () {
|
|||
arguments6: '1 2 3 4 5. 6',
|
||||
values: 'foo bar foo bar {2} {100}',
|
||||
object: 'foo bar foo bar {z}',
|
||||
"gender": "model.user.fields.gender",
|
||||
"name": "model.user.fields.name"
|
||||
})
|
||||
.expect('Set-Cookie', /^locale=en\-us; path=\/; expires=\w+/)
|
||||
.expect(200, done);
|
||||
|
@ -305,6 +327,8 @@ describe('koa-locales.test.js', function () {
|
|||
arguments6: '1 2 3 4 5. 6',
|
||||
values: 'foo bar foo bar {2} {100}',
|
||||
object: 'foo bar foo bar {z}',
|
||||
"gender": "model.user.fields.gender",
|
||||
"name": "model.user.fields.name"
|
||||
})
|
||||
.expect('Set-Cookie', /^locale=en\-us; path=\/; expires=\w+/)
|
||||
.expect(200, done);
|
||||
|
@ -330,6 +354,8 @@ describe('koa-locales.test.js', function () {
|
|||
arguments6: '1 2 3 4 5. 6',
|
||||
values: 'foo bar foo bar {2} {100}',
|
||||
object: 'foo bar foo bar {z}',
|
||||
"gender": "性別",
|
||||
"name": "姓名"
|
||||
})
|
||||
.expect('Set-Cookie', /^locale=zh\-tw; path=\/; expires=\w+/)
|
||||
.expect(200, done);
|
||||
|
@ -355,6 +381,8 @@ describe('koa-locales.test.js', function () {
|
|||
arguments6: '1 2 3 4 5. 6',
|
||||
values: 'foo bar foo bar {2} {100}',
|
||||
object: 'foo bar foo bar {z}',
|
||||
"gender": "model.user.fields.gender",
|
||||
"name": "model.user.fields.name"
|
||||
})
|
||||
.expect('Set-Cookie', /^locale=en\-us; path=\/; expires=\w+/)
|
||||
.expect(200, done);
|
||||
|
@ -371,6 +399,8 @@ function createApp(options) {
|
|||
app.use(function* () {
|
||||
this.body = {
|
||||
email: this[fname]('Email'),
|
||||
name: this[fname]('model.user.fields.name'),
|
||||
gender: this[fname]('model.user.fields.gender'),
|
||||
hello: this[fname]('Hello %s, how are you today?', 'fengmk2'),
|
||||
message: this[fname]('Hello %s, how are you today? How was your %s.', 'fengmk2', 18),
|
||||
empty: this[fname](),
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
module.exports = {
|
||||
Email: '邮箱',
|
||||
'Hello %s, how are you today?': '%s,今天过得如何?',
|
||||
model: {
|
||||
user: {
|
||||
fields: {
|
||||
name: '姓名',
|
||||
gender: '性别'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
{
|
||||
"Email": "郵箱",
|
||||
"Hello %s, how are you today?": "%s,今天過得如何?"
|
||||
"Hello %s, how are you today?": "%s,今天過得如何?",
|
||||
"model": {
|
||||
"user": {
|
||||
"fields": {
|
||||
"name": "姓名",
|
||||
"gender": "性別"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue