-
Notifications
You must be signed in to change notification settings - Fork 56
/
i18n.js
108 lines (88 loc) · 3.33 KB
/
i18n.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
/*
Copyright 2020 ODK Central Developers
See the NOTICE file at the top-level directory of this distribution and at
https://github.com/getodk/central-frontend/blob/master/NOTICE.
This file is part of ODK Central. It is subject to the license terms in
the LICENSE file found in the top-level directory of this distribution and at
https://www.apache.org/licenses/LICENSE-2.0. No part of ODK Central,
including this file, may be copied, modified, propagated, or distributed
except according to the terms contained in the LICENSE file.
*/
import { useI18n } from 'vue-i18n';
import { watchSyncEffect } from 'vue';
import { locales } from '../i18n';
import { memoizeForContainer } from './composable';
////////////////////////////////////////////////////////////////////////////////
// loadLocale()
const setLocale = (i18n, locale) => {
i18n.locale = locale; // eslint-disable-line no-param-reassign
document.documentElement.setAttribute('lang', locale);
};
// Loads a locale asynchronously.
export const loadLocale = ({ i18n, logger }, locale) => {
if (!locales.has(locale)) return Promise.reject(new Error('unknown locale'));
if (i18n.messages[locale] != null) {
if (locale !== i18n.locale) setLocale(i18n, locale);
return Promise.resolve();
}
return import(
/* webpackChunkName: "i18n-[request]" */
`../locales/${locale}.json`
)
.then(m => {
i18n.setLocaleMessage(locale, m.default);
setLocale(i18n, locale);
})
.catch(error => {
logger.log(error);
throw error;
});
};
////////////////////////////////////////////////////////////////////////////////
// tn(), $tcn()
// Combination of $tc() and $n()
export function $tcn(path, count, values = undefined) {
return this.$tc(path, count, { count: this.$n(count, 'default'), ...values });
}
// Combination of t() and n()
const tn = (t, n) => (path, count, values) => {
const list = { count: n(count, 'default') };
Object.entries(values || {}).forEach(([k, v]) => { list[k] = typeof v === 'number' ? n(v, 'default') : v; });
return t(path, list, count);
};
////////////////////////////////////////////////////////////////////////////////
// useI18nUtils()
const useGlobalUtils = memoizeForContainer(({ i18n }) => {
const formats = {};
watchSyncEffect(() => {
const { locale } = i18n;
if (formats[locale] != null) return;
formats[locale] = {
numberFormats: {},
listFormat: new Intl.ListFormat(locale, { style: 'narrow' })
};
});
const getNumberFormat = (key) => {
const { locale } = i18n;
const { numberFormats } = formats[locale];
const existingFormat = numberFormats[key];
if (existingFormat != null) return existingFormat;
const options = i18n.getNumberFormat(locale)[key];
const numberFormat = new Intl.NumberFormat(locale, options);
numberFormats[key] = numberFormat;
return numberFormat;
};
return {
formatRange: (start, end, key = 'default') => (start === end
? i18n.n(start, key)
: getNumberFormat(key).formatRange(start, end)),
formatList: (list) => formats[i18n.locale].listFormat.format(list),
formatListToParts: (list) =>
formats[i18n.locale].listFormat.formatToParts(list)
};
});
const useLocalUtils = () => {
const { t, n } = useI18n();
return { tn: tn(t, n) };
};
export const useI18nUtils = () => ({ ...useGlobalUtils(), ...useLocalUtils() });