Content
I18 Micro, my localization solution for the web
If you want something done right, sometimes you have to do it yourself.
For a few years now most of the apps I’ve worked on have had localization systems, and I’ve literally had to use a different library for each one. From my experience there isn’t a single library that meets all my expectations:
- Typesafe
- No build step
- Easy to use
Other times I’ve realized the side project I was building for fun didn’t need a library with 10,000 dependencies to translate 10 strings.
So I decided to build my own solution.
Interactive example
const locales = ["en", "es", "fr"];
type Locale = typeof locales[number];
const i18n = new I18n(locales, "en", {
en: {
hello: "Hello",
bye: "Bye"
},
es: {
hello: "Hola",
bye: "Adios"
},
fr: {
hello: "Bonjour",
bye: "Au revoir"
}
})
Hello key: Hello
Bye key: Bye
i18n Micro
No other name was available, but here’s an example of how it works:
import I18n from "i18n-micro";
const i18n = new I18n(
["en", "es"],
"en",
{
en: {
greeting: "Hello, {name}!",
nav: {
home: "Home",
about: "About",
},
},
es: {
greeting: "¡Hola, {name}!",
nav: {
home: "Inicio",
about: "Acerca de",
},
},
}
);
The constructor accepts 3 parameters: an array of languages, the default language (which must be one of the languages in the array), and finally a texts object whose first-level keys MUST be one of the languages declared earlier.
How to use
This approach felt pretty clean in practice — here’s how it works:
i18n.t("nav.home"); // Home
What if we need to change the locale?
i18n.t("nav.home"); // Home
i18n.changeLocale("es");
i18n.t("nav.home"); // Inicio
What if we have a constant like a name that we know won’t be translated?
const name = "Sturgill Simpson";
i18n.t('greeting', { name }); // ¡Hola, Sturgill Simpson!
Oh, and the string key parameter accepted by i18n.t is typesafe:
i18n.t("nav.hoem"); // ❌ TypeScript error
i18n-micro is agnostic — it can be used on the client and on the server. This is probably biased, but honestly it’s my favorite i18n library. I’ve used it in two projects, and I plan to keep using it for many more (starting by replacing the horrible custom i18n system I designed for my blog.)
Conclusion
In its first week on NPM it had 120 downloads — at least 110 of those are probably bots, and 8 are probably mine — but with small projects where I’ve used it it has already saved me from the classic initial setup I do with my custom solutions.
I plan to add type-safety when using JSON files for larger applications in the future; however that would require a build step, so I don’t consider it a priority right now.
The repository is public on GitHub, and you can also see it on NPM.
See you next time!
You may like:
Building Reusable PostgreSQL Helper Functions in Deno with deno-postgres
Boilerplate code is life.
Interface vs Type – A Comprehensive Guide
Life is full of choices, choose right.