Go Back

read

Published on: Apr 17, 2026

Programming

Change Language:

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:

  1. Typesafe
  2. No build step
  3. 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: