Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/acro5piano/typed-i18n
[deprecated] type-safe i18n library
https://github.com/acro5piano/typed-i18n
i18n npm-package type-safety typescript
Last synced: 18 days ago
JSON representation
[deprecated] type-safe i18n library
- Host: GitHub
- URL: https://github.com/acro5piano/typed-i18n
- Owner: acro5piano
- License: mit
- Created: 2019-11-19T07:08:52.000Z (almost 5 years ago)
- Default Branch: master
- Last Pushed: 2023-01-07T11:54:35.000Z (almost 2 years ago)
- Last Synced: 2024-10-12T06:43:25.974Z (about 1 month ago)
- Topics: i18n, npm-package, type-safety, typescript
- Language: TypeScript
- Homepage:
- Size: 1.49 MB
- Stars: 23
- Watchers: 4
- Forks: 0
- Open Issues: 21
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Deprecated. Please use https://lingui.js.org/ instead
[![CircleCI](https://circleci.com/gh/acro5piano/typed-i18n.svg?style=svg)](https://circleci.com/gh/acro5piano/typed-i18n)
[![npm version](https://badge.fury.io/js/typed-i18n.svg)](https://badge.fury.io/js/typed-i18n)# typed-i18n
type-safe i18n library
# Why
The aim of `typed-i18n` is to provide zero-configuration type-safe i18n feature.
Typical i18n libraries uses the syntax of `t('group.key')`, which is apparently not type-safe.
`typed-i18n` uses regular JS & TS syntax so you can get these benefits:
- Build-time type safety
- Editor supports
- Checking i18n coverage in TS levelAlso `typed-i18n` supports two translation flows:
**engineer-driven translation**
Engineers directly write translations. We can completely make them type-safe.
**translator-driven translation**
translators fill yaml/json/spreadsheets/(any) then compile it. It is a common pattern, but type-safety will be lost to some extent.
# Install
```
npm install --save typed-i18n
```Or if you use Yarn:
```
yarn add typed-i18n
```# Usage
You can write basic translations like this:
```typescript
import TypedI18n from 'typed-i18n'const en = {
hello: 'Hello',
goodbye: 'Goodbye',
}const ja = {
hello: 'こんにちは',
goodbye: 'さようなら',
}type Lang = 'en' | 'ja'
type Translations = typeof en & typeof jaconst t = new TypedI18n()
.addLocale('en', en)
.addLocale('ja', ja)t.setLocale('en')
console.log(t.trans.hello) // => Hellot.setLocale('ja')
console.log(t.trans.hello) // => こんにちは
```If there are any mistakes in your translations, TS will check them.
# Type-safety
In the above example, the following code will throw TypeScript errors.
```typescript
// missing the locale
t.setLocale('cn')// missing the key
t.trans.notExistKey// trying to add a locale with missing keys
t.addLocale('de', {
hello: 'Guten Tag',
})
```# Interpolation
Interpolation is one of the most used functionalities in I18N. It enables you to integrate dynamic values into your translations.
There are two options to implement it:
**1. use `interp` function**
```typescript
import TypedI18n, { interp } from 'typed-i18n'const en = {
greeting: interp(name => `Hello, ${name}`),
}const t = new TypedI18n<'en', typeof en>().addLocale('en', en)
console.log(t.trans.greeting('John')) // => Hello, John
```**2. define `$index` and call `withArgs` method**
```typescript
import TypedI18n from 'typed-i18n'const en = {
greeting: `Hello, $1`,
}const t = new TypedI18n<'en', typeof en>().addLocale('en', en)
console.log(t.withArgs('John').trans.greeting) // => Hello, John
```# Nesting
You can nest your translations. There are two options to implement it:
**1. use getter functions**
```typescript
import TypedI18n from 'typed-i18n'const en = {
hello: 'Hello',
goodbye: 'Goodbye',
helloButGoodbye: () => `${en.hello}, but ${en.goodbye}.`,
}const t = new TypedI18n<'en', typeof en>().addLocale('en', en)
console.log(t.trans.helloButGoodbye) // => Hello, but Goodbye.
```**2. use `$this` expression**
```typescript
import TypedI18n from 'typed-i18n'const en = {
hello: 'Hello',
goodbye: 'Goodbye',
helloButGoodbye: '$this.hello, but $this.goodbye.',
}const t = new TypedI18n<'en', typeof en>().addLocale('en', en)
console.log(t.trans.helloButGoodbye) // => Hello, but Goodbye.
```# React bindings
You can use `typed-i18n` with React:
```
npm install --save typed-i18n-react
``````typescript
// i18n.ts
import TypedI18n, from 'typed-i18n'
import createContextHooks from 'typed-i18n-react'const en = {
hello: 'Hello',
changeLocale: 'Change Locale',
}const ja = {
hello: 'こんにちは',
changeLocale: '言語を変える',
}type Lang = 'en' | 'ja'
type Translations = typeof en & typeof jaconst t = new TypedI18n()
.addLocale('en', en)
.addLocale('ja', ja)export const { useTrans, useChangeLocale, Provider } = createContextHooks(t)
``````typescript
// App.tsx
import React from 'react'
import ReactDOM from 'react-dom'
import { useTrans, useChangeLocale, Provider } from './i18n'function App() {
const t = useTrans()
const changeLocale = useChangeLocale()const changeLang = React.useCallback(() => {
changeLocale(t.locale === 'en' ? 'ja' : 'en')
}, [changeLocale, t.locale])return (
{t.trans.hello}
{t.trans.changeLocale}
)
}ReactDOM.render(
,
document.getElementById('root'),
)
```# TODO
- [x] Deeply nested object support
- [x] React bindings
- [ ] Plurals