refactor: upgrade to i18n9

This commit is contained in:
axolotle 2024-03-04 03:31:24 +01:00
parent dd9ae21472
commit 81707bb11a
8 changed files with 97 additions and 57 deletions

View file

@ -21,7 +21,7 @@
"fork-awesome": "^1.2.0",
"simple-evaluate": "^1.4.6",
"vue": "3.3.4",
"vue-i18n": "^8.28.2",
"vue-i18n": "^9.10.1",
"vue-router": "^4.3.0",
"vue-showdown": "^2.4.1",
"vuex": "^4.1.0"

View file

@ -10,7 +10,7 @@ class APIError extends Error {
super(
error
? error.replaceAll('\n', '<br>')
: i18n.t('error_server_unexpected'),
: i18n.global.t('error_server_unexpected'),
)
const urlObj = new URL(url)
this.name = 'APIError'
@ -39,7 +39,9 @@ class APIErrorLog extends APIError {
// 0 — (means "the connexion has been closed" apparently)
class APIConnexionError extends APIError {
constructor(method, response) {
super(method, response, { error: i18n.t('error_connection_interrupted') })
super(method, response, {
error: i18n.global.t('error_connection_interrupted'),
})
this.name = 'APIConnexionError'
}
}
@ -57,7 +59,7 @@ class APIBadRequestError extends APIError {
// 401 — Unauthorized
class APIUnauthorizedError extends APIError {
constructor(method, response, errorData) {
super(method, response, { error: i18n.t('unauthorized') })
super(method, response, { error: i18n.global.t('unauthorized') })
this.name = 'APIUnauthorizedError'
}
}
@ -65,7 +67,7 @@ class APIUnauthorizedError extends APIError {
// 404 — Not Found
class APINotFoundError extends APIError {
constructor(method, response, errorData) {
errorData.error = i18n.t('api_not_found')
errorData.error = i18n.global.t('api_not_found')
super(method, response, errorData)
this.name = 'APINotFoundError'
}
@ -83,7 +85,7 @@ class APIInternalError extends APIError {
// 502 — Bad gateway (means API is down)
class APINotRespondingError extends APIError {
constructor(method, response) {
super(method, response, { error: i18n.t('api_not_responding') })
super(method, response, { error: i18n.global.t('api_not_responding') })
this.name = 'APINotRespondingError'
}
}

View file

@ -152,7 +152,7 @@ export function formatYunoHostArgument(arg) {
props: defaultProps.concat(['type', 'autocomplete', 'trim']),
callback: function () {
if (!arg.help) {
arg.help = i18n.t('good_practices_about_admin_password')
arg.help = i18n.global.t('good_practices_about_admin_password')
}
arg.example = '••••••••••••'
validation.passwordLenght = validators.minLength(8)
@ -180,7 +180,7 @@ export function formatYunoHostArgument(arg) {
if (arg.type !== 'select') {
field.props.link = {
name: arg.type + '-list',
text: i18n.t(`manage_${arg.type}s`),
text: i18n.global.t(`manage_${arg.type}s`),
}
}
},
@ -337,7 +337,7 @@ export function formatYunoHostArgument(arg) {
if (arg.helpLink) {
field.props.link = {
href: arg.helpLink.href,
text: i18n.t(arg.helpLink.text),
text: i18n.global.t(arg.helpLink.text),
}
}

View file

@ -1,9 +1,9 @@
import { nextTick } from 'vue'
import store from '@/store'
import i18n from '@/i18n'
import supportedLocales from './supportedLocales'
let dateFnsLocale
const loadedLanguages = []
export let dateFnsLocale
/**
* Returns the first two supported locales that can be found in the `localStorage` or
@ -34,26 +34,54 @@ function getDefaultLocales() {
return defaultLocales
}
function updateDocumentLocale(locale) {
document.documentElement.lang = locale
export async function setI18nLocale(locale) {
if (!i18n.global.availableLocales.includes(locale)) {
await loadLocaleMessages(locale)
// also query/set the date-fns locale object for time translation
await loadDateFnsLocale(locale)
}
// Preload 'en' locales as it is the hard fallback
if (locale !== 'en' && !i18n.global.availableLocales.includes('en')) {
loadLocaleMessages('en')
}
if (i18n.mode === 'legacy') {
i18n.global.locale = locale
} else {
i18n.global.locale.value = locale
}
document.querySelector('html').setAttribute('lang', locale)
// FIXME can't currently change document direction easily since bootstrap still doesn't handle rtl.
// document.dir = locale === 'ar' ? 'rtl' : 'ltr'
}
export async function setI18nFallbackLocale(locale) {
if (!i18n.global.availableLocales.includes(locale)) {
await loadLocaleMessages(locale)
}
if (i18n.mode === 'legacy') {
i18n.global.fallbackLocale = [locale, 'en']
} else {
i18n.global.fallbackLocale.value = [locale, 'en']
}
}
/**
* Loads a translation file and adds its content to the i18n plugin `messages`.
*
* @return {Promise<string>} Promise that resolve the given locale string
*/
function loadLocaleMessages(locale) {
if (loadedLanguages.includes(locale)) {
return Promise.resolve(locale)
}
return import(`@/i18n/locales/${locale}.json`).then((messages) => {
i18n.setLocaleMessage(locale, messages.default)
loadedLanguages.push(locale)
return locale
})
export async function loadLocaleMessages(locale) {
// load locale messages with dynamic import
const messages = await import(`./locales/${locale}.json`)
// set locale and locale message
i18n.global.setLocaleMessage(locale, messages)
return nextTick()
}
/**
@ -71,19 +99,10 @@ async function loadDateFnsLocale(locale) {
/**
* Initialize all locales
*/
function initDefaultLocales() {
export async function initDefaultLocales() {
// Get defined locales from `localStorage` or `navigator`
const [locale, fallbackLocale] = getDefaultLocales()
store.dispatch('UPDATE_LOCALE', locale)
store.dispatch('UPDATE_FALLBACKLOCALE', fallbackLocale || 'en')
return loadLocaleMessages('en')
}
export {
initDefaultLocales,
updateDocumentLocale,
loadLocaleMessages,
loadDateFnsLocale,
dateFnsLocale,
await store.dispatch('UPDATE_LOCALE', locale)
await store.dispatch('UPDATE_FALLBACKLOCALE', fallbackLocale || 'en')
}

View file

@ -3,10 +3,9 @@
* @module i18n
*/
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import { createI18n } from 'vue-i18n'
// Plugin Initialization
Vue.use(VueI18n)
export default new VueI18n({})
export default createI18n({
// FIXME
legacy: true,
})

View file

@ -199,7 +199,7 @@ export default {
? humanKey
: { key: humanKey }
const humanRoute = key
? i18n.t('human_routes.' + key, args)
? i18n.global.t('human_routes.' + key, args)
: `[${method}] /${uri}`
let request = {
@ -368,9 +368,9 @@ export default {
// if a traduction key string has been given and we also need to pass
// the route param as a variable.
if (trad && param) {
text = i18n.t(trad, { [param]: to.params[param] })
text = i18n.global.t(trad, { [param]: to.params[param] })
} else if (trad) {
text = i18n.t(trad)
text = i18n.global.t(trad)
} else {
text = to.params[param]
}
@ -395,7 +395,7 @@ export default {
}
// Display a simplified breadcrumb as the document title.
document.title = `${getTitle(breadcrumb)} | ${i18n.t('yunohost_admin')}`
document.title = `${getTitle(breadcrumb)} | ${i18n.global.t('yunohost_admin')}`
},
UPDATE_TRANSITION_NAME({ state, commit }, { to, from }) {

View file

@ -3,12 +3,7 @@
* @module store/settings
*/
import i18n from '@/i18n'
import {
loadLocaleMessages,
updateDocumentLocale,
loadDateFnsLocale,
} from '@/i18n/helpers'
import { setI18nLocale, setI18nFallbackLocale } from '@/i18n/helpers'
import supportedLocales from '@/i18n/supportedLocales'
export default {
@ -62,19 +57,14 @@ export default {
actions: {
UPDATE_LOCALE({ commit }, locale) {
loadLocaleMessages(locale).then(() => {
updateDocumentLocale(locale)
return setI18nLocale(locale).then(() => {
commit('SET_LOCALE', locale)
i18n.locale = locale
})
// also query the date-fns locale object for filters
loadDateFnsLocale(locale)
},
UPDATE_FALLBACKLOCALE({ commit }, locale) {
loadLocaleMessages(locale).then(() => {
return setI18nFallbackLocale(locale).then(() => {
commit('SET_FALLBACKLOCALE', locale)
i18n.fallbackLocale = [locale, 'en']
})
},

View file

@ -3,6 +3,14 @@ import { defineConfig, loadEnv } from 'vite'
import fs from 'fs'
import createVuePlugin from '@vitejs/plugin-vue'
import supportedLocales from './src/i18n/supportedLocales'
const supportedDatefnsLocales = Object.entries(supportedLocales).map(
([locale, { dateFnsLocale }]) => {
return dateFnsLocale || locale
},
)
export default defineConfig(({ command, mode }) => {
// Load env file based on `mode` in the current working directory.
// Set the third parameter to '' to load all env regardless of the `VITE_` prefix.
@ -53,6 +61,28 @@ export default defineConfig(({ command, mode }) => {
if (!id.includes('node_modules') && id.includes('api/')) {
return 'core'
}
// Translations
if (id.includes('locales')) {
const match = /.*\/i18n\/locales\/([\w-]+)\.json/.exec(id)
return `locales/${match[1]}/translations`
}
// Split date-fns locales
if (id.includes('date-fns')) {
const match = /.*\/date-fns\/esm\/locale\/([\w-]+)\/.*\.js/.exec(
id,
)
if (match) {
if (supportedDatefnsLocales.includes(match[1])) {
return `locales/${match[1]}/date-fns`
} else {
// FIXME: currently difficult to cherry pick only needed locales,
// hopefully this chunk should not be fetched.
return 'locales/not-used'
}
} else {
return 'date-fns'
}
}
},
},
},