From bd8a2dd09aaf369a456601a3041f3e476f561292 Mon Sep 17 00:00:00 2001 From: Bobbie Goede Date: Fri, 16 Feb 2024 03:49:27 +0100 Subject: [PATCH] feat: add `loadLocaleMessages` to manually load locale messages (#2799) * feat: extend Vue i18n with `loadLocaleMessages` function * docs: add `loadLocaleMessages` to lazy-load en vue-i18n sections * test: add test for `loadLocaleMessages` --- .../docs/2.guide/7.lazy-load-translations.md | 20 +++++++++++++++++++ docs/content/docs/4.api/4.vue-i18n.md | 8 ++++++++ .../locales/lazy-locale-module-nl.ts | 1 + specs/fixtures/lazy/lang/lazy-locale-en.json | 3 ++- specs/fixtures/lazy/pages/manual-load.vue | 18 +++++++++++++++++ specs/lazy_load/basic_lazy_load.spec.ts | 17 +++++++--------- src/runtime/plugins/i18n.ts | 15 ++++++++++++-- src/runtime/types.ts | 6 ++++++ 8 files changed, 75 insertions(+), 13 deletions(-) create mode 100644 specs/fixtures/lazy/pages/manual-load.vue diff --git a/docs/content/docs/2.guide/7.lazy-load-translations.md b/docs/content/docs/2.guide/7.lazy-load-translations.md index ef298f466..069489842 100644 --- a/docs/content/docs/2.guide/7.lazy-load-translations.md +++ b/docs/content/docs/2.guide/7.lazy-load-translations.md @@ -192,3 +192,23 @@ export default defineNuxtConfig({ } }) ``` + + +## Using translations of non-loaded locale + +As only the current locale translations are loaded you have to manually load a locale to be able to use its translations. + +Nuxt i18n extends Vue i18n to provide the `loadLocaleMessages` function to manually load locale messages, the example below demonstrates its usage. + +```ts +const { loadLocaleMessages, t } = useI18n() + +await loadLocaleMessages('nl') + +const welcome = computed(() => t('welcome')) // Welcome! +const welcomeDutch = computed(() => t('welcome', 1, { locale: 'nl' })) // Welkom! +``` + +::callout{type="info"} +As messages could be loaded from a remote API invoking the `loadLocaleMessages` function will always load messages, unnecessary loading can impact performance. +:: \ No newline at end of file diff --git a/docs/content/docs/4.api/4.vue-i18n.md b/docs/content/docs/4.api/4.vue-i18n.md index 2dcc4ced7..9fcb05be5 100644 --- a/docs/content/docs/4.api/4.vue-i18n.md +++ b/docs/content/docs/4.api/4.vue-i18n.md @@ -31,6 +31,14 @@ Updates stored locale cookie with specified locale code. Consider using `setLoca Switches locale of the app to specified locale code. If `useCookie` option is enabled, locale cookie will be updated with new value. If prefixes are enabled (`strategy` other than `no_prefix`), will navigate to new locale's route. +### loadLocaleMessages() + +- **Arguments**: + - locale (type: `string`) +- **Returns**: `Promise` + +Loads the translation messages of the specified locale code. This is only relevant for projects using lazy-loaded translations when using translations from a non-loaded locale. + ### getBrowserLocale() - **Arguments**: diff --git a/specs/fixtures/lazy/i18n-module/locales/lazy-locale-module-nl.ts b/specs/fixtures/lazy/i18n-module/locales/lazy-locale-module-nl.ts index 04d91c38b..1fa03ae7d 100644 --- a/specs/fixtures/lazy/i18n-module/locales/lazy-locale-module-nl.ts +++ b/specs/fixtures/lazy/i18n-module/locales/lazy-locale-module-nl.ts @@ -1,4 +1,5 @@ export default defineI18nLocale(locale => ({ moduleLayerText: 'This is a merged module layer locale key in Dutch', + welcome: 'Welkom!', dynamicTime: new Date().toISOString() })) diff --git a/specs/fixtures/lazy/lang/lazy-locale-en.json b/specs/fixtures/lazy/lang/lazy-locale-en.json index 780cd9077..51b73ce28 100644 --- a/specs/fixtures/lazy/lang/lazy-locale-en.json +++ b/specs/fixtures/lazy/lang/lazy-locale-en.json @@ -4,5 +4,6 @@ "posts": "Posts", "dynamic": "Dynamic", "html": "This is the danger", - "dynamicTime": "Not dynamic" + "dynamicTime": "Not dynamic", + "welcome": "Welcome!" } diff --git a/specs/fixtures/lazy/pages/manual-load.vue b/specs/fixtures/lazy/pages/manual-load.vue new file mode 100644 index 000000000..28587ea98 --- /dev/null +++ b/specs/fixtures/lazy/pages/manual-load.vue @@ -0,0 +1,18 @@ + + + diff --git a/specs/lazy_load/basic_lazy_load.spec.ts b/specs/lazy_load/basic_lazy_load.spec.ts index 9da899e80..9dbf0903e 100644 --- a/specs/lazy_load/basic_lazy_load.spec.ts +++ b/specs/lazy_load/basic_lazy_load.spec.ts @@ -119,17 +119,7 @@ describe('basic lazy loading', async () => { }) test('files with cache disabled bypass caching', async () => { - // const home = url('/') - // const page = await createPage() - // await page.goto(home) const { page, consoleLogs } = await renderPage('/') - // const messages: string[] = [] - // page.on('console', msg => { - // const content = msg.text() - // if (content.includes('lazy-locale-')) { - // messages.push(content) - // } - // }) await page.click('#lang-switcher-with-nuxt-link-en-GB') expect([...consoleLogs].filter(log => log.text.includes('lazy-locale-en-GB.js bypassing cache!'))).toHaveLength(1) @@ -143,4 +133,11 @@ describe('basic lazy loading', async () => { await page.click('#lang-switcher-with-nuxt-link-fr') expect([...consoleLogs].filter(log => log.text.includes('lazy-locale-fr.json5 bypassing cache!'))).toHaveLength(2) }) + + test('manually loaded messages can be used in translations', async () => { + const { page } = await renderPage('/manual-load') + + expect(await getText(page, '#welcome-english')).toEqual('Welcome!') + expect(await getText(page, '#welcome-dutch')).toEqual('Welkom!') + }) }) diff --git a/src/runtime/plugins/i18n.ts b/src/runtime/plugins/i18n.ts index f9437b64b..102328c00 100644 --- a/src/runtime/plugins/i18n.ts +++ b/src/runtime/plugins/i18n.ts @@ -10,7 +10,7 @@ import { parallelPlugin, normalizedLocales } from '#build/i18n.options.mjs' -import { loadVueI18nOptions, loadInitialMessages } from '../messages' +import { loadVueI18nOptions, loadInitialMessages, loadLocale } from '../messages' import { loadAndSetLocale, detectLocale, @@ -18,7 +18,8 @@ import { navigate, injectNuxtHelpers, extendBaseUrl, - _setLocale + _setLocale, + mergeLocaleMessage } from '../utils' import { getBrowserLocale as _getBrowserLocale, @@ -188,6 +189,11 @@ export default defineNuxtPlugin({ ) ) } + composer.loadLocaleMessages = async (locale: string) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const setter = (locale: Locale, message: Record) => mergeLocaleMessage(i18n, locale, message) + await loadLocale(locale, localeLoaders, setter) + } composer.differentDomains = nuxtI18nOptions.differentDomains composer.defaultLocale = nuxtI18nOptions.defaultLocale composer.getBrowserLocale = () => _getBrowserLocale() @@ -299,6 +305,11 @@ export default defineNuxtPlugin({ return async (locale: string) => Reflect.apply(composer.setLocale, composer, [locale]) } }, + loadLocaleMessages: { + get() { + return async (locale: string) => Reflect.apply(composer.loadLocaleMessages, composer, [locale]) + } + }, differentDomains: { get() { return composer.differentDomains diff --git a/src/runtime/types.ts b/src/runtime/types.ts index 4a4e6ce0b..b673785ba 100644 --- a/src/runtime/types.ts +++ b/src/runtime/types.ts @@ -80,6 +80,12 @@ export interface ComposerCustomProperties< * @param locale - A {@link Locale} */ setLocale: (locale: string) => Promise + /** + * Loads locale messages of the specified locale code. + * + * @param locale - A {@link Locale} + */ + loadLocaleMessages: (locale: string) => Promise /** * Returns browser locale code filtered against the ones defined in options. *