Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor!: functions in the config to be used through hooks #1919

Merged
merged 4 commits into from
Mar 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/content/2.guide/15.migrating.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ About details, See also [Lang Switcher](/api/lang-switcher#dynamic-route-paramet

This option is no longer necessary, because i18n custom block is supported by [unplugin-vue-i18n](https://github.com/intlify/bundle-tools/tree/main/packages/unplugin-vue-i18n) **as default**.

### Deprecated `onBeforeLanguageSwitch` and `onLanguageSwitched` function options

These functions can now be triggered using Nuxt runtime hooks. Please refer to [runtime hooks](/guide/runtime-hooks) to see how to use these.

### Change some export APIs name on Nuxt context

The following API will be changed to `$`:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
# Callbacks
# Runtime Hooks

Nuxt i18n module exposes some callbacks that you can use to perform specific tasks that depend on the app's language.
Nuxt i18n module exposes some [runtime hooks](https://nuxt.com/docs/guide/going-further/hooks#app-hooks-runtime) as callbacks that you can use to perform specific tasks that depend on the app's language.

---

**Nuxt i18n module** exposes some callbacks that you can use to perform specific tasks that depend on the app's language.

### `onBeforeLanguageSwitch`
### `i18n:beforeLocaleSwitch`

Called before the app's locale is switched. Can be used to override the new locale by returning a new locale code.

Parameters:

- **oldLocale**: the app's locale before the switch
- **newLocale**: the app's locale after the switch
- **isInitialSetup**: set to `true` if it's the initial locale switch that triggers on app load. It's a special case since the locale is not technically set yet so we're switching from no locale to locale.
- **nuxtApp**: the Nuxt app
- **initialSetup**: set to `true` if it's the initial locale switch that triggers on app load. It's a special case since the locale is not technically set yet so we're switching from no locale to locale.
- **context**: the Nuxt app

Returns: `string` or nothing

### `onLanguageSwitched`
### `i18n:localeSwitched`

Called right after the app's locale has been switched.

Expand All @@ -34,13 +34,14 @@ A typical usage would be to define those callbacks via a plugin where you can ac

```js {}[/plugins/i18n.js]
export default defineNuxtPlugin(nuxtApp => {
// onBeforeLanguageSwitch called right before setting a new locale
nuxtApp.$i18n.onBeforeLanguageSwitch = (oldLocale, newLocale, isInitialSetup, nuxtApp) => {
console.log('onBeforeLanguageSwitch', oldLocale, newLocale, isInitialSetup)
}
// onLanguageSwitched called right after a new locale has been set
nuxtApp.$i18n.onLanguageSwitched = (oldLocale, newLocale) => {
// called right before setting a new locale
nuxtApp.hook('i18n:beforeLocaleSwitch', ({ oldLocale, newLocale, initialSetup, context }) => {
console.log('onBeforeLanguageSwitch', oldLocale, newLocale, initialSetup)
})

// called right after a new locale has been set
nuxtApp.hook('i18n:localeSwitched', ({oldLocale, newLocale}) => {
console.log('onLanguageSwitched', oldLocale, newLocale)
}
})
})
```
18 changes: 0 additions & 18 deletions docs/content/3.options/2.routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,24 +113,6 @@ Whether [custom paths](/guide/custom-paths) are extracted from page files

If `customRoutes` option is disabled with `config`, the module will look for custom routes in the `pages` option. Refer to the [Routing](/guide/routing-strategies) for usage.

## `onBeforeLanguageSwitch`

- type: `function`
- default: `(oldLocale, newLocale, isInitialSetup, context) => {}`

A listener called before the app's locale is changed. Can override the locale that is about to be set.

See [callbacks](/guide/callbacks)

## `onLanguageSwitched`

- type: `function`
- default: `(oldLocale, newLocale) => {}`

A listener called after app's locale has changed.

See [callbacks](/guide/callbacks)

## `skipSettingLocaleOnNavigate`

- type: `boolean`
Expand Down
12 changes: 0 additions & 12 deletions docs/content/4.API/3.vue-i18n.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,3 @@ Object of the current locale properties.
- **Type**: `boolean`

Whether `differentDomains` option is enabled.

### onBeforeLanguageSwitch

- **Type**: `Function`

See [callbacks](/guide/callbacks)

### onLanguageSwitched

- **Type**: `Function`

See [callbacks](/guide/callbacks)
6 changes: 0 additions & 6 deletions playground/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,6 @@ export default defineNuxtConfig({
// // // cookieKey: 'my_custom_cookie_name',
// // redirectOn: 'root'
// },
onBeforeLanguageSwitch: (oldLocale: string, newLocale: string, initial: boolean, nuxt: NuxtApp) => {
console.log('onBeforeLanguageSwitch', oldLocale, newLocale, initial)
},
onLanguageSwitched: (oldLocale: string, newLocale: string) => {
console.log('onLanguageSwitched', oldLocale, newLocale)
},
// vueI18n: './vue-i18n.options.ts'
vueI18n: {
legacy: false,
Expand Down
12 changes: 6 additions & 6 deletions playground/plugins/i18n.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { defineNuxtPlugin } from '#imports'

export default defineNuxtPlugin(nuxtApp => {
nuxtApp.$i18n.onBeforeLanguageSwitch = (oldLocale, newLocale, isInitialSetup, nuxtApp) => {
console.log('onBeforeLanguageSwitch', oldLocale, newLocale, isInitialSetup)
}
// onLanguageSwitched called right after a new locale has been set
nuxtApp.$i18n.onLanguageSwitched = (oldLocale, newLocale) => {
nuxtApp.hook('i18n:beforeLocaleSwitch', ({ oldLocale, newLocale, initialSetup }) => {
console.log('onBeforeLanguageSwitch', oldLocale, newLocale, initialSetup)
})

nuxtApp.hook('i18n:localeSwitched', ({ oldLocale, newLocale }) => {
console.log('onLanguageSwitched', oldLocale, newLocale)
}
})
})
15 changes: 15 additions & 0 deletions specs/fixtures/plugins/i18nHooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { defineNuxtPlugin } from '#imports'

export default defineNuxtPlugin(nuxtApp => {
nuxtApp.hook('i18n:beforeLocaleSwitch', ({ oldLocale, newLocale, initialSetup }) => {
console.log('onBeforeLanguageSwitch', oldLocale, newLocale, initialSetup)

if (newLocale === 'en') {
return 'fr'
}
})

nuxtApp.hook('i18n:localeSwitched', ({ oldLocale, newLocale }) => {
console.log('onLanguageSwitched', oldLocale, newLocale)
})
})
17 changes: 3 additions & 14 deletions specs/callbacks.spec.ts β†’ specs/runtime_hooks.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,12 @@ await setup({
browser: true,
// overrides
nuxtConfig: {
i18n: {
defaultLocale: 'en',
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onBeforeLanguageSwitch: (oldLocale: string, newLocale: string, initialSetup: boolean, context: any) => {
console.log('onBeforeLanguageSwitch', oldLocale, newLocale, initialSetup, context)
if (newLocale === 'en') {
return 'fr'
}
},
onLanguageSwitched: (oldLocale: string, newLocale: string) => {
console.log('onLanguageSwitched', oldLocale, newLocale)
}
}
plugins: [fileURLToPath(new URL(`./fixtures/plugins/i18nHooks.ts`, import.meta.url))],
i18n: { defaultLocale: 'en' }
}
})

describe('onBeforeLanguageSwitch / onLanguageSwitched', () => {
describe('beforeLocaleSwitch / localeSwitched', () => {
test('<NuxtLink>', async () => {
const home = url('/')
const page = await createPage()
Expand Down
2 changes: 0 additions & 2 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,6 @@ export const DEFAULT_OPTIONS = {
customRoutes: 'page',
pages: {},
skipSettingLocaleOnNavigate: false,
onBeforeLanguageSwitch: () => '',
onLanguageSwitched: () => null,
types: undefined,
debug: false
} as const
Expand Down
15 changes: 15 additions & 0 deletions src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,9 @@ function checkOptions(options: NuxtI18nOptions) {
}
}

type MaybePromise<T> = T | Promise<T>
type LocaleSwitch<T extends string = string> = { oldLocale: T; newLocale: T }

declare module '@nuxt/schema' {
interface NuxtConfig {
i18n?: NuxtI18nOptions
Expand All @@ -286,3 +289,15 @@ declare module '@nuxt/schema' {
'i18n:extend-messages': (messages: LocaleMessages<DefineLocaleMessage>[], localeCodes: string[]) => Promise<void>
}
}

declare module '#app' {
interface RuntimeNuxtHooks {
'i18n:beforeLocaleSwitch': <Context = unknown>(
params: LocaleSwitch & {
initialSetup: boolean
context: Context
}
) => MaybePromise<void>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
) => MaybePromise<void>
) => MaybePromise<string | void>

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator Author

@ineshbose ineshbose Mar 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of return, it may need to be something like nuxtApp.$i18n.locale = 'en'

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't work with callHook it seems!

'i18n:localeSwitched': (params: LocaleSwitch) => MaybePromise<void>
}
}
5 changes: 1 addition & 4 deletions src/options.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,5 @@ export {
NuxtI18nOptionsDefault,
NuxtI18nInternalOptions,
DetectBrowserLanguageOptions,
RootRedirectOptions,
LanguageSwitchedHandler,
BeforeLanguageSwitchHandler,
LanguageSwitchedHandler
RootRedirectOptions
} from './types'
8 changes: 6 additions & 2 deletions src/runtime/plugins/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,12 @@ export default defineNuxtPlugin(async nuxt => {
_getLocaleCookie(nuxt.ssrContext, { ...nuxtI18nOptions.detectBrowserLanguage, localeCodes })
composer.setLocaleCookie = (locale: string) =>
_setLocaleCookie(locale, nuxt.ssrContext, nuxtI18nOptions.detectBrowserLanguage || undefined)
composer.onBeforeLanguageSwitch = nuxtI18nOptions.onBeforeLanguageSwitch
composer.onLanguageSwitched = nuxtI18nOptions.onLanguageSwitched

composer.onBeforeLanguageSwitch = (oldLocale, newLocale, initialSetup, context) =>
nuxt.callHook('i18n:beforeLocaleSwitch', { oldLocale, newLocale, initialSetup, context })
composer.onLanguageSwitched = (oldLocale, newLocale) =>
nuxt.callHook('i18n:localeSwitched', { oldLocale, newLocale })

composer.finalizePendingLocaleChange = async () => {
if (!i18n.__pendingLocale) {
return
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ type BeforeLanguageSwitchHandler = (
newLocale: string,
initialSetup: boolean,
context: NuxtApp
) => string | void
) => Promise<string | void>

/**
* Called after the app's locale is switched.
*
* @param oldLocale - The app's locale before the switch
* @param newLocale - The app's locale after the switch.
*/
type LanguageSwitchedHandler = (oldLocale: string, newLocale: string) => void
type LanguageSwitchedHandler = (oldLocale: string, newLocale: string) => Promise<void>

export interface ComposerCustomProperties {
/**
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ export async function loadAndSetLocale<Context extends NuxtApp = NuxtApp>(
}

// call onBeforeLanguageSwitch
const localeOverride = onBeforeLanguageSwitch(i18n, oldLocale, newLocale, initial, context)
const localeOverride = await onBeforeLanguageSwitch(i18n, oldLocale, newLocale, initial, context)
const localeCodes = getLocaleCodes(i18n)
if (localeOverride && localeCodes && localeCodes.includes(localeOverride)) {
if (localeOverride === oldLocale) {
Expand Down Expand Up @@ -205,7 +205,7 @@ export async function loadAndSetLocale<Context extends NuxtApp = NuxtApp>(
}
setLocale(i18n, newLocale)

onLanguageSwitched(i18n, oldLocale, newLocale)
await onLanguageSwitched(i18n, oldLocale, newLocale)

ret = true
return [ret, oldLocale]
Expand Down
11 changes: 0 additions & 11 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,8 @@ export type CustomRoutePages = {
}
}

export type BeforeLanguageSwitchHandler = <Context = unknown>(
oldLocale: string,
newLocale: string,
initialSetup: boolean,
context: Context
) => string | void

export type LanguageSwitchedHandler = (oldLocale: string, newLocale: string) => void

export type NuxtI18nOptions<Context = unknown> = {
differentDomains?: boolean
onBeforeLanguageSwitch?: BeforeLanguageSwitchHandler
onLanguageSwitched?: LanguageSwitchedHandler
detectBrowserLanguage?: DetectBrowserLanguageOptions | false
langDir?: string | null
lazy?: boolean | LazyOptions
Expand Down
6 changes: 3 additions & 3 deletions test/__snapshots__/gen.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const resolveNuxtI18nOptions = async (context) => {
return nuxtI18nOptions
}

export const nuxtI18nOptionsDefault = Object({vueI18n: undefined,locales: [],defaultLocale: \\"\\",defaultDirection: \\"ltr\\",routesNameSeparator: \\"___\\",trailingSlash: false,defaultLocaleRouteNameSuffix: \\"default\\",strategy: \\"prefix_except_default\\",lazy: false,langDir: null,rootRedirect: null,detectBrowserLanguage: Object({\\"alwaysRedirect\\":false,\\"cookieCrossOrigin\\":false,\\"cookieDomain\\":null,\\"cookieKey\\":\\"i18n_redirected\\",\\"cookieSecure\\":false,\\"fallbackLocale\\":\\"\\",\\"redirectOn\\":\\"root\\",\\"useCookie\\":true}),differentDomains: false,baseUrl: \\"\\",dynamicRouteParams: false,customRoutes: \\"page\\",pages: Object({}),skipSettingLocaleOnNavigate: false,onBeforeLanguageSwitch: (() => \\"\\"),onLanguageSwitched: (() => null),types: undefined,debug: false})
export const nuxtI18nOptionsDefault = Object({vueI18n: undefined,locales: [],defaultLocale: \\"\\",defaultDirection: \\"ltr\\",routesNameSeparator: \\"___\\",trailingSlash: false,defaultLocaleRouteNameSuffix: \\"default\\",strategy: \\"prefix_except_default\\",lazy: false,langDir: null,rootRedirect: null,detectBrowserLanguage: Object({\\"alwaysRedirect\\":false,\\"cookieCrossOrigin\\":false,\\"cookieDomain\\":null,\\"cookieKey\\":\\"i18n_redirected\\",\\"cookieSecure\\":false,\\"fallbackLocale\\":\\"\\",\\"redirectOn\\":\\"root\\",\\"useCookie\\":true}),differentDomains: false,baseUrl: \\"\\",dynamicRouteParams: false,customRoutes: \\"page\\",pages: Object({}),skipSettingLocaleOnNavigate: false,types: undefined,debug: false})

export const nuxtI18nInternalOptions = Object({__normalizedLocales: [Object({\\"code\\":\\"en\\"})]})
export const NUXT_I18N_MODULE_ID = \\"@nuxtjs/i18n\\"
Expand Down Expand Up @@ -141,7 +141,7 @@ export const resolveNuxtI18nOptions = async (context) => {
return nuxtI18nOptions
}

export const nuxtI18nOptionsDefault = Object({vueI18n: undefined,locales: [],defaultLocale: \\"\\",defaultDirection: \\"ltr\\",routesNameSeparator: \\"___\\",trailingSlash: false,defaultLocaleRouteNameSuffix: \\"default\\",strategy: \\"prefix_except_default\\",lazy: false,langDir: null,rootRedirect: null,detectBrowserLanguage: Object({\\"alwaysRedirect\\":false,\\"cookieCrossOrigin\\":false,\\"cookieDomain\\":null,\\"cookieKey\\":\\"i18n_redirected\\",\\"cookieSecure\\":false,\\"fallbackLocale\\":\\"\\",\\"redirectOn\\":\\"root\\",\\"useCookie\\":true}),differentDomains: false,baseUrl: \\"\\",dynamicRouteParams: false,customRoutes: \\"page\\",pages: Object({}),skipSettingLocaleOnNavigate: false,onBeforeLanguageSwitch: (() => \\"\\"),onLanguageSwitched: (() => null),types: undefined,debug: false})
export const nuxtI18nOptionsDefault = Object({vueI18n: undefined,locales: [],defaultLocale: \\"\\",defaultDirection: \\"ltr\\",routesNameSeparator: \\"___\\",trailingSlash: false,defaultLocaleRouteNameSuffix: \\"default\\",strategy: \\"prefix_except_default\\",lazy: false,langDir: null,rootRedirect: null,detectBrowserLanguage: Object({\\"alwaysRedirect\\":false,\\"cookieCrossOrigin\\":false,\\"cookieDomain\\":null,\\"cookieKey\\":\\"i18n_redirected\\",\\"cookieSecure\\":false,\\"fallbackLocale\\":\\"\\",\\"redirectOn\\":\\"root\\",\\"useCookie\\":true}),differentDomains: false,baseUrl: \\"\\",dynamicRouteParams: false,customRoutes: \\"page\\",pages: Object({}),skipSettingLocaleOnNavigate: false,types: undefined,debug: false})

export const nuxtI18nInternalOptions = Object({__normalizedLocales: [Object({\\"code\\":\\"en\\"})]})
export const NUXT_I18N_MODULE_ID = \\"@nuxtjs/i18n\\"
Expand Down Expand Up @@ -172,7 +172,7 @@ export const resolveNuxtI18nOptions = async (context) => {
return nuxtI18nOptions
}

export const nuxtI18nOptionsDefault = Object({vueI18n: undefined,locales: [],defaultLocale: \\"\\",defaultDirection: \\"ltr\\",routesNameSeparator: \\"___\\",trailingSlash: false,defaultLocaleRouteNameSuffix: \\"default\\",strategy: \\"prefix_except_default\\",lazy: false,langDir: null,rootRedirect: null,detectBrowserLanguage: Object({\\"alwaysRedirect\\":false,\\"cookieCrossOrigin\\":false,\\"cookieDomain\\":null,\\"cookieKey\\":\\"i18n_redirected\\",\\"cookieSecure\\":false,\\"fallbackLocale\\":\\"\\",\\"redirectOn\\":\\"root\\",\\"useCookie\\":true}),differentDomains: false,baseUrl: \\"\\",dynamicRouteParams: false,customRoutes: \\"page\\",pages: Object({}),skipSettingLocaleOnNavigate: false,onBeforeLanguageSwitch: (() => \\"\\"),onLanguageSwitched: (() => null),types: undefined,debug: false})
export const nuxtI18nOptionsDefault = Object({vueI18n: undefined,locales: [],defaultLocale: \\"\\",defaultDirection: \\"ltr\\",routesNameSeparator: \\"___\\",trailingSlash: false,defaultLocaleRouteNameSuffix: \\"default\\",strategy: \\"prefix_except_default\\",lazy: false,langDir: null,rootRedirect: null,detectBrowserLanguage: Object({\\"alwaysRedirect\\":false,\\"cookieCrossOrigin\\":false,\\"cookieDomain\\":null,\\"cookieKey\\":\\"i18n_redirected\\",\\"cookieSecure\\":false,\\"fallbackLocale\\":\\"\\",\\"redirectOn\\":\\"root\\",\\"useCookie\\":true}),differentDomains: false,baseUrl: \\"\\",dynamicRouteParams: false,customRoutes: \\"page\\",pages: Object({}),skipSettingLocaleOnNavigate: false,types: undefined,debug: false})

export const nuxtI18nInternalOptions = Object({__normalizedLocales: [Object({\\"code\\":\\"en\\"})]})
export const NUXT_I18N_MODULE_ID = \\"@nuxtjs/i18n\\"
Expand Down