@owja/i18n
Version:
lightweight internationalization library for javascript
174 lines (137 loc) • 6.19 kB
Markdown

[](https://badge.fury.io/js/%40owja%2Fi18n)
[](https://codecov.io/gh/owja/i18n)
[](https://travis-ci.org/owja/i18n)
[](https://unpkg.com/@owja/i18n/index.module.js)
This is a lightweight internationalization library which is in early **alpha** state. This means it is
work in progress, unstable, can contain bugs and the API can change until first stable release.
### Features
* lightweight bundle size **~1 kb** (brotli compressed, without plugins)
* no global state
* it is made with dependency injection in mind
* Build-in support for plurals, interpolation and context
* uses Intl.Locale and Intl.PluralRules under the hood
* Extendable with plugins
##### What does it not have and why?
* No loading mechanism. Nowadays we have dynamic imports and fetch and both can do this
job perfectly
* No namespaces. You can add translations while runtime without the need for namespaces
If you want some kind of namespaces you can use multidimensional objects
* No nesting. Could be implemented with a plugin
* No objects, no arrays
* No formatting. Could be implemented with a plugin
### Extendability (Plugins)
There will be a few plugins on stable release. Planed are:
* **[done]** Datetime Formatter, like `[[date|1558819424|short]]` to `05/25`
* **[done]** Currency Formatter, like `[[cur|2.323122]]` to `€ 2,32`
* **[done]** Number Formatter, like `[[number|2.323122|2]]` to `2,32`
* **[todo]** Html2Char Converter, for some useful codes like `­` to `0x00AD`
The reason why this functionality isn't included in the main bundle is that in
many cases they are not needed, or you need only one or two and not all.
### Usage
##### Step 1 - Creating an instance of the Translator
```typescript
import {Translator} from "@owja/i18n";
const translator = new Translator({default:"de",fallback:"en"});
```
If you use a [dependency injection tool](https://github.com/owja/ioc), you can bind the `.t()` method of the `translator` constant
to make accessing the main functionality as easy as possible.
##### Step 2 - Importing Translations
a) Adding with static imports
```typescript
import de from "lang/de.json";
import en from "lang/de.json";
translator.addResource("de", de);
translator.addResource("en", en);
```
b) Adding with dynamic imports
```typescript
import("lang/de.json").then((m) => translator.addResource("de", m.default));
import("lang/en.json").then((m) => translator.addResource("en", m.default));
```
c) Adding with fetch
```typescript
fetch("lang/de.json").then(r => r.json())
.then((r) => translator.addResource("de", r));
fetch("lang/en.json").then(r => r.json())
.then((r) => translator.addResource("en", r));
```
##### Step 3 - Translate something
*lang/de.json*
```json
{
"hello": "Hallo Welt",
"car": "Auto",
"car_other": "Autos",
"employee_male_0": "Kein Mitarbeiter",
"employee_male_one": "Der Mitarbeiter",
"employee_male_other": "Die Mitarbeiter",
"employee_female_0": "Keine Mitarbeiterinnen",
"employee_female_one": "Die Mitarbeiterin",
"employee_female_other": "Die Mitarbeiterinnen",
"dashboard": {
"button": "Ok"
},
"contact": {
"button": "Senden"
}
}
```
```typescript
translate.t("hello"); // output: "Hallo Welt"
translate.t("car", {count: 2}); // output: "Autos"
translate.t("car", {count: 1}); // output: "Auto"
translate.t("employee", {count: 0, context: "male"}); // output: "Kein Mitarbeiter"
translate.t("employee", {count: 1, context: "male"}); // output: "Der Mitarbeiter"
translate.t("employee", {count: 2, context: "male"}); // output: "Die Mitarbeiter"
translate.t("employee", {count: 0, context: "female"}); // output: "Keine Mitarbeiterinnen"
translate.t("employee", {count: 1, context: "female"}); // output: "Die Mitarbeiterin"
translate.t("employee", {count: 2, context: "female"}); // output: "Die Mitarbeiterinnen"
translate.t("dashboard.button"}); // output: "Ok"
translate.t("contact.button"}); // output: "Senden"
```
`Intl.PluralRules` is used under the hood to get the rule for the current set locale.
For example this is in german and english:
* **-1** is `one`
* **1** is `one`
* **everything else** is `other`
...and in arabic:
* **less than -10** is `many`
* **-3 to -10** is `few`
* **-2** is `two`
* **-1** is `one`
* **0** is `zero`
* **1** is `one`
* **2** is `two`
* **3 to 10** is `few`
* **greater than 10** is `many`
##### Setting the Language and Listening
Setting the language:
```typescript
translate.locale("de"); // sets only the language and is guessing the region which will result in DE in this case
translate.locale("de-DE"); // sets language and region
translate.locale(new Intl.Locale("de-DE")); // sets language and region too
translate.locale("zh-Hant-HK"); // sets language, script and region
translate.locale(new Intl.Locale("zh-Hant-HK")); // sets language, script and region too
```
Getting the language:
```typescript
translate.short(); // short locale (language) like "en" or like "zh-Hant" if script was set
translate.long(); // long locale like "en-GB" or like "zh-Hant-HK" if script was set
translate.script(); // long script like "Hant" if script was set else it returns undefined
translate.region(); // region of the current locale like "DE" if "de" or "de-DE" was set
```
Listening to language change and unsubscribe:
```typescript
// subscribe
const unsubscribe = translate.listen(() => alert("language was changed"));
// and this will unsubscribe the listener
unsubscribe();
```
> Note: The callback will get triggered on some other changes too,
like new translation resources or plugins got added.
### Inspiration
This library is made with inspiration of the well known [i18next](https://github.com/i18next/i18next) framework.
### License
**MIT**
Copyright © 2019 - 2020 Hauke Broer