mirror of
https://github.com/YunoHost/yunohost-admin.git
synced 2024-09-03 20:06:15 +02:00
refactor: upgrade to i18n9
This commit is contained in:
parent
dd9ae21472
commit
81707bb11a
8 changed files with 97 additions and 57 deletions
|
@ -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"
|
||||
|
|
|
@ -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'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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')
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
|
|
|
@ -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 }) {
|
||||
|
|
|
@ -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']
|
||||
})
|
||||
},
|
||||
|
||||
|
|
|
@ -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'
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue