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

@bandf/i18n

v1.1.2

Published

Automatic, on-device internationalization for plain JavaScript and native Web Components, powered by the Bergamot translation engine compiled to WebAssembly.

Readme

@bandf/i18n

On-device internationalization for plain JavaScript and Web Components. Translation runs in the browser, in a worker, with the Bergamot engine (the engine behind Firefox Translations) compiled to WebAssembly and Mozilla's models: 54 languages from English, most of them both ways. Nothing is sent to a server; there is no key, no catalog and no build step to start with. Pages are not annotated: every text node, inline sentence and translatable attribute is translated in place, in the same nodes, and restored on the way back.

| you want to | read | |---|---| | see it run | The demo | | add it to a Vite project | In a Vite project, docs/VITE.md | | add it to a site without Vite | On any static host, docs/DEPLOYMENT.md | | translate from Node or a script | Command line, docs/API.md | | know what the page must and must not contain | Markup, docs/API.md | | the full API, options and events | docs/API.md | | how the DOM layer and the text pipeline work | docs/ARCHITECTURE.md, docs/TEXT-PIPELINE.md | | check every part by hand | docs/QA.md | | work on the library itself | Working in the repository | | know how this differs from the browser's own translation | Why not the browser's translation |

The demo

npx @bandf/i18n              # serves the demo from the package on a free port and opens it; --port=, --no-open

The demo is an unannotated page with a <language-select>, and links at the bottom to every test page: the library against a fake engine, real Lit components, the engine's budgets, a page that rewrites itself, hostile inputs, and snapshots of Wikipedia, MDN, Bootstrap and other public pages. The first language chosen downloads its model (25–40 MB) into the package's own models/ directory; a corpus page is snapshotted on first visit; Lit is installed for its page on first visit.

In a Vite project

npm install @bandf/i18n      # or yarn add @bandf/i18n
// vite.config.js
import { bandfI18n } from '@bandf/i18n/vite';

export default { plugins: [bandfI18n({ directions: [`en-fr`, `en-de`] })] };
<language-select></language-select>
import { createI18n, defineLanguageSelect } from '@bandf/i18n';

const i18n = createI18n({ sourceLocale: `en` });
defineLanguageSelect(i18n);
i18n.observe(document);

The plugin serves the models in development, downloading a direction the first time a page asks for it (verified against the hashes pinned in the package) into node_modules/.cache/bandf-i18n/models, and vite build copies the declared directions into dist/models/. prerender: { languages: ['fr'] } also writes dist/fr/index.html in French, so that visit downloads no model and search engines index French text. Build-time catalogs, source recording and every option: docs/VITE.md.

On any static host

npx @bandf/i18n models en-fr en-de    # downloads the pinned models into ./models

Serve that directory as models/ next to your pages, or name it with <meta name="bandf-i18n-models" content="/path/to/models/"> or createI18n({ models: { modelsUrl } }). Mozilla's registry does not allow cross-origin requests; every site hosts the models it offers. Headers, caching, storage and memory: docs/DEPLOYMENT.md.

Markup

The library reads only standard HTML:

  • translate="no" (or class="notranslate") — leave this subtree alone: brand names, formatted values, user content.
  • lang="fr" — this subtree is already in another language.
  • title, alt, placeholder, aria-label and the other translatable attributes are translated; code, kbd, samp, var, pre, text the user typed and embedded media are not.

Open shadow roots are followed; a closed one is passed explicitly (i18n.observe(this.shadowRoot)). Content the application writes later is translated as it changes, cached translations are applied before the next paint, and a locale change back to the source restores the original nodes and text. Reviewed translations are overrides keyed by source text; short labels come from a ten-language glossary or a role-aware carrier sentence. Placeholders such as {name} are protected, and an output that loses one is rejected rather than shown.

Programmatic use: i18n.translate(text, { role }), i18n.translateBatch(items), i18n.setLocale(), i18n.plural(), number(), date(), list(); events progress, statechange, localechange, error, translationfallback. See docs/API.md.

Command line

npx @bandf/i18n [demo] [--port=0] [--no-open]
npx @bandf/i18n models [--out=models] [en-fr en-de ...]
npx @bandf/i18n catalogs --languages=fr,de [--sources=bandf-i18n.sources.json] [--out=catalogs] [--models=models] [--source=en]
npx @bandf/i18n prerender --languages=fr,de [--root=dist] [--out=dist] [--base=/] [--models=models] [--source=en] [--catalogs=catalogs] [pages...]
npx @bandf/i18n list
  • demo (the default) serves the demo page and opens it in the default browser, or in the command named by BROWSER; --no-open or BROWSER=none skips the opening.
  • models downloads the pinned models (every direction without arguments) and verifies them; a second run downloads nothing.
  • catalogs translates a recorded sources file (docs/VITE.md) into <out>/<language>.json plus review.json for rejected strings.
  • prerender renders the HTML pages under --root in each language into <out>/<language>/ (needs jsdom).
  • list prints the pinned directions with architecture, tier and size.

Under Node, createNodeEngine() from @bandf/i18n/node runs the engine on worker threads with models read from disk, and createI18n({ engine }) on top of it is the complete pipeline (docs/API.md, "Recording and Node").

Layout

  • src/ — the library: engine/, dom/, text/, labels/, elements/, cache.js; the module map is in docs/ARCHITECTURE.md
  • vite/ — the Vite plugin
  • bin/ — the bandf-i18n command
  • tools/ — models.js (pinned downloads), build-catalogs.js, prerender.js, serve.js (the package server), corpus-snapshot.js; in the repository also local-models.js (yarn models), mirror-models.js (yarn models:refresh) and build-engine.js (yarn engine:build)
  • engine/ — the built engine, VERSION.json and license (engine/README.md)
  • models/ — manifest.json (every direction Mozilla's registry has released: registry path, size and SHA-256 of each file, quality metrics, tier), directions.json (what yarn models mirrors and the architecture preference yarn models:refresh pins with), and the mirrored binaries, git-ignored; a pivot through English needs both halves (de-en and en-fr for German to French)
  • examples/ — the demo (index.html, served as /) and vite-app/
  • tests/, scripts/ — the suites, their pages and their runners; the pages ship in the package so the demo can link to them, the runners do not

Working in the repository

git clone https://gitlab.com/bandf-os/i18n.git && cd i18n
yarn install             # Yarn 4, pinned in .yarn/releases; node_modules linker
yarn models              # the directions the demo and suites use (~400 MB); models:refresh re-pins every released direction
yarn dev                 # serves on a free port, prints the URL and opens it; --no-open skips, PORT chooses the port

The development server serves the whole repository; the demo links to every page:

| page | what it shows | |---|---| | / | the demo (examples/index.html): an unannotated page, the language control, live rewrites, per-direction download progress | | /tests/browser.html | the DOM, protocol and cache suites against a fake engine; results render on the page | | /tests/lit.html | real Lit components translated, re-rendered by Lit, reordered, swapped and restored | | /tests/engine/index.html | the real engine, run on open: load times cold and warm, throughput, token survival, markup retention per language, pivoting, memory; the corpus is tests/engine/corpus.js | | /tests/engine/auto.html | the same run, self-reporting; used for Firefox and Safari | | /tests/page/live.html | a page that rewrites itself continuously while being translated | | /tests/page/hostile.html | code, placeholders, URLs, RTL, nested inline markup, translate="no" | | /tests/corpus/cache/*.html | snapshots of public pages, taken on first request (or all at once by yarn test:corpus); ?lang=fr runs the check on one, restore included; ?lang=fr&hold leaves it translated | | examples/vite-app/ | a Vite project with recorded sources and build-time catalogs (npx vite inside it) |

The suites drive those pages in headless Chrome:

yarn lint                # eslint.config.js; lint:fix applies what it can
yarn test                # Node: text pipeline, labels, core contracts, worker protocol, the DOM layer under jsdom
yarn test:browser        # /tests/browser.html, twice in one profile (fresh and returning visitor)
yarn test:lit            # /tests/lit.html
yarn test:engine         # /tests/engine/index.html
yarn test:page           # /tests/page/: live churn, hostile inputs, RTL, restore, residency
yarn test:corpus         # the public-page snapshots: fidelity, coverage, throughput
yarn test:vite           # examples/vite-app: dev server recording, build, catalogs, bundled engine, pre-rendering
yarn test:package        # packs the tarball, installs it into a throwaway project, runs Vite dev and build against it
yarn test:browsers       # macOS: auto.html in Firefox and Safari
yarn test:all            # everything above

Measurements (docs/QA.md, "Measurements"): yarn bench:labels, bench:page, bench:parallel, measure:languages.

Why not the browser's translation

Two different things hide behind "the browser can translate pages".

The browser's translate button (Chrome's bar, Firefox Translations, Safari). The visitor does it to your site; you do not do it for them. It cannot be tied to a language control in your UI, cannot ship reviewed strings or terminology, does not tell the page what it did, and behaves differently in each browser — Chrome's sends text to Google's servers. Most visitors never find it. With this library the site translates itself, the same way in every browser, as a feature you own.

Chrome's Translator API (the one a page can call). It translates strings, only in Chrome — no Firefox, no Safari — and only on devices Chrome deems eligible. The engine is also the smallest part of the job. Deciding what on a page is translatable, keeping markup and node identity intact, watching for changes without loops, protecting placeholders and code, handling short labels with roles and a glossary, restoring the source, persisting results, and building reviewable catalogs at build time with the same model the visitor runs — that is the layer above any engine, and it is what this library is. It carries its own engine so that layer behaves identically everywhere, with model versions you pin, so a catalog built on your machine matches what the visitor sees.

Licenses

The library is MIT. The engine and the models are Mozilla Public License 2.0; see THIRD_PARTY_NOTICES.md and engine/LICENSE.