diff --git a/src/app.ts b/src/app.ts index 9409885..aee5d18 100644 --- a/src/app.ts +++ b/src/app.ts @@ -93,7 +93,15 @@ export default class I18n implements ILifecycleBoot { return ctx.gettext(key, ...args); } // 在 view 中使用 `__(key, value, ...args)` - this.app.locals.gettext = gettextInContext; - this.app.locals.__ = gettextInContext; + Object.defineProperties(app.locals, { + __: { + value: gettextInContext, + enumerable: true, + }, + gettext: { + value: gettextInContext, + enumerable: true, + }, + }); } } diff --git a/test/i18n.test.ts b/test/i18n.test.ts index e6e88ac..cee8fff 100644 --- a/test/i18n.test.ts +++ b/test/i18n.test.ts @@ -90,6 +90,20 @@ describe('test/i18n.test.ts', () => { assert.strictEqual(ctx.app.__('en-us', 'Email {0} {1}', [ 'a', 'b' ]), 'Email a b'); assert.strictEqual(ctx.app.__('en-us', '', [ 'a', 'b' ]), ''); }); + + it('should ctx.locals.__() work', () => { + const ctx = app.mockContext(); + assert.equal(ctx.locals.__('Email %s', 'ok'), 'Email ok'); + ctx.locals.a = 'aaa'; + assert.equal(ctx.locals.a, 'aaa'); + assert.deepEqual(Object.keys(ctx.locals), [ '__', 'gettext', 'a' ]); + }); + + it('should not allow to override the app.locals.__', () => { + assert.throws(() => { + app.locals.__ = () => 'app.__'; + }, /Cannot assign to read only property '__' of object/); + }); }); describe('with cookieDomain', () => {