tiny-translation
v1.0.1
Published
simple translation manager
Downloads
4
Maintainers
Readme
tiny-translation - lib for localisation
Simple translate manager with supporting of dynamic imports, variables and plural. You can use a lib for react applications react-tiny-translation
Install
npm i tiny-translation
// or
yarn add tiny-translation
Usage
You can use different files for translates. Below I use follow example files
lang_ru.json
{
"screens": {
"Home": {
"title": "Заголовок",
"description": "Описание ${desc} ${name}",
"plural": {
"zero": "${COUNT} бананов",
"one": "${COUNT} банан",
"two": "${COUNT} банана",
"few": "${COUNT} банана",
"many": "${COUNT} бананов",
"other": "${COUNT} бананов"
}
}
}
"extrapoint": {
"anything": "Что-нибудь"
}
}
lang_en.json
{
"screens": {
"Home": {
"title": "Title",
"description": "Description ${desc} ${name}",
"plural": {
"zero": "${COUNT} bananas",
"one": "${COUNT} banane",
"two": "${COUNT} bananas",
"few": "${COUNT} bananas",
"many": "${COUNT} bananas",
"other": "${COUNT} bananas"
}
}
}
"extrapoint": {
"anything": "Anything"
}
}
Creating
You should pass the translations and the starting locale to the init method. You can also explicitly specify possible locales by passing Locale type when creating a Translation instance
import ru from './lang_ru.json';
import en from './lang_en.json';
enum Locale {
ru = 'ru',
en = 'en',
}
const translation = new Translation<Locale>({
translations: { ru, en },
locale: Locale.en,
});
await translation.init();
Creating with dynamic imports
Files of translates will dynamic download. See webpack code-splitting
enum Locale {
ru = 'ru',
en = 'en',
}
const translation = new Translation<Locale>({
translations: {
ru: () => new Promise((resolve) => import('./lang_ru.json').then((res) => resolve(res.default))),
en: () => new Promise((resolve) => import('./lang_en.json').then((res) => resolve(res.default))),
},
locale: Locale.en,
});
await translation.init();
or you can use fetch for dynamic download
enum Locale {
ru = 'ru',
en = 'en',
}
const translation = new Translation<Locale>({
translations: {
ru: async () => await fetch('url_of_my_translate_ru.json'),
en: async () => await fetch('url_of_my_translate_en.json'),
},
locale: Locale.en,
});
await translation.init();
Creating with custom pluralization
You can pass the custom plural functions.
Note: under hood it uses
Intl.PluralRules(locale).select(count)
, but it does not support in IE. You can pass in the init method own plural functions object.
import ru from './lang_ru.json';
import en from './lang_en.json';
enum Locale {
ru = 'ru',
en = 'en',
}
const translation = new Translation<Locale>({
translations: { ru, en },
locale: Locale.en,
pluralRecord: { ru: (count: number, locale: string) => "zero" | "one" | "two" | "few" | "many" | "other", en: (count: number, locale: string) => "zero" | "one" | "two" | "few" | "many" | "other" }
});
await translation.init();
Translate
You can write in different ways:
// case 1
const translate = translation.createTranslate`screens`;
translate`Home.title`; // en -> Title; ru -> Заголовок
// case 2
const translate = translation.createTranslate`screens.Home`;
translate`title`; // en -> Title; ru -> Заголовок
// case 3
const translate = translation.createTranslate`screens.Home.title`;
translate``; // en -> Title; ru -> Заголовок
// case 4
const translate = translation.createTranslate``;
translate`screens.Home.title`; // en -> Title; ru -> Заголовок
Note: createTranslate and translate take a TemplateStringsArray or a string as first param.
createTranslate`some` // it works
createTranslate('some') // it works too
createTranslate'some' // it does not work!
translate`some` // it works
translate('some') // it works too
translate'some' // it does not work!
Translate with variables
const translate = translation.createTranslate`screens.Home`;
translate('description', { variables: { desc: "Any", name: "Name" } }); // en -> Description Any Name; ru -> Описание Any Name
Translate with plural
const translate = translation.createTranslate`screens.Home`;
translate('plural', { count: 3 }); // en -> 3 bananas; ru -> 3 банана
Note: COUNT is reserved name. Don't name your variables so.
translate('description', { variables: { COUNT: "you data" } }) // bad
Translate with few points
In any translation function, you can write the full path, and this works even if a different root path is passed to createTranslate
const translate = translation.createTranslate`screens`;
translate`Home.title` // en -> Title; ru -> Заголовок
translate`extrapoint.anything` // en -> Anything; ru -> Что-нибудь
Error handing
Sometimes we mistake in translate files, and we need see it
const translate = translation.createTranslate`screens.Home`;
translate`plural`
// throw "invalid translate! result: "[object Object]"; result as a json: {"zero":"zero bananas","one":"one banane","two":"two bananas","few":"${COUNT} bananas","many":"${COUNT} bananas","other":"${COUNT} bananas"}; rootResult: "undefined"; rootResult as a json: undefined. full path: "screens.Home.plural"; translate path: "plural";"
Also you can ignore error:
const translate = translation.createTranslate`screens.Home`;
translate(`plural`, { errorsMode: 'ignore' }) // returns ''
Or you can handle error:
const translate = translation.createTranslate`screens.Home`;
translate(`plural`, { errorsMode: (error: TransError) => 'handle error' }) // returns 'handle error'
API
Methods
constructor
type PluralFn = (count: number, locale: string) => "zero" | "one" | "two" | "few" | "many" | "other";
constructor(params: {
/**
* for example: { ru: { test: 'тест' }, en: { test: 'test' } }
*/
translations: Record<Locale, unknown>;
/**
* string
*/
locale: Locale;
/**
* If you want you can pass custom plural hanlders
*/
pluralRecord?: Record<Locale, PluralFn>;
})
init
Download dynamic files
init(): Promise<void>
changeLocale
changeLocale(locale: Locale): Promise<void>
createTranslate
createTranslate<T extends Variables = Variables>(module: string | TemplateStringsArray): Translate<T>
translate
type Variables = Record<string, string>;
type ErrorsMode = 'ignore' | 'throw' | 'console' | ((error: TransError) => string);
type TranslateOptions<T extends Variables = Variables> = {
/**
* ignore the error, handle error, show in the console or throw error (throw by default)
* */
errorsMode?: ErrorsMode;
/**
* it uses for the plural if it exists
* */
count?: number;
/**
* for replaced the variable patters - ${variable}
* */
variables?: T;
};
type Translate<T extends Variables = Variables> = (
path: string | TemplateStringsArray,
options?: TranslateOptions<T>
) => string;
Events
You can listen trans events. They will be helpful for creating a lib for any frameworks
loadstart
Triggered before only dynamic importingloadend
Triggered after only dynamic importingchange-locale
Triggered every time bychangeLocale
method but afterloadend
. It takes alocale
as a first argumentinit
Triggered single time in the end byinit
method. It takes alocale
as a first argument
// To add
translation.addEventListener('loadstart', () => void);
translation.addEventListener('loadend', () => void);
translation.addEventListener('change-locale', (locale: string) => void);
translation.addEventListener('init', (locale: string) => void);
// To remove
translation.removeEventListener('loadstart', () => void);
translation.removeEventListener('loadend', () => void);
translation.removeEventListener('change-locale', (locale: string) => void);
translation.removeEventListener('init', (locale: string) => void);