Skip to content
This repository has been archived by the owner on May 19, 2022. It is now read-only.

Commit

Permalink
Merge pull request #5 from panter/features/namespaces
Browse files Browse the repository at this point in the history
feat(namespace): introduce namespaces
  • Loading branch information
claudiocro authored May 22, 2017
2 parents 44bd76e + 3682316 commit c9d7b08
Show file tree
Hide file tree
Showing 4 changed files with 219 additions and 17 deletions.
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,43 @@ Vue.component('app', {

```
### i18nOptions
The namespace will be loaded with (loadNamespaces)[http://i18next.com/docs/api/#load-namespaces],so one can lazy load namespaces for components.
``` javascript

const locales = {
en: {
tos: 'Term of Service',
term: 'I accept {{0}}. {{1}}.',
promise: 'I promise',
}
};

i18next.init({
lng: 'en',
fallbackLng: 'en',
resources: {
en: { common: locales.en },
},
});

const i18n = new VueI18next(i18next);

Vue.component('app', {
i18nOptions: { namespaces: 'common'},
template: `
<div>
<i18next path="term" tag="label">
<a href="#" target="_blank">{{ $t("tos") }}</a>
<strong>{{ $t("promise") }}</strong>
</i18next>
</div>`,
});

```
## Build Setup
``` bash
Expand Down
12 changes: 11 additions & 1 deletion src/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,17 @@ export function install(_Vue) {
Vue.mixin({
computed: {
$t() {
return (key, options) => this.$i18n.t(key, options, this.$i18n.i18nLoadedAt);
if (this.$options.i18nOptions) {
const { lng = null } = this.$options.i18nOptions;
let { namespaces } = this.$options.i18nOptions;
namespaces = namespaces || this.$i18n.i18next.options.defaultNS;
if (typeof namespaces === 'string') namespaces = [namespaces];
this.$i18n.i18next.loadNamespaces(namespaces);

const fixedT = this.$i18n.i18next.getFixedT(lng, namespaces);
return (key, options) => fixedT(key, options, this.$i18n.i18nLoadedAt);
}
return (key, options) => this.$i18n.i18next.t(key, options, this.$i18n.i18nLoadedAt);
},
},

Expand Down
28 changes: 28 additions & 0 deletions test/helpers/backendMock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
class Backend {
constructor(services, options = {}) {
this.init(services, options);
this.type = 'backend';
this.queue = [];
}

init(services, options) {
this.services = services;
this.options = options;
}

read(language, namespace, callback) {
this.queue.push({ language, namespace, callback });
}
flush() {
this.queue.forEach(({ language, namespace, callback }) => {
callback(null, {
key1: `${language}__${namespace}__test`,
interpolateKey: `${language}__${namespace}__add {{insert}} {{up, uppercase}}`,
});
});
}
}

Backend.type = 'backend';

export default Backend;
159 changes: 143 additions & 16 deletions test/unit/component.test.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
describe('Components', () => {
/* eslint-disable global-require*/
import BackendMock from '../helpers/backendMock';

const backend = new BackendMock();
function nextTick() {
return new Promise(resolve => Vue.nextTick(resolve));
}

describe('Components namespaces', () => {
const i18next1 = i18next.createInstance();
let vueI18Next;
let vm;
beforeEach((done) => {
vueI18Next = new VueI18Next(i18next);
i18next.init({
i18next1.init({
lng: 'en',
resources: {
en: {
translation: {
hello: 'Hello',
hello1: 'Hello1',
},
translation: { hello: 'Hello' },
common: { key1: 'Hello {{name}}' },
},
de: {
translation: { hello: 'Hallo' },
common: { key1: 'Hallo {{name}}' },
},
},
});
vueI18Next = new VueI18Next(i18next1);

const el = document.createElement('div');
vm = new Vue({
Expand All @@ -22,17 +33,26 @@ describe('Components', () => {
child1: {
components: {
'sub-child1': {
i18nOptions: { lng: 'de' },
render(h) {
return h('div', { }, [
h('p', { ref: 'hello' }, [this.$t('hello')]),
]);
},
},
'sub-child2': {
i18nOptions: { namespaces: 'common' },
render(h) {
return h('div', {}, [
h('p', { ref: 'hello1' }, [this.$t('hello1')]),
return h('div', { }, [
h('p', { ref: 'key1' }, [this.$t('key1', { name: 'Waldo' })]),
]);
},
},
},
render(h) {
return h('div', {}, [
h('p', { ref: 'hello' }, [this.$t('hello')]),
h('sub-child1', { ref: 'sub-child1' }),
h('sub-child2', { ref: 'sub-child2' }),
]);
},
},
Expand All @@ -45,16 +65,123 @@ describe('Components', () => {
},
}).$mount(el);


vm.$nextTick(done);
});

it('should render sub components correctly', () => {
const root = vm.$refs.hello;
const hello = vm.$refs.child1.$refs.hello;
const hello1 = vm.$refs.child1.$refs['sub-child1'].$refs.hello1;
it('should render sub components correctly', async () => {
const hello = vm.$refs.hello;
const deHello = vm.$refs.child1.$refs['sub-child1'].$refs.hello;
const commonHello = vm.$refs.child1.$refs['sub-child2'].$refs.key1;

backend.flush();
await nextTick();

expect(root.textContent).to.equal('Hello');
expect(hello.textContent).to.equal('Hello');
expect(hello1.textContent).to.equal('Hello1');
expect(deHello.textContent).to.equal('Hallo');
expect(commonHello.textContent).to.equal('Hello Waldo');
});
});


describe('Components with backend', () => {
describe('namespace on top component', () => {
const i18next1 = i18next.createInstance();
let vueI18Next;
let vm;
beforeEach((done) => {
i18next1.use(backend).init({
lng: 'en',
});
vueI18Next = new VueI18Next(i18next1);

const el = document.createElement('div');
vm = new Vue({
i18n: vueI18Next,
i18nOptions: { namespaces: 'common' },

render(h) {
return h('div', {}, [
h('p', { ref: 'hello' }, [this.$t('key1')]),
]);
},
}).$mount(el);


vm.$nextTick(done);
});

it('should render sub components correctly', async () => {
const root = vm.$refs.hello;
backend.flush();
await nextTick();

expect(root.textContent).to.equal('dev__common__test');
});
});

describe('Nested namespaces', () => {
const i18next1 = i18next.createInstance();
let vueI18Next;
let vm;
beforeEach((done) => {
i18next1.use(backend).init({
lng: 'en',
fallbackLng: ['de', 'en'],
});
vueI18Next = new VueI18Next(i18next1);

const el = document.createElement('div');
vm = new Vue({
i18n: vueI18Next,
components: {
child1: {
components: {
'sub-child1': {
i18nOptions: { lng: 'de' },
render(h) {
return h('div', { }, [
h('p', { ref: 'key11' }, [this.$t('key1')]),
]);
},
},
'sub-child2': {
i18nOptions: { namespaces: 'common' },
render(h) {
return h('div', { }, [
h('p', { ref: 'key12' }, [this.$t('key1')]),
]);
},
},
},
render(h) {
return h('div', {}, [
h('sub-child1', { ref: 'sub-child1' }),
h('sub-child2', { ref: 'sub-child2' }),
]);
},
},
},
render(h) {
return h('div', {}, [
h('child1', { ref: 'child1' }),
]);
},
}).$mount(el);


vm.$nextTick(done);
});

it('should render sub components correctly', async () => {
const key11 = vm.$refs.child1.$refs['sub-child1'].$refs.key11;
const key12 = vm.$refs.child1.$refs['sub-child2'].$refs.key12;

backend.flush();
await nextTick();

expect(key11.textContent).to.equal('de__translation__test');
expect(key12.textContent).to.equal('de__common__test');
});
});
});

0 comments on commit c9d7b08

Please sign in to comment.