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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@shopify/react-i18n-swc-plugin

v0.7.6

Published

swc transform plugin for `@shopify/react-i18n`

Downloads

470

Readme

shopify_react_i18n_swc_plugin

Plugin for @shopify/react-i18n.

Usage

To load plugins, you may use swcrc's jsc.experimental configs:

{
  jsc: {
    ...
   experimental: {
     ...
     cache_root: String // optional, specify where swc will create wasm bytecode cache
    // list of plugins. If `pluginname` is resolvable to npm package, it'll try to load from installed npm packages.
    // or it can be an absolute path to the .wasm binary
     plugins: [ ['@shopify/react-i18n-swc-plugin', {cwd: <root_directory_here>}] ]
   }
}

This plugin will look for an adjacent translations folder containing, at minimum, an en.json file (the default locale). It will then iterate over each reference to the useI18n hook or withI18n decorator and, if the reference is a call expression with no arguments, and inject the appropriate arguments.

Note

Make sure you pass the root directory you would like the plugin to start working from as this plugin will not do anything without this.

Default Transform

Given folder structure

├── MyComponent.tsx
└── translations
   └── en.json
   └── fr.json
   └── jp.json

File content

// Within translations/en.js

{
  "heading": "All Films"
}

// Within translations/fr.js

{
  "heading": "fr_All Films"
}

// Within translations/jp.js

{
  "heading": "jp_All Films"
}
// Within MyComponent.tsx:

useI18n();

// Becomes:

import _en from "./translations/en.json";

useI18n({
  id: "MyComponent_<hash>",
  fallback: _en,
  async translations(locale) {
    if (["fr", "jp"].indexOf(locale) < 0) {
      return;
    }

    return import(
      /* webpackChunkName: "MyComponent_<hash>-i18n", webpackMode: "lazy-once" */ `./translations/${locale}.json`
    ).then((dict) => dict && dict.default);
  },
});

Options

mode

Type: with-dynamic-paths, with-explicit-paths, from-generated-index, from-dictionary-index

Default: with-dynamic-paths

with-explicit-paths

Use this mode with bundlers that require import paths to be explicit.

The babel plugin uses dynamic imports by default to resolve translation locations. Some bundlers however require that imports be explicity stated so that the bundler knows what files are to be included in the final generated bundle. Examples of bundlers with this behaviour include Metro and rollup.js. Configure the plugin to use explicit paths rather than dynamic imports with the with-explicit-paths options.

Usage
// webpack.config.js
module.exports = {
  resolve: {
    extensions: [".js"],
  },
  module: {
    rules: [
      {
        test: /\.(js)$/,
        use: {
          loader: "babel-loader",
          options: {
            plugins: [
              "@shopify/react-i18n/babel",
              { mode: "with-explicit-paths" },
            ],
          },
        },
      },
    ],
  },
};

Transform

With two locale translation files (default being en):

// After auto-fill:

import _en from "./translations/en.json";

useI18n({
  id: "MyComponent_<hash>",
  fallback: _en,
  async translations(locale) {
    if (locale !== "jp") {
      return;
    }

    return import(
      /* webpackChunkName: "MyComponent_<hash>-i18n" */ "./translations/jp.json"
    ).then((dict) => dict && dict.default);
  },
});

With three or more locale translation files (default being en):

// After auto-fill:

import _en from "./translations/en.json";

useI18n({
  id: "MyComponent_<hash>",
  fallback: _en,
  async translations(locale) {
    const returnDefault = (dict) => dict && dict.default;

    switch (locale) {
      case "fr":
        return import(
          /* webpackChunkName: "MyComponent_<hash>-i18n" */ "./translations/fr.json"
        ).then(returnDefault);
      case "jp":
        return import(
          /* webpackChunkName: "MyComponent_<hash>-i18n" */ "./translations/jp.json"
        ).then(returnDefault);
    }
  },
});

from-generated-index

Use this mode to avoid caching issues when integrating with babel-loader.

This is swc-loader here, update this. Because babel-loader's cache is based on a component's source content hash, newly added translation files will not invalidate the component's Babel cache. To combat this, run the generateTranslationIndexes function before building, and configure the plugin to use its from-generated-index mode.

The generator will look for any translations folders and generate an array of local ids in translations/index.js based on the {locale}.json files found. We recommend that you add **/translations/index.js to .gitignore to make sure the generated files are not checked-in.

Usage
// webpack.config.js
module.exports = {
  resolve: {
    extensions: [".js", ".jsx"],
  },
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        use: [
          {
            loader: "babel-loader",
            options: {
              plugins: [
                "@babel/plugin-syntax-dynamic-import",
                ["@shopify/react-i18n/babel", { mode: "from-generated-index" }],
              ],
            },
          },
        ],
      },
    ],
  },
};
// generate-translations.js
const {
  generateTranslationIndexes,
} = require('@shopify/react-i18n/generate-index');

generateTranslationIndexes();
webpack(require(./webpack.config.js));
Transform
// Generated translations/index.js from generateTranslationIndexes()
export default ["fr", "jp"];
// Within MyComponent.tsx:

useI18n();

// Becomes:

import _en from "./translations/en.json";
import __shopify__i18n_translations from "./translations";

useI18n({
  id: "MyComponent_<hash>",
  fallback: _en,
  async translations(locale) {
    if (__shopify__i18n_translations.indexOf(locale) < 0) {
      return;
    }

    return import(
      /* webpackChunkName: "MyComponent_<hash>-i18n", webpackMode: "lazy-once" */ `./translations/${locale}.json`
    ).then((dict) => dict && dict.default);
  },
});

from-dictionary-index

Use this mode to statically embed locale-specific translations.

For large applications, even asynchronously loaded translations can significantly degrade the user experience:

  • Bundlers like webpack have to embed kilobytes of data to track each translation import
  • Users not using the "default" language have to download kilobytes of translations for every language

To avoid this, it is possible to build versions of app with specific locale translations embedded directly in JavaScript.

Usage
// webpack.config.js
{
  plugins: [
    ['@shopify/react-i18n/babel', {mode: 'from-dictionary-index'}],
  ],
}

Then generate translations/index.js files containing specific locale data using the @shopify/react-i18n/generate-dictionaries helper. e.g., the following code generates three versions of an application with English, French, and German content using webpack.

// generate-translations.js
const {
  generateTranslationDictionaries,
} = require('@shopify/react-i18n/generate-dictionaries');

// Build English app.
await generateTranslationDictionaries(['en']);
webpack(require(./webpack.config.js));

// Build French app.
await generateTranslationDictionaries(['fr'], {fallbackLocale: 'en'});
webpack(require(./webpack.config.js));

// Build German app.
await generateTranslationDictionaries(['de'], {fallbackLocale: 'en'});
webpack(require(./webpack.config.js));
Transform
// Generated translations/index.js using generateTranslationDictionaries(['fr'], {fallbackLocale: 'en'});

export default JSON.parse(
  '{"en":{"heading":"All Films"},"fr":{"heading":"fr_All Films"}}'
);
// Within MyComponent.tsx:

useI18n();

// Becomes:
import __shopify__i18n_translations from "./translations";

useI18n({
  id: "MyComponent_<hash>",
  fallback: Object.values(__shopify__i18n_translations)[0],
  translations(locale) {
    return Promise.resolve(__shopify__i18n_translations[locale]);
  },
});

defaultLocale

Type: string

Default: en

Setting the default locale to something other than en

If you want your default locale to be something else than English because it's not your primary locale, you can pass the defaultLocale option to the babel plugin:

// webpack.config.js
module.exports = {
  resolve: {
    extensions: [".js"],
  },
  module: {
    rules: [
      {
        test: /\.(js)$/,
        use: {
          loader: "babel-loader",
          options: {
            plugins: [["@shopify/react-i18n/babel", { defaultLocale: "fr" }]],
          },
        },
      },
    ],
  },
};