diff --git a/spec/integration.spec.ts b/spec/integration.spec.ts index fc7ea1e..a3d4350 100644 --- a/spec/integration.spec.ts +++ b/spec/integration.spec.ts @@ -140,4 +140,65 @@ describe('custom locale detection', () => { expect(res.body).toEqual(translated[locale]) } }) + test('async parallel', async () => { + const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)) + + const loader = (path: string) => import(path).then((m) => m.default || m) + const messages: Record ReturnType> = { + en: () => loader('./fixtures/en.json'), + ja: () => loader('./fixtures/ja.json'), + } + + // async locale detector + const localeDetector = async ( + event: H3Event, + i18n: CoreContext, + ) => { + const locale = getQueryLocale(event).toString() + await sleep(100) + const loader = messages[locale] + if (loader && !i18n.messages[locale]) { + const message = await loader() + i18n.messages[locale] = message + } + return locale + } + + const middleware = defineI18nMiddleware({ + locale: localeDetector, + messages: { + en: { + hello: 'hello, {name}', + }, + }, + }) + app = createApp({ ...middleware }) + request = supertest(toNodeListener(app)) + + app.use( + '/', + eventHandler(async (event) => { + await sleep(100) + const t = await useTranslation(event) + await sleep(100) + return { message: t('hello', { name: 'h3' }) } + }), + ) + + const translated: Record = { + en: { + message: 'hello, h3', + }, + ja: { + message: 'こんにちは, h3', + }, + } + // request in parallel + const resList = await Promise.all( + ['en', 'ja'].map((locale) => + request.get(`/?locale=${locale}`).then((res: { body: string }) => res.body) + ), + ) + expect(resList).toEqual([translated['en'], translated['ja']]) + }) }) diff --git a/src/index.test.ts b/src/index.test.ts index 1c9aebb..7a70ca7 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -73,6 +73,8 @@ describe('useTranslation', () => { const bindLocaleDetector = (locale as LocaleDetector).bind(null, eventMock) // @ts-ignore ignore type error because this is test context.locale = bindLocaleDetector + // @ts-ignore ignore type error because this is test + eventMock.context._i18nLocale = bindLocaleDetector // test `useTranslation` const t = await useTranslation(eventMock) diff --git a/src/index.ts b/src/index.ts index b389f5d..6c5cd4a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,12 @@ // deno-lint-ignore-file no-explicit-any ban-types -import { createCoreContext, NOT_REOSLVED, translate as _translate } from '@intlify/core' +import { + createCoreContext, + NOT_REOSLVED, + // @ts-expect-error internal function + parseTranslateArgs, + translate as _translate, +} from '@intlify/core' import { getHeaderLocale } from '@intlify/utils/h3' export * from '@intlify/utils/h3' @@ -27,6 +33,7 @@ import type { declare module 'h3' { interface H3EventContext { i18n?: CoreContext + _i18nLocale?: LocaleDetector } } @@ -129,7 +136,8 @@ export function defineI18nMiddleware< return { onRequest(event: H3Event) { - i18n.locale = getLocaleDetector(event, i18n as CoreContext) + event.context._i18nLocale = getLocaleDetector(event, i18n as CoreContext) + i18n.locale = event.context._i18nLocale event.context.i18n = i18n as CoreContext }, onAfterResponse(event: H3Event) { @@ -349,16 +357,25 @@ export async function useTranslation< ) } - const localeDetector = event.context.i18n.locale as unknown as LocaleDetector + const localeDetector = event.context._i18nLocale as unknown as LocaleDetector + let locale: string if (localeDetector.constructor.name === 'AsyncFunction') { - event.context.i18n.locale = await localeDetector(event) + locale = await localeDetector(event) + event.context.i18n.locale = locale } function translate(key: string, ...args: unknown[]): string { + const [_, options] = parseTranslateArgs(key, ...args) + const [arg2] = args const result = Reflect.apply(_translate, null, [ event.context.i18n!, key, - ...args, + arg2, + { + // bind to request locale + locale, + ...options, + }, ]) return NOT_REOSLVED === result ? key : result as string }