Skip to content

Commit 1147a57

Browse files
authored
feat(hono): support async locale detector (#35)
* feat(hono): support async locale detector * fix: test codes * fix: e2e test * docs: fix
1 parent 301f76c commit 1147a57

File tree

17 files changed

+281
-71
lines changed

17 files changed

+281
-71
lines changed

packages/h3/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
"prepack": "pnpm build"
6464
},
6565
"dependencies": {
66-
"@intlify/core": "^11.1.12",
66+
"@intlify/core": "catalog:",
6767
"@intlify/utils": "catalog:"
6868
},
6969
"devDependencies": {

packages/h3/spec/integration.spec.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ test('translation', async () => {
5353
})
5454

5555
describe('custom locale detection', () => {
56-
test('basic', async () => {
56+
test('basic detection', async () => {
5757
// define custom locale detector
5858
const localeDetector = (event: H3Event): string => {
5959
return getQueryLocale(event.req).toString()
@@ -88,7 +88,7 @@ describe('custom locale detection', () => {
8888
expect(body).toEqual({ message: 'こんにちは, h3' })
8989
})
9090

91-
test('async', async () => {
91+
test('detect with async loading', async () => {
9292
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))
9393

9494
const loader = (path: string) => import(path).then(m => m.default || m)
@@ -150,7 +150,8 @@ describe('custom locale detection', () => {
150150
expect(body).toEqual(translated[locale])
151151
}
152152
})
153-
test('async parallel', async () => {
153+
154+
test('detect with async parallel loading', async () => {
154155
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))
155156

156157
const loader = (path: string) => import(path).then(m => m.default || m)

packages/hono/README.md

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,9 @@ const app = new Hono()
101101
// install middleware with `app.use`
102102
app.use('*', i18nMiddleware)
103103

104-
app.get('/', c => {
104+
app.get('/', async c => {
105105
// use `useTranslation` in handler
106-
const t = useTranslation(c)
106+
const t = await useTranslation(c)
107107
return c.text(t('hello', { name: 'hono' }) + `\n`)
108108
})
109109

@@ -139,6 +139,54 @@ const middleware = defineI18nMiddleware({
139139
})
140140
```
141141

142+
You can make that function asynchronous. This is useful when loading resources along with locale detection.
143+
144+
<!-- eslint-disable markdown/no-missing-label-refs -- NOTE(kazupon): ignore github alert -->
145+
146+
> [!NOTE]
147+
> The case which a synchronous function returns a promise is not supported. you need to use `async function`.
148+
149+
<!-- eslint-enable markdown/no-missing-label-refs -- NOTE(kazupon): ignore github alert -->
150+
151+
```ts
152+
import { Hono } from 'hono'
153+
import { defineI18nMiddleware, getCookieLocale } from '@intlify/hono'
154+
155+
import type { Context } from 'hono'
156+
import type { DefineLocaleMessage, CoreContext } from '@intlify/h3'
157+
158+
const loader = (path: string) => import(path).then(m => m.default)
159+
const messages: Record<string, () => ReturnType<typeof loader>> = {
160+
en: () => loader('./locales/en.json'),
161+
ja: () => loader('./locales/ja.json')
162+
}
163+
164+
// define custom locale detector and lazy loading
165+
const localeDetector = async (
166+
ctx: Context,
167+
i18n: CoreContext<string, DefineLocaleMessage>
168+
): Promise<string> => {
169+
// detect locale
170+
const locale = getCookieLocale(ctx.req.raw).toString()
171+
172+
// resource lazy loading
173+
const loader = messages[locale]
174+
if (loader && !i18n.messages[locale]) {
175+
const message = await loader()
176+
i18n.messages[locale] = message
177+
}
178+
179+
return locale
180+
}
181+
182+
const middleware = defineI18nMiddleware({
183+
// set your custom locale detector
184+
locale: localeDetector
185+
// something options
186+
// ...
187+
})
188+
```
189+
142190
## 🧩 Type-safe resources
143191

144192
<!-- eslint-disable markdown/no-missing-label-refs -- NOTE(kazupon): ignore github alert -->
@@ -234,12 +282,12 @@ You can `useTranslation` set the type parameter to the resource schema you want
234282
the part of example:
235283
236284
```ts
237-
app.get('/', c => {
285+
app.get('/', async c => {
238286
type ResourceSchema = {
239287
hello: string
240288
}
241289
// set resource schema as type parameter
242-
const t = useTranslation<ResourceSchema>(c)
290+
const t = await useTranslation<ResourceSchema>(c)
243291
// you can completion when you type `t('`
244292
return c.json(t('hello', { name: 'hono' }))
245293
})
@@ -270,8 +318,8 @@ declare module '@intlify/hono' {
270318
export interface DefineLocaleMessage extends ResourceSchema {}
271319
}
272320
273-
app.get('/', c => {
274-
const t = useTranslation(c)
321+
app.get('/', async c => {
322+
const t = await useTranslation(c)
275323
// you can completion when you type `t('`
276324
return c.json(t('hello', { name: 'hono' }))
277325
})

packages/hono/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
"prepack": "pnpm build"
6363
},
6464
"dependencies": {
65-
"@intlify/core": "^11.0.0",
65+
"@intlify/core": "catalog:",
6666
"@intlify/utils": "catalog:"
6767
},
6868
"devDependencies": {

packages/hono/playground/basic/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ const i18n = defineI18nMiddleware({
2020

2121
const app: Hono = new Hono()
2222
app.use('*', i18n)
23-
app.get('/', c => {
24-
const t = useTranslation(c)
23+
app.get('/', async c => {
24+
const t = await useTranslation(c)
2525
return c.text(t('hello', { name: 'hono' }) + `\n`)
2626
})
2727

packages/hono/playground/global-schema/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ const i18n = defineI18nMiddleware({
2727

2828
const app: Hono = new Hono()
2929
app.use('*', i18n)
30-
app.get('/', c => {
31-
const t = useTranslation(c)
30+
app.get('/', async c => {
31+
const t = await useTranslation(c)
3232
return c.text(t('hello', { name: 'hono' }))
3333
})
3434

packages/hono/playground/local-schema/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ const i18n = defineI18nMiddleware({
1818

1919
const app: Hono = new Hono()
2020
app.use('*', i18n)
21-
app.get('/', c => {
21+
app.get('/', async c => {
2222
type ResourceSchema = {
2323
hello: string
2424
}
25-
const t = useTranslation<ResourceSchema>(c)
25+
const t = await useTranslation<ResourceSchema>(c)
2626
return c.text(t('hello', { name: 'hono' }))
2727
})
2828

packages/hono/spec/e2e.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,6 @@ describe('e2e', () => {
5454
const stdout = await runCommand(
5555
`curl -H 'Accept-Language: ja,en-US;q=0.7,en;q=0.3' http://localhost:3000`
5656
)
57-
expect(stdout).toContain(`こんにちは, h3`)
57+
expect(stdout).toContain(`こんにちは, hono`)
5858
})
5959
})
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"hello": "hello, {name}"
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"hello": "こんにちは, {name}"
3+
}

0 commit comments

Comments
 (0)