-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
140 lines (119 loc) · 3.73 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
const defaultOptions = {
locale: 'en',
fallbackLocale: 'en',
countTag: `{count}`,
countSeperator: '|',
messages: {},
fallbackTranslation: '__NO_TRANSLATION__',
// ==========
// Hooks to do your own loggers, push keys to API, ...
/**
* Called to get key
*
* @param {*} key
* @param {*} { messages = {}, locale, ns = 'common' }
* @returns
*/
getKey (key, { messages = {}, locale, ns = 'common' }) {
const translation = messages[locale][key]
return translation
},
/**
* Called if getKey returns false
*
* @param {*} key
* @param {*} { messages, locale, fallbackLocale }
* @returns
*/
onMissingKey (key, { messages, locale, fallbackLocale }) {
console.log(`Missing key for language "${locale}": ${key}`)
return messages[fallbackLocale][key]
},
/**
* Called after getKey or onMissingKey
*
* @param {*} key
* @param {*} { messages = {}, locale, ns = 'common' }
*/
parseTranslation (translation, ctx = {}) {
// Parse variables like {count}, ...
return translation.replace(/\{(.*?)\}/g, function (match, token) {
return ctx[token]
})
}
}
/** Simple i18n plugin */
// https://alligator.io/vuejs/creating-custom-plugins/
export default {
// The install method will be called with the Vue constructor as
// the first argument, along with possible options
install (Vue, _options = defaultOptions, vueProp = '$i18n') {
// console.log(options);
// Set config
const options = {
...defaultOptions,
// Detect language from messages
languages: Object.keys(_options.messages),
// Merge in options
..._options
}
// Get hookable methods
const { getKey } = options
const $t = function (key, settings = {
context: '',
count: 1
}) {
const combinedOptions = {
...options,
...settings
}
const translation = getKey(key, combinedOptions) ||
combinedOptions.onMissingKey(key, combinedOptions) ||
combinedOptions.fallbackTranslation
return combinedOptions.parseTranslation(translation, combinedOptions)
}
// Special for some compatibility with https://kazupon.github.io/vue-i18n/guide/pluralization.html#accessing-the-number-via-the-pre-defined-argument
const $tc = function (key, count = 1, settings = {}) {
const combinedOptions = {
...options,
...settings,
count
}
const translation = getKey(key, combinedOptions) ||
combinedOptions.onMissingKey(key, combinedOptions) ||
combinedOptions.fallbackTranslation
// Replace count tag e.g. {count}
const { countTag = '{count}', countSeperator = '|' } = combinedOptions
const parts = translation.split(countSeperator)
const clamp = (value, min, max) => Math.min(Math.max(value, min), max)
// Cases:
// 1: odd: '{count} car',
// 2: car: 'car | cars',
// 3: apple: 'no apples | one apple | {count} apples'
// parts index calculator table
//
// count length => 1 2 3
//
// -2 0 0 0
// -1 0 0 0
// 0 0 0 0
// 1 0 0 1
// 2 0 1 2
// 3 0 1 2
// 4 0 1 2
// included edge case clamp count == 1 and partslength == 2
const value = count === 1 && parts.length === 2 ? 0 : count
const partsIndex = clamp(value, 0, parts.length - 1)
const part = parts[partsIndex] || options.fallbackTranslation
return part.replace(countTag, count)
}
// Bind to Vue
Vue.prototype[vueProp] = Vue.observable(options)
Vue.mixin({
methods: {
$t,
$tc
}
})
}
}