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

babel-plugin-inline-i18n-messages

v0.1.3

Published

A tooling-agnostic i18n message inlining plugin for babel

Downloads

17

Readme

babel-plugin-inline-i18n-messages

npm Build Status codecov npm

A tooling-agnostic i18n message inlining plugin for babel. Enables dynamic, scalable i18n message bundles capable of being code-split.

Why

  • Automatic bundles: No manual maintenance of message bundles. File-scoped bundles are created and loaded automatically.
  • Reduced message bundle bloat Only the messages need are loaded so no unused messages are loaded.
  • Tooling agnostic Configuration is generic enough so that any i18n tool can be used.
  • Easily code-split File-scoped message bundles mean that code splitting messages is trivial. Example.

For more explanation see Motivation.

Example

See full examples here.

i18n('key.path.hello');
i18n('key.path.sup');

      ↓ ↓ ↓ ↓ ↓ ↓

import { addMessages } from "i18n/addMessages.js";
addMessages([
  ["key.path.hello", "hello, world"],
  ["key.path.sup", "sup, world"],
]);
i18n('key.path.hello');
i18n('key.path.sup');

Table of Contents

Getting started

Installation

npm install babel-plugin-inline-i18n-messages --save-dev

Add to babel configuration

Add to your .babelrc or babel-loader configuration. For more information about the plugin options see Options.

{
  "plugins": [
    [
      "inline-i18n-messages",
      {
        "addMessagesSource": "path/to/addMessages/module",
        "getMessageFile": "path/to/getMessage/module",
        "extractKeysFile": "path/to/extractKeysFile/module",
        "locale": "en-us"
      }
    ]
  ]
}

Options

  • addMessagesSource (required): Path to client-side module that exports addMessages function. Should be an absolute path to avoid issues with folder structure. See addMessages.
  • getMessageFile (required): Path to build-side module that exports getMessage function. See getMessage.
  • extractKeysFile OR extractKeysType (required): Your configuration must include one of the following:
    • extractKeysFile: Path to build-side module that exports extractKeys function. See extractKeys.
    • extractKeysType: One of the supported extractKeysTypes: formatjs. See react-intl support for more informatiom.
  • locale: Locale string that is passed to your getMessage function.

react-intl support

If you are using formatjs as your i18n tool, there are a couple of features built into this plugin to get you up and running faster.

Instead of defining a extractKeysFile in your configuration, set extractKeysType to formatjs. Your babel configuration should look something like this:

{
  "plugins": [
    [
      "inline-i18n-messages",
      {
        "extractKeysType": "formatjs",
        "addMessagesSource": "path/to/addMessages/module",
        "getMessageFile": "path/to/getMessage/module",
        "locale": "en-us"
      }
    ]
  ]
}

Once you create your getMessage and addMessages functions and plug the messages into your <IntlProvider/>, you should be ready to go.

See a full react-intl example here.

For a more advanced example that pre-compiles the message into an AST using intl-messageformat-parser see this example.

Motivation

The problem

Most internationalization (i18n) libraries require you to statically define your i18n messages upfront in one large object. Visiting one page might require you to load the messages of the entire application. This creates an issue at large scales when those message objects can be massive.

You could manually split up your message objects and load them at specific parts of your application but this process is unwieldy. What happens if you delete a page? Create a new page? What if two pages require the same messages? You'd have to manually maintain this relationship in your i18n message bundles. This approach leads to an awkward and brittle maintenance experience.

The solution

What if instead of loading one large object upfront for the entire application, we file-scoped the loading of i18n messages. This would mean each file had its own i18n message bundle which was loaded only when the file was loaded. Think of this as similar to a CSS-in-JS solution for i18n messages. We are co-locating your messages in your JS like how CSS-in-JS co-locates your styles in your JS to reduce bloat. By loading only the messages we need, when we need them, we are never loading extraneous messages.

This is exactly what babel-plugin-inline-i18n-messages does automatically. When you include this plugin into your babel configuration, it will search for the message keys you use in each file and dynamically load only the messages you need per file. This makes it extremely easy to code-split parts of your application in a way that your i18n messages are also code-split.

Furthermore, it does so in a way that is agnostic to what i18n tooling you are using. If you are using react-intl/formatjs see react-intl support.

API

addMessages

A client-side module that exports a named function called addMessages. This function should accept an array of id and message arrays and inject them into your i18n tooling. This function will be dependent on your client-side i18n tooling. You'll add the path to this module as the addMessagesSource option in the plugin configuration.

To avoid issues with nested folder structure, you'll want to use an absolute path to this module. To achieve this you can use babel-plugin-module-resolver. See full examples here.

Example:

// src/i18n/messages.js
export const messages = {};

export function addMessages(idAndMessages) {
  idAndMessages.forEach(([id, message]) => {
    messages[id] = message;
  });
}

// src/i18n/index.js
import { messages } from "./messages.js";
import i18n from "i18n-tool";

i18n.init(messages);

See full examples here.

getMessage

A build-side module that exports a default function called getMessage. This function should accept a message key, locale, and default message and return a message. This function will be dependent on your localization flow and where you keep your translated messages. You'll add the path to this module as the getMessageFile option in the plugin configuration.

Example:

// i18n/getMessage.js
module.exports = function getMessage(key, locale, defaultMessage) {
  const file = fs.readFileSync(`./messages/${locale}.json`);
  const messages = JSON.parse(file);

  return messages[key] || defaultMessage;
};

See full examples here.

extractKeys

A build-side module that exports a default function called extractKeys. This function should accept a filename and return an array of message key string or an object containing key strings and default message strings. These keys will be passed to your getMessage function. This function will be dependent on your client-side i18n tooling. You'll add the path to this module as the extractKeysFile option in the plugin configuration.

Example:

// i18n/extractKeys.js
const { extract } = require("i18n-tool");

module.exports = function extractKeys(filename) {
  return extract(filename).keys;
};

See full examples here.