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

Commit 92768cf

Browse files
authored
Merge pull request #27 from panter/features/directive
feat(directive): introduce a t directive
2 parents e31aaab + ffe566d commit 92768cf

File tree

5 files changed

+445
-9
lines changed

5 files changed

+445
-9
lines changed

.vscode/settings.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
{
2-
"javascript.implicitProjectConfig.experimentalDecorators": true
3-
}
2+
"javascript.implicitProjectConfig.experimentalDecorators": true,
3+
"eslint.autoFixOnSave": true
4+
}

README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,42 @@ Vue.component("app", {
160160
});
161161
```
162162
163+
### Directive
164+
165+
Full Featured properties:
166+
167+
* `path`: string
168+
* `language`: language, optional
169+
* `args`: object
170+
171+
```javascript
172+
const locales = {
173+
en: {
174+
hello: "Hello",
175+
helloWithName: "Hello {{name}}"
176+
}
177+
};
178+
179+
i18next.init({
180+
lng: "en",
181+
resources: {
182+
en: { translation: locales.en }
183+
}
184+
});
185+
186+
const i18n = new VueI18next(i18next);
187+
188+
// simple usage
189+
Vue.component("app", {
190+
template: `<p v-t="hello"></p>`
191+
});
192+
193+
// full featured
194+
Vue.component("app", {
195+
template: `<p ref="text" v-t="{ path: 'helloWithName', language: 'en', args: { name: 'Hans' } }"></p>`
196+
});
197+
```
198+
163199
### i18nOptions
164200
165201
The namespace will be loaded with (loadNamespaces)[http://i18next.com/docs/api/#load-namespaces],so one can lazy load namespaces for components.

src/directive.js

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/* eslint-disable no-param-reassign, no-console, no-unused-vars */
2+
3+
function equalLanguage(el, vnode) {
4+
const vm = vnode.context;
5+
return el._i18nLanguage === vm.$i18n.i18next.language;
6+
}
7+
8+
function equalValue(value, oldValue) {
9+
if (value === oldValue) {
10+
return true;
11+
} else if (value && oldValue) {
12+
return (
13+
value.path === oldValue.path &&
14+
value.language === oldValue.language &&
15+
value.args === oldValue.args
16+
);
17+
}
18+
}
19+
20+
function assert(vnode) {
21+
const vm = vnode.context;
22+
23+
if (!vm.$i18n) {
24+
console.log('No VueI18Next instance found in the Vue instance');
25+
return false;
26+
}
27+
28+
return true;
29+
}
30+
31+
function parseValue(value) {
32+
let path;
33+
let language;
34+
let args;
35+
36+
if (typeof value === 'string') {
37+
path = value;
38+
} else if (toString.call(value) === '[object Object]') {
39+
path = value.path;
40+
language = value.language;
41+
args = value.args;
42+
}
43+
44+
return { path, language, args };
45+
}
46+
47+
function t(el, binding, vnode) {
48+
const value = binding.value;
49+
50+
const { path, language, args } = parseValue(value);
51+
if (!path && !language && !args) {
52+
console.log('v-t: invalid value');
53+
return;
54+
}
55+
56+
if (!path) {
57+
console.log('v-t: `path` is required');
58+
return;
59+
}
60+
61+
const vm = vnode.context;
62+
el.textContent = language
63+
? vm.$i18n.i18next.getFixedT(language)(path, args)
64+
: vm.$i18n.i18next.t(path, args);
65+
66+
el._i18nLanguage = vm.$i18n.i18next.language;
67+
}
68+
69+
export function bind(el, binding, vnode) {
70+
if (!assert(vnode)) {
71+
return;
72+
}
73+
74+
t(el, binding, vnode);
75+
}
76+
77+
export function update(el, binding, vnode, oldVNode) {
78+
if (equalLanguage(el, vnode) && equalValue(binding.value, binding.oldValue)) {
79+
return;
80+
}
81+
82+
t(el, binding, vnode);
83+
}

src/install.js

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* eslint-disable import/no-mutable-exports */
22
import deepmerge from 'deepmerge';
33
import component from './component';
4+
import { bind, update } from './directive';
45

56
export let Vue;
67

@@ -13,7 +14,11 @@ export function install(_Vue) {
1314
Vue = _Vue;
1415

1516
const getByKey = (i18nOptions, i18nextOptions) => (key) => {
16-
if (i18nOptions && i18nOptions.keyPrefix && !key.includes(i18nextOptions.nsSeparator)) {
17+
if (
18+
i18nOptions &&
19+
i18nOptions.keyPrefix &&
20+
!key.includes(i18nextOptions.nsSeparator)
21+
) {
1722
return `${i18nOptions.keyPrefix}.${key}`;
1823
}
1924
return key;
@@ -36,13 +41,17 @@ export function install(_Vue) {
3641
Vue.mixin({
3742
computed: {
3843
$t() {
39-
const getKey = getByKey(this._i18nOptions, this.$i18n ? this.$i18n.i18next.options : {});
44+
const getKey = getByKey(
45+
this._i18nOptions,
46+
this.$i18n ? this.$i18n.i18next.options : {},
47+
);
4048

4149
if (this._i18nOptions && this._i18nOptions.namespaces) {
4250
const { lng, namespaces } = this._i18nOptions;
4351

4452
const fixedT = this.$i18n.i18next.getFixedT(lng, namespaces);
45-
return (key, options) => fixedT(getKey(key), options, this.$i18n.i18nLoadedAt);
53+
return (key, options) =>
54+
fixedT(getKey(key), options, this.$i18n.i18nLoadedAt);
4655
}
4756

4857
return (key, options) =>
@@ -60,17 +69,25 @@ export function install(_Vue) {
6069
let inlineTranslations = {};
6170

6271
if (this.$i18n) {
63-
const getNamespace = this.$i18n.options.getComponentNamespace || getComponentNamespace;
72+
const getNamespace =
73+
this.$i18n.options.getComponentNamespace || getComponentNamespace;
6474
const { namespace, loadNamespace } = getNamespace(this);
6575

6676
if (options.__i18n) {
6777
options.__i18n.forEach((resource) => {
68-
inlineTranslations = deepmerge(inlineTranslations, JSON.parse(resource));
78+
inlineTranslations = deepmerge(
79+
inlineTranslations,
80+
JSON.parse(resource),
81+
);
6982
});
7083
}
7184

7285
if (options.i18nOptions) {
73-
const { lng = null, keyPrefix = null, messages } = this.$options.i18nOptions;
86+
const {
87+
lng = null,
88+
keyPrefix = null,
89+
messages,
90+
} = this.$options.i18nOptions;
7491
let { namespaces } = this.$options.i18nOptions;
7592
namespaces = namespaces || this.$i18n.i18next.options.defaultNS;
7693

@@ -85,7 +102,10 @@ export function install(_Vue) {
85102
this.$i18n.i18next.loadNamespaces(namespaces);
86103
} else if (options.parent && options.parent._i18nOptions) {
87104
this._i18nOptions = { ...options.parent._i18nOptions };
88-
this._i18nOptions.namespaces = [namespace, ...this._i18nOptions.namespaces];
105+
this._i18nOptions.namespaces = [
106+
namespace,
107+
...this._i18nOptions.namespaces,
108+
];
89109
} else if (options.__i18n) {
90110
this._i18nOptions = { namespaces: [namespace] };
91111
}
@@ -109,4 +129,5 @@ export function install(_Vue) {
109129
});
110130

111131
Vue.component(component.name, component);
132+
Vue.directive('t', { bind, update });
112133
}

0 commit comments

Comments
 (0)