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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/content/2.guide/15.migrating.md
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
@@ -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
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
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
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
@@ -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
@@ -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
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
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
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
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
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
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
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
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
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