Skip to content

Commit 2b58f94

Browse files
authored
fix: missing i18n context during prerender (#3862)
1 parent fcf8439 commit 2b58f94

File tree

4 files changed

+40
-31
lines changed

4 files changed

+40
-31
lines changed

src/runtime/server/context.ts

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import type { LocaleMessages } from '@intlify/core'
22
import type { DefineLocaleMessage } from '@intlify/h3'
3-
import type { H3Event, H3EventContext } from 'h3'
4-
import type { ResolvedI18nOptions } from '../shared/vue-i18n'
3+
import { type H3Event, type H3EventContext, getRequestURL } from 'h3'
4+
import { type ResolvedI18nOptions, setupVueI18nOptions } from '../shared/vue-i18n'
5+
import { useRuntimeI18n } from '../shared/utils'
6+
import { createLocaleConfigs, getDefaultLocaleForDomain } from '../shared/locales'
57

68
export function useI18nContext(event: H3Event) {
79
if (event.context.nuxtI18n == null) {
@@ -14,18 +16,35 @@ export function tryUseI18nContext(event: H3Event) {
1416
return event.context.nuxtI18n
1517
}
1618

17-
const headers = new Headers({ 'x-nuxt-i18n': 'internal' })
18-
if (import.meta.dev) {
19-
headers.set('Cache-Control', 'no-cache')
19+
const getHost = (event: H3Event) => getRequestURL(event, { xForwardedHost: true }).host
20+
21+
export async function initializeI18nContext(event: H3Event) {
22+
const runtimeI18n = useRuntimeI18n(undefined, event)
23+
const defaultLocale: string = runtimeI18n.defaultLocale || ''
24+
const options = await setupVueI18nOptions(getDefaultLocaleForDomain(getHost(event)) || defaultLocale)
25+
const localeConfigs = createLocaleConfigs(options.fallbackLocale)
26+
const ctx = createI18nContext()
27+
28+
ctx.vueI18nOptions = options
29+
ctx.localeConfigs = localeConfigs
30+
31+
event.context.nuxtI18n = ctx
32+
return ctx
2033
}
34+
2135
/**
2236
* Fetches the messages for the specified locale.
2337
* @internal
2438
*/
25-
export const fetchMessages = async (locale: string) =>
26-
await $fetch<LocaleMessages<DefineLocaleMessage>>(`${__I18N_SERVER_ROUTE__}/${locale}/messages.json`, {
39+
export const fetchMessages = async (locale: string) => {
40+
const headers = new Headers({ 'x-nuxt-i18n': 'internal' })
41+
if (import.meta.dev) {
42+
headers.set('Cache-Control', 'no-cache')
43+
}
44+
return await $fetch<LocaleMessages<DefineLocaleMessage>>(`${__I18N_SERVER_ROUTE__}/${locale}/messages.json`, {
2745
headers,
2846
})
47+
}
2948

3049
export function createI18nContext(): NonNullable<H3EventContext['nuxtI18n']> {
3150
return {

src/runtime/server/plugin.ts

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { stringify } from 'devalue'
22
import { defineI18nMiddleware } from '@intlify/h3'
33
import { defineNitroPlugin, useStorage } from 'nitropack/runtime'
4-
import { createI18nContext, tryUseI18nContext, useI18nContext } from './context'
4+
import { initializeI18nContext, tryUseI18nContext, useI18nContext } from './context'
55
import { createUserLocaleDetector } from './utils/locale-detector'
66
import { pickNested } from './utils/messages-utils'
7-
import { createLocaleConfigs, getDefaultLocaleForDomain, isSupportedLocale } from '../shared/locales'
7+
import { isSupportedLocale } from '../shared/locales'
88
import { setupVueI18nOptions } from '../shared/vue-i18n'
99
import { joinURL } from 'ufo'
1010
// @ts-expect-error virtual file
@@ -19,8 +19,6 @@ import { useDetectors } from '../shared/detection'
1919
import { domainFromLocale } from '../shared/domain'
2020
import { isExistingNuxtRoute, matchLocalized } from '../shared/matching'
2121

22-
const getHost = (event: H3Event) => getRequestURL(event, { xForwardedHost: true }).host
23-
2422
function* detect(
2523
detectors: ReturnType<typeof useDetectors>,
2624
detection: ReturnType<typeof useI18nDetection>,
@@ -145,26 +143,14 @@ export default defineNitroPlugin(async (nitro) => {
145143

146144
const baseUrlGetter = createBaseUrlGetter()
147145

148-
async function initialize(event: H3Event) {
149-
const options = await setupVueI18nOptions(getDefaultLocaleForDomain(getHost(event)) || _defaultLocale)
150-
const localeConfigs = createLocaleConfigs(options.fallbackLocale)
151-
const ctx = createI18nContext()
152-
153-
ctx.vueI18nOptions = options
154-
ctx.localeConfigs = localeConfigs
155-
156-
event.context.nuxtI18n = ctx
157-
return ctx
158-
}
159-
160146
nitro.hooks.hook('request', async (event: H3Event) => {
161-
await initialize(event)
147+
await initializeI18nContext(event)
162148
})
163149

164150
nitro.hooks.hook('render:before', async ({ event }) => {
165151
if (!__I18N_SERVER_REDIRECT__) { return }
166152

167-
const ctx = import.meta.prerender && !event.context.nuxtI18n ? await initialize(event) : useI18nContext(event)
153+
const ctx = import.meta.prerender && !event.context.nuxtI18n ? await initializeI18nContext(event) : useI18nContext(event)
168154
const url = getRequestURL(event)
169155
const detector = useDetectors(event, detection)
170156
const localeSegment = detector.route(event.path)

src/runtime/server/routes/messages.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { deepCopy } from '@intlify/shared'
22
import { defineCachedEventHandler, defineCachedFunction } from 'nitropack/runtime'
33
import { createError, defineEventHandler, getRouterParam } from 'h3'
4-
import { useI18nContext } from '../context'
4+
import { initializeI18nContext, tryUseI18nContext, useI18nContext } from '../context'
55
import { getMergedMessages } from '../utils/messages'
66

77
import type { H3Event } from 'h3'
@@ -31,10 +31,12 @@ const _cachedMessageLoader = defineCachedFunction(_messagesHandler, {
3131
name: 'i18n:messages-internal',
3232
maxAge: !__I18N_CACHE__ ? -1 : 60 * 60 * 24,
3333
getKey: event => [getRouterParam(event, 'locale') ?? 'null', getRouterParam(event, 'hash') ?? 'null'].join('-'),
34-
shouldBypassCache(event) {
34+
async shouldBypassCache(event) {
3535
const locale = getRouterParam(event, 'locale')
3636
if (locale == null) { return false }
37-
return !useI18nContext(event).localeConfigs?.[locale]?.cacheable
37+
// prerendering may require initializing context
38+
const ctx = tryUseI18nContext(event) || await initializeI18nContext(event)
39+
return !ctx.localeConfigs?.[locale]?.cacheable
3840
},
3941
})
4042

src/runtime/shared/utils.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
import { type NuxtApp, useRuntimeConfig } from '#app'
1+
import type { NuxtApp } from '#app'
2+
import { useRuntimeConfig } from '#imports'
23
import { isString } from '@intlify/shared'
34
import type { DetectBrowserLanguageOptions, I18nPublicRuntimeConfig, RootRedirectOptions } from '#internal-i18n-types'
5+
import type { H3Event } from 'h3'
46

5-
export function useRuntimeI18n(nuxtApp?: NuxtApp) {
7+
export function useRuntimeI18n(nuxtApp?: NuxtApp, event?: H3Event) {
68
if (!nuxtApp) {
7-
return useRuntimeConfig().public.i18n as unknown as I18nPublicRuntimeConfig
9+
return useRuntimeConfig(event).public.i18n as unknown as I18nPublicRuntimeConfig
810
}
911
return nuxtApp.$config.public.i18n as unknown as I18nPublicRuntimeConfig
1012
}

0 commit comments

Comments
 (0)