-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: translation utility implementation (#2)
* feat: translation utility implementation * updates * update bun lock
- Loading branch information
Showing
9 changed files
with
484 additions
and
378 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,156 @@ | ||
# @intlify/h3 | ||
|
||
Internationalization utilitis for h3 | ||
[![npm version][npm-version-src]][npm-version-href] | ||
[![npm downloads][npm-downloads-src]][npm-downloads-href] | ||
[![CI][ci-src]][ci-href] | ||
|
||
**NOTICE: This is a work in progress 👷** | ||
Internationalization middleware & utilitis for h3 | ||
|
||
## 🌟 Features | ||
|
||
✅️ **Translation:** Simple API like | ||
[vue-i18n](https://vue-i18n.intlify.dev/) | ||
|
||
✅ **Custom locale detector:** You can implement your own locale detector | ||
on server-side | ||
|
||
✅️️ **Useful utilities:** support internationalization composables | ||
utilities via [@intlify/utils](https://github.com/intlify/utils) | ||
|
||
## 💿 Installation | ||
|
||
```sh | ||
# Using npm | ||
npm install @intlify/h3 | ||
|
||
# Using yarn | ||
yarn add @intlify/h3 | ||
|
||
# Using pnpm | ||
pnpm add @intlify/h3 | ||
|
||
# Using bun | ||
bun add @intlify/h3 | ||
``` | ||
|
||
## 🚀 Usage | ||
|
||
```ts | ||
import { createServer } from 'node:http' | ||
import { createApp, createRouter, eventHandler, toNodeListener } from 'h3' | ||
import { | ||
defineI18nMiddleware, | ||
detectLocaleFromAcceptLanguageHeader, | ||
useTranslation, | ||
} from '@intlify/h3' | ||
|
||
// define middleware with vue-i18n like options | ||
const middleware = defineI18nMiddleware({ | ||
// detect locale with `accept-language` header | ||
locale: detectLocaleFromAcceptLanguageHeader, | ||
// resource messages | ||
messages: { | ||
en: { | ||
hello: 'Hello {name}!', | ||
}, | ||
ja: { | ||
hello: 'こんにちは、{name}!', | ||
}, | ||
}, | ||
// something options | ||
// ... | ||
}) | ||
|
||
// install middleware with `createApp` option | ||
const app = createApp({ ...middleware }) | ||
|
||
const router = createRouter() | ||
router.get( | ||
'/', | ||
eventHandler((event) => { | ||
// use `useTranslation` in event handler | ||
const t = useTranslation(event) | ||
return t('hello', { name: 'h3' }) | ||
}), | ||
) | ||
|
||
app.use(router) | ||
createServer(toNodeListener(app)).listen(3000) | ||
``` | ||
|
||
## 🛠️ Custom locale detection | ||
|
||
You can detect locale with your custom logic from current `H3Event`. | ||
|
||
example for detecting locale from url query header: | ||
|
||
```ts | ||
import { defineI18nMiddleware, getQueryLocale } from '@intlify/h3' | ||
import type { H3Event } from 'h3' | ||
|
||
const DEFAULT_LOCALE = 'en' | ||
|
||
// define custom locale detector | ||
const localeDetector = (event: H3Event): string => { | ||
try { | ||
return getQueryLocale(event).toString() | ||
} catch () { | ||
return DEFAULT_LOCALE | ||
} | ||
} | ||
|
||
const middleware = defineI18nMiddleware({ | ||
// set your custom locale detector | ||
locale: localeDetector, | ||
// something options | ||
// ... | ||
}) | ||
``` | ||
|
||
## 🛠️ Utilites & Helpers | ||
|
||
`@intlify/h3` has a concept of composable utilities & helpers. | ||
|
||
### Utilities | ||
|
||
`@intlify/h3` composable utilities accept event (from | ||
`eventHandler((event) => {})`) as their first argument. (Exclud | ||
`useTranslation`) return the | ||
[`Intl.Locale`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale) | ||
|
||
### Translations | ||
|
||
- `useTranslation(event)`: use translation function | ||
|
||
### Headers | ||
|
||
- `getHeaderLocale(event)`: get locale from `accept-language` header | ||
- `getHeaderLocales(event)`: get some locales from `accept-language` header | ||
|
||
### Cookies | ||
|
||
- `getCookieLocale()`: get locale from cookie | ||
- `setCookieLocale()`: set locale to cookie | ||
|
||
### Misc | ||
|
||
- `getPathLocale(event)`: get locale from path | ||
- `getQueryLocale(event)`: get locale from query | ||
|
||
## Helpers | ||
|
||
- `detectLocaleFromAcceptLanguageHeader`: detect locale from `accept-language` | ||
header | ||
|
||
## ©️ License | ||
|
||
[MIT](http://opensource.org/licenses/MIT) | ||
|
||
<!-- Badges --> | ||
|
||
[npm-version-src]: https://img.shields.io/npm/v/@intlify/h3?style=flat&colorA=18181B&colorB=FFAD33 | ||
[npm-version-href]: https://npmjs.com/package/@intlify/h3 | ||
[npm-downloads-src]: https://img.shields.io/npm/dm/@intlify/h3?style=flat&colorA=18181B&colorB=FFAD33 | ||
[npm-downloads-href]: https://npmjs.com/package/@intlify/h3 | ||
[ci-src]: https://github.com/intlify/utils/actions/workflows/ci.yml/badge.svg | ||
[ci-href]: https://github.com/intlify/utils/actions/workflows/ci.yml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -63,11 +63,15 @@ | |
"@vitest/coverage-v8": "^0.34.4", | ||
"bumpp": "^9.2.0", | ||
"gh-changelogen": "^0.2.8", | ||
"h3": "^1.8.1", | ||
"h3": "^1.8.2", | ||
"lint-staged": "^14.0.0", | ||
"supertest": "^6.3.3", | ||
"typescript": "^5.2.2", | ||
"unbuild": "^2.0.0", | ||
"vitest": "^0.34.4" | ||
"vitest": "^1.0.0-beta.1" | ||
}, | ||
"dependencies": { | ||
"@intlify/core": "npm:@intlify/[email protected]", | ||
"@intlify/utils": "^0.8.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import { afterEach, expect, test, vi } from 'vitest' | ||
import { createApp, eventHandler, toNodeListener } from 'h3' | ||
import { getQueryLocale } from '@intlify/utils/h3' | ||
import supertest from 'supertest' | ||
|
||
import { | ||
defineI18nMiddleware, | ||
detectLocaleFromAcceptLanguageHeader, | ||
useTranslation, | ||
} from '../src/index.ts' | ||
|
||
import type { App, H3Event } from 'h3' | ||
import type { SuperTest, Test } from 'supertest' | ||
|
||
let app: App | ||
let request: SuperTest<Test> | ||
|
||
afterEach(() => { | ||
vi.resetAllMocks() | ||
}) | ||
|
||
test('translation', async () => { | ||
const middleware = defineI18nMiddleware({ | ||
locale: detectLocaleFromAcceptLanguageHeader, | ||
messages: { | ||
en: { | ||
hello: 'hello, {name}', | ||
}, | ||
ja: { | ||
hello: 'こんにちは, {name}', | ||
}, | ||
}, | ||
}) | ||
app = createApp({ ...middleware }) | ||
request = supertest(toNodeListener(app)) | ||
|
||
app.use( | ||
'/', | ||
eventHandler((event) => { | ||
const t = useTranslation(event) | ||
return { message: t('hello', { name: 'h3' }) } | ||
}), | ||
) | ||
|
||
const res = await request.get('/').set( | ||
'accept-language', | ||
'en;q=0.9,ja;q=0.8', | ||
) | ||
expect(res.body).toEqual({ message: 'hello, h3' }) | ||
}) | ||
|
||
test('custom locale detection', async () => { | ||
const defaultLocale = 'en' | ||
|
||
// define custom locale detector | ||
const localeDetector = (event: H3Event): string => { | ||
try { | ||
return getQueryLocale(event).toString() | ||
} catch (_e) { | ||
return defaultLocale | ||
} | ||
} | ||
|
||
const middleware = defineI18nMiddleware({ | ||
locale: localeDetector, | ||
messages: { | ||
en: { | ||
hello: 'hello, {name}', | ||
}, | ||
ja: { | ||
hello: 'こんにちは, {name}', | ||
}, | ||
}, | ||
}) | ||
app = createApp({ ...middleware }) | ||
request = supertest(toNodeListener(app)) | ||
|
||
app.use( | ||
'/', | ||
eventHandler((event) => { | ||
const t = useTranslation(event) | ||
return { message: t('hello', { name: 'h3' }) } | ||
}), | ||
) | ||
|
||
const res = await request.get('/?locale=ja') | ||
expect(res.body).toEqual({ message: 'こんにちは, h3' }) | ||
}) |
Oops, something went wrong.