intl-ts is an i18n (internationalization) library for TypeScript. The package is compiled in ES2015 and so can also be used by JavaScript applications, but may require a Babel translation to be used with browsers. Its main features are:
- Type safe: using a wrong message name or the wrong type for the parameters will be checked at compile time. If your IDE allow it, you may even have completion for message names.
- Mutable or immutable: the library can be used in an immutable way (good for most state-aware framework, like React/Redux), or in a mutable way (for better performance).
- MobX integration: if you are using MobX, the
$preferences
property of theIntl
object will automatically become observable, allowing, for example,React
components to automatically refresh when chosen language changes. - Agnostic: can be used both at server (NodeJS) or browser side.
If you were using a previous version of the library, you may be interested by the migration guide
Installation is done using npm install
command:
$ npm install --save intl-ts
If you prefer using yarn
:
$ yarn add intl-ts
Because French is my native language, finding all documents and messages in French is not an option. Other translations are welcome.
Anyway, because English is the language of programming, the code, including variable names and comments, are in English.
🇫🇷 Une version française de ce document se trouve ici.
- Create your language strings (messages):
// English version — default
const en = {
$: 'English',
welcome: 'Welcome here!',
hello: (name: string) => `Hello ${name}`,
showElementCount: (count: number) => {
switch (count) {
case 0: {
return 'There are no elements'
}
case 1: {
return 'There is one element'
}
default: {
return `There are ${count} elements`
}
}
},
}
// Type describing messages
type langType = typeof en
// French version — full
const fr: langType = {
$: 'Français',
welcome: 'Bienvenue ici !',
hello: (name: string) => `Bonjour ${name}`,
showElementCount: (count: number) => {
switch (count) {
case 0: {
return 'Il n’y a pas d’éléments'
}
case 1: {
return 'Il y a un élément'
}
default: {
return `Il y a ${count} elements`
}
}
},
}
// Canada french version — partial
const fr_ca: PartialMessages<langType> = {
$: 'Français (Canada)',
welcome: 'Bienvenue icitte !',
}
// Esperanto version — partial
const eo: PartialMessages<langType> = {
$: 'Esperanto',
welcome: 'Bonvenon ĉi-tie!',
hello: (name: string) => `Saluton ${name}`,
}
Note that the message names must not contain one of the keyword of the Intl API.
- Create the corresponding language map:
// Direct creation
const languageMap = new LanguageMap({
default: en,
en: 'default',
fr,
fr_ca,
eo,
})
// Dynamic creation
const languageMap = new LanguageMap(en, 'en').merge({ fr, fr_ca }).merge({ eo })
Note that you should only use lowercase letters, digits and underscores as keys in language maps, because language codes will be formatted this way by the Intl
class.
- Create the internationalization object, and use it!
const lang = new Intl<langType>(languageMap, ['eo', 'fr-CA'])
lang.welcome() // 'Bonvenon ĉi-tie!'
lang.showElementCount(0) // 'Il n’y a pas d’éléments' — Compilation check that 0 is of type number
Object states will never change except:
- Internal string representation of the
LanguageMap
(because of lazy initialization), - if you choose to update the language preferences with
Intl.$changePreferences
, but you can choose to update them by cloning initial object using the copy constructor.
A new object is created when calling LanguageMap.merge()
.