npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@gigahatch/babel-plugin-precompile-intl

v1.0.0

Published

Compile translations in ICU message format to invocable functions at build time

Downloads

4

Readme

babel-plugin-precompile-intl

This babel plugin compiles translations in the ICU message syntax into executable functions at build time, analyzing the used features and importing the required runtime helpers from precompile-intl-runtime to perform the operations that can't be performed at build time.

Differences with other internationalization libraries

This approach is different than the taken by libraries like intl-messageformat or format-message, which do all the work in the browser. The approach taken by those libraries is more flexible as you can just load json files with translations in plain text and that's it, but it also means the library needs to ship a parser for the ICU message syntax, and it always has to have ship code for all the features that the ICU syntax supports, even features you might not use, making those libraries several times bigger.

The strategy used by this library assumes that your app will have some sort of built process that you can use to analyze and precompile the messages in your app. This process spares the browser of the burden of doing the same process in the user's devices, resulting in smaller and faster apps.

Compile translations? WAT?

Ok, let's check it with an example.

Say you have a file with translations like this:

{
  "plain": "Some text without interpolations",
  "interpolated": "A text where I interpolate {count} times",
  "time": "Now is {now, time}",
  "time-custom-format": "The hour is {now, time, hour}",
  "date": "Today is {today, date}",
  "date-custom-format": "Today is {today, date, abbr-full}",
  "number": "My favorite number is {n, number}",
  "percent": "My favorite number is {n, number, percent}",
  "pluralized": "I have {count, plural,=0 {no cats} =1 {one cat} other {{count} cats}}",
  "pluralized-with-hash": "I have {count, plural, zero {no cats} one {just # cat} other {# cats}}",
  "selected": "{gender, select, male {He is a good boy} female {She is a good girl} other {They are good fellas}}",
}

This babel plugin will precompile that file into something like this:

import { __date, __interpolate, __number, __plural, __select, __time } from "precompile-intl-runtime";
export default {
  plain: "Some text without interpolations",
  interpolated: `A text where I interpolate ${__interpolate(count)} times`,
  time: now => `Now is ${__time(now)}`,
  "time-custom-format": now => `The hour is ${__time(now, "hour")}`,
  date: today => `Today is ${__date(today)}`,
  "date-custom-format": today => `Today is ${__date(today, "abbr-full")}`,
  number: n => `My favorite number is ${__number(n)}`,
  percent: n => `My favorite number is ${__number(n, "percent")}`,
  pluralized: count => `I have ${__plural(count, { 0: "no cats", 1: "one cat", h: `${__interpolate(count)} cats`})}`,
  "pluralized-with-hash": count => `I have ${__plural(count, { z: "no cats", o: `just ${count} cat`, h: `${count} cats`})}`,
  selected: gender => __select(gender, { male: "He is a good boy", female: "She is a good girl", other: "They are good fellas"})
}

As you see, translations with no logic remain unchanged, but translations that take arguments are transformed into functions that take those arguments and use some runtime helpers from precompile-intl-runtime, the runtime counterpart of this library.

Although this output may seem very verbose, it is designed to minify extremely well. Your minification step will transform keys like this:

"pluralized-with-hash": "I have {count, plural, zero {no cats} one {just # cat} other {# cats}}",
--------------------------------------------------------------------------------------------------
"pluralized-with-hash":t=>`I have ${jt(t,{z:"no cats",o:`just ${t} cat`,h:`${t} cats`})}`

On average the minified output is between 5% and 10% smaller than the original input, and the runtime library is much smaller than other alternatives and even smaller because it can be tree-shaken so only the helpers your translations need are included, varying the weight of the library between 1k and just a few bytes.

If you store translations in *.js file, you may use template literals (strings with backticks). These strings may span multiple lines in the file.

export default {
  notice: `
    Great to see you again!
    ... long text ...
  `
}

Note: you should not use JavaScript variables and expressions in these template literals. This syntax is not supported:

const name = "Gregory"
export default {
  notice: `Hello, ${name}`
}

It will be better to use interpolations and pass values on call:

// Translations file.
export default {
  notice: `Hello, {name}`
}

// Page, layout, etc. See `precompile-intl-runtime`.
$t('notice', {values: {name: 'Gregory'}})