Skip to content

Commit 6c92ea8

Browse files
committed
fix: add intlify/hono package
1 parent 930d7a9 commit 6c92ea8

File tree

22 files changed

+2404
-8
lines changed

22 files changed

+2404
-8
lines changed

knip.config.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,16 @@ export default {
44
workspaces: {
55
'packages/h3': {
66
ignore: ['**/playground/**']
7+
},
8+
'packages/hono': {
9+
ignore: ['**/playground/**']
710
}
811
},
912
ignore: ['**/src/**.test-d.ts'],
10-
ignoreDependencies: ['lint-staged', '@vitest/coverage-v8']
13+
ignoreDependencies: [
14+
'lint-staged',
15+
'@vitest/coverage-v8',
16+
'vitest-environment-miniflare',
17+
'miniflare'
18+
]
1119
} satisfies KnipConfig

package.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,9 @@
3737
"lint:eslint": "eslint . --cache",
3838
"lint:knip": "knip",
3939
"lint:prettier": "prettier . --check --experimental-cli",
40-
"prepare": "git config --local core.hooksPath .githooks",
4140
"play:h3": "pnpm --filter @intlify/h3 run play:basic",
41+
"play:hono": "pnpm --filter @intlify/hono run play:basic",
42+
"prepare": "git config --local core.hooksPath .githooks",
4243
"release": "bumpp \"package.json\" \"packages/**/package.json\" --commit \"release: v\" --all --push --tag",
4344
"test": "vitest run --typecheck",
4445
"typecheck": "tsgo --noEmit --diagnostics"
@@ -68,10 +69,12 @@
6869
"eslint-plugin-yml": "^1.19.0",
6970
"knip": "^5.69.1",
7071
"lint-staged": "^16.2.6",
72+
"miniflare": "^3.20231016.0",
7173
"prettier": "^3.6.2",
7274
"typescript": "^5.9.3",
7375
"typescript-eslint": "^8.46.4",
74-
"vitest": "^3.2.4"
76+
"vitest": "^3.2.4",
77+
"vitest-environment-miniflare": "^2.14.1"
7578
},
7679
"prettier": "@kazupon/prettier-config",
7780
"lint-staged": {

packages/h3/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,13 @@
6060
"@intlify/utils": "^0.13.0"
6161
},
6262
"devDependencies": {
63-
"@types/node": "^24.10.0",
63+
"@types/node": "catalog:",
6464
"@types/supertest": "^6.0.3",
6565
"h3": "^1.15.4",
6666
"supertest": "^7.1.4",
6767
"typedoc": "^0.28.14",
6868
"typedoc-plugin-markdown": "^4.9.0",
6969
"typescript": "^5.9.3",
70-
"unbuild": "^3.6.1"
70+
"unbuild": "catalog:"
7171
}
7272
}

packages/hono/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
See the [`@intlify/hono` changelog](https://github.com/intlify/srvmid/blob/main/CHANGELOG.md)

packages/hono/README.md

Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
# @intlify/hono
2+
3+
[![npm version][npm-version-src]][npm-version-href]
4+
[![npm downloads][npm-downloads-src]][npm-downloads-href]
5+
[![CI][ci-src]][ci-href]
6+
7+
Internationalization middleware & utilities for [Hono](https://hono.dev/)
8+
9+
## 🌟 Features
10+
11+
✅️  **Translation:** Simple API like
12+
[vue-i18n](https://vue-i18n.intlify.dev/)
13+
14+
 **Custom locale detector:** You can implement your own locale detector
15+
on server-side
16+
17+
✅️️  **Useful utilities:** support internationalization composables
18+
utilities via [@intlify/utils](https://github.com/intlify/utils)
19+
20+
## 💿 Installation
21+
22+
```sh
23+
# Using npm
24+
npm install @intlify/hono
25+
26+
# Using yarn
27+
yarn add @intlify/hono
28+
29+
# Using pnpm
30+
pnpm add @intlify/hono
31+
32+
# Using bun
33+
bun add @intlify/hono
34+
```
35+
36+
## 🚀 Usage
37+
38+
```ts
39+
import { Hono } from 'hono'
40+
import {
41+
defineI18nMiddleware,
42+
detectLocaleFromAcceptLanguageHeader,
43+
useTranslation
44+
} from '@intlify/hono'
45+
46+
// define middleware with vue-i18n like options
47+
const i18nMiddleware = defineI18nMiddleware({
48+
// detect locale with `accept-language` header
49+
locale: detectLocaleFromAcceptLanguageHeader,
50+
// resource messages
51+
messages: {
52+
en: {
53+
hello: 'Hello {name}!'
54+
},
55+
ja: {
56+
hello: 'こんにちは、{name}!'
57+
}
58+
}
59+
// something options
60+
// ...
61+
})
62+
63+
const app = new Hono()
64+
65+
// install middleware with `app.use`
66+
app.use('*', i18nMiddleware)
67+
68+
app.get('/', c => {
69+
// use `useTranslation` in handler
70+
const t = useTranslation(c)
71+
return c.text(t('hello', { name: 'hono' }) + `\n`)
72+
})
73+
74+
export default app
75+
```
76+
77+
## 🛠️ Custom locale detection
78+
79+
You can detect locale with your custom logic from current `Context`.
80+
81+
example for detecting locale from url query:
82+
83+
```ts
84+
import { defineI18nMiddleware, getQueryLocale } from '@intlify/hono'
85+
import type { Context } from 'hono'
86+
87+
const DEFAULT_LOCALE = 'en'
88+
89+
// define custom locale detector
90+
const localeDetector = (ctx: Context): string => {
91+
try {
92+
return getQueryLocale(ctx).toString()
93+
} catch () {
94+
return DEFAULT_LOCALE
95+
}
96+
}
97+
98+
const middleware = defineI18nMiddleware({
99+
// set your custom locale detector
100+
locale: localeDetector,
101+
// something options
102+
// ...
103+
})
104+
```
105+
106+
## 🧩 Type-safe resources
107+
108+
> [!WARNING]
109+
> **This is experimental feature (inspired from [vue-i18n](https://vue-i18n.intlify.dev/guide/advanced/typescript.html#typescript-support)).**
110+
> We would like to get feedback from you 🙂.
111+
112+
> [!NOTE]
113+
> The exeample code is [here](https://github.com/intlify/hono/tree/main/playground/typesafe-schema)
114+
115+
You can support the type-safe resources with schema using TypeScript on `defineI18nMiddleware` options.
116+
117+
Locale messages resource:
118+
119+
```ts
120+
export default {
121+
hello: 'hello, {name}!'
122+
}
123+
```
124+
125+
your application code:
126+
127+
```ts
128+
import { defineI18nMiddleware } from '@intlify/hono'
129+
import en from './locales/en.ts'
130+
131+
// define resource schema, as 'en' is master resource schema
132+
type ResourceSchema = typeof en
133+
134+
const i18nMiddleware = defineI18nMiddleware<[ResourceSchema], 'en' | 'ja'>({
135+
messages: {
136+
en: { hello: 'Hello, {name}' }
137+
}
138+
// something options
139+
// ...
140+
})
141+
142+
// someting your implementation code ...
143+
// ...
144+
```
145+
146+
Result of type checking with `tsc`:
147+
148+
```sh
149+
npx tsc --noEmit
150+
index.ts:13:3 - error TS2741: Property 'ja' is missing in type '{ en: { hello: string; }; }' but required in type '{ en: ResourceSchema; ja: ResourceSchema; }'.
151+
152+
13 messages: {
153+
~~~~~~~~
154+
155+
../../node_modules/@intlify/core/node_modules/@intlify/core-base/dist/core-base.d.ts:125:5
156+
125 messages?: {
157+
~~~~~~~~
158+
The expected type comes from property 'messages' which is declared here on type 'CoreOptions<string, { message: ResourceSchema; datetime: DateTimeFormat; number: NumberFormat; }, { messages: "en"; datetimeFormats: "en"; numberFormats: "en"; } | { ...; }, ... 8 more ..., NumberFormats<...>>'
159+
160+
161+
Found 1 error in index.ts:13
162+
```
163+
164+
If you are using [Visual Studio Code](https://code.visualstudio.com/) as an editor, you can notice that there is a resource definition omission in the editor with the following error before you run the typescript compilation.
165+
166+
![Type-safe resources](assets/typesafe-schema.png)
167+
168+
## 🖌️ Resource keys completion
169+
170+
> [!WARNING]
171+
> **This is experimental feature (inspired from [vue-i18n](https://vue-i18n.intlify.dev/guide/advanced/typescript.html#typescript-support)).**
172+
> We would like to get feedback from you 🙂.
173+
174+
> [!NOTE]
175+
> Resource Keys completion can be used if you are using [Visual Studio Code](https://code.visualstudio.com/)
176+
177+
You can completion resources key on translation function with `useTranslation`.
178+
179+
![Key Completion](assets/key-completion.gif)
180+
181+
resource keys completion has twe ways.
182+
183+
### Type parameter for `useTranslation`
184+
185+
> [!NOTE]
186+
> The exeample code is [here](https://github.com/intlify/hono/tree/main/playground/local-schema)
187+
188+
You can `useTranslation` set the type parameter to the resource schema you want to key completion of the translation function.
189+
190+
the part of example:
191+
192+
```ts
193+
app.get('/', c => {
194+
type ResourceSchema = {
195+
hello: string
196+
}
197+
// set resource schema as type parameter
198+
const t = useTranslation<ResourceSchema>(c)
199+
// you can completion when you type `t('`
200+
return c.json(t('hello', { name: 'hono' }))
201+
}),
202+
```
203+
204+
### global resource schema with `declare module '@intlify/hono'`
205+
206+
> [!NOTE]
207+
> The exeample code is [here](https://github.com/intlify/hono/tree/main/playground/global-schema)
208+
209+
You can do resource key completion with the translation function using the typescript `declare module`.
210+
211+
the part of example:
212+
213+
```ts
214+
import en from './locales/en.ts'
215+
216+
// 'en' resource is master schema
217+
type ResourceSchema = typeof en
218+
219+
// you can put the type extending with `declare module` as global resource schema
220+
declare module '@intlify/hono' {
221+
// extend `DefineLocaleMessage` with `ResourceSchema`
222+
export interface DefineLocaleMessage extends ResourceSchema {}
223+
}
224+
225+
app.get('/', c => {
226+
const t = useTranslation(c)
227+
// you can completion when you type `t('`
228+
return c.json(t('hello', { name: 'hono' }))
229+
}),
230+
231+
```
232+
233+
The advantage of this way is that it is not necessary to specify the resource schema in the `useTranslation` type parameter.
234+
235+
## 🛠️ Utilites & Helpers
236+
237+
`@intlify/hono` has a concept of composable utilities & helpers.
238+
239+
### Utilities
240+
241+
`@intlify/hono` composable utilities accept context (from
242+
`(context) => {})`) as their first argument. (Exclud `useTranslation`) return the [`Intl.Locale`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale)
243+
244+
### Translations
245+
246+
- `useTranslation(context)`: use translation function
247+
248+
### Headers
249+
250+
- `getHeaderLocale(context, options)`: get locale from `accept-language` header
251+
- `getHeaderLocales(context, options)`: get some locales from `accept-language` header
252+
253+
### Cookies
254+
255+
- `getCookieLocale(context, options)`: get locale from cookie
256+
- `setCookieLocale(context, options)`: set locale to cookie
257+
258+
### Misc
259+
260+
- `getPathLocale(context, options)`: get locale from path
261+
- `getQueryLocale(context, options)`: get locale from query
262+
263+
## Helpers
264+
265+
- `detectLocaleFromAcceptLanguageHeader(context)`: detect locale from `accept-language` header
266+
267+
## 🙌 Contributing guidelines
268+
269+
If you are interested in contributing to `@intlify/hono`, I highly recommend checking out [the contributing guidelines](/CONTRIBUTING.md) here. You'll find all the relevant information such as [how to make a PR](/CONTRIBUTING.md#pull-request-guidelines), [how to setup development](/CONTRIBUTING.md#development-setup)) etc., there.
270+
271+
## ©️ License
272+
273+
[MIT](http://opensource.org/licenses/MIT)
274+
275+
<!-- Badges -->
276+
277+
[npm-version-src]: https://img.shields.io/npm/v/@intlify/hono?style=flat&colorA=18181B&colorB=FFAD33
278+
[npm-version-href]: https://npmjs.com/package/@intlify/hono
279+
[npm-downloads-src]: https://img.shields.io/npm/dm/@intlify/hono?style=flat&colorA=18181B&colorB=FFAD33
280+
[npm-downloads-href]: https://npmjs.com/package/@intlify/hono
281+
[ci-src]: https://github.com/intlify/utils/actions/workflows/ci.yml/badge.svg
282+
[ci-href]: https://github.com/intlify/utils/actions/workflows/ci.yml

packages/hono/build.config.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { defineBuildConfig } from 'unbuild'
2+
3+
export default defineBuildConfig({
4+
declaration: true,
5+
rollup: {
6+
emitCJS: true
7+
},
8+
entries: ['./src/index.ts'],
9+
externals: ['hono']
10+
})

0 commit comments

Comments
 (0)