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

vite-plugin-build-time-i18n

v0.1.1

Published

Vite plugin for build-time i18n with static translation replacement and ICU message precompilation.

Downloads

205

Readme

vite-plugin-build-time-i18n

Build-time i18n for Vite. This plugin replaces string-literal translation calls during build so your app ships translated output instead of doing key lookup at runtime.

It is designed for projects that want:

  • static replacement for simple messages
  • precompiled formatting for plural, select, number, date, and time messages
  • build-time diagnostics for missing, unused, or non-precompilable translation keys
  • zero runtime translation catalog lookup in application code

License: LICENCE

Why use it

Instead of shipping a message catalog and resolving keys in the browser, this plugin rewrites calls such as:

const title = t("app.page.title");
const countLabel = t("app.page.priorityCount", { count: 2 });

into either:

  • a plain string literal for static messages
  • a generated formatter call for messages that need interpolation or ICU-style branching

That keeps translated output close to the final bundle and catches catalog problems during the build.

Requirements

  • Node.js 25+
  • Vite 8+

Install

npm install vite-plugin-build-time-i18n

vite is a peer dependency and must already exist in the consuming project.

Quick start

// vite.config.ts
import { defineConfig } from "vite";
import { buildTimeI18nPlugin } from "vite-plugin-build-time-i18n";

export default defineConfig({
  plugins: [
    ...buildTimeI18nPlugin({
      locale: "de",
      localesDir: "src/i18n/locales",
    }),
  ],
});
// src/i18n/locales/de.json
{
  "app": {
    "page": {
      "title": "Startseite",
      "priorityCount": "{count, plural, one {# Prioritaet} other {# Prioritaeten}}"
    }
  }
}
// application code
function t(key: string, values?: Record<string, unknown>) {
  return key;
}

const title = t("app.page.title");
const countLabel = t("app.page.priorityCount", { count: 2 });

Build output shape:

const title = "Startseite";

import { __i18nFormat } from "virtual:build-time-i18n-helper";

const countLabel = __i18nFormat(
  {
    type: "message",
    parts: [
      /* compiled parts */
    ],
  },
  { count: 2 },
  "de",
);

How it works

During build, the plugin:

  1. reads <localesDir>/<locale>.json
  2. flattens nested message objects into dotted keys
  3. precompiles supported message syntax
  4. scans matching source files for direct calls to the configured translation function
  5. rewrites supported calls in the final bundle

Locale file format

Locale files must be top-level JSON objects. Nested objects are flattened into dotted keys.

{
  "app": {
    "route": {
      "modeLabel": "Routenmodus"
    },
    "stats": {
      "participants": "Teilnehmende: {count, number, compact}"
    }
  }
}

This becomes:

  • app.route.modeLabel
  • app.stats.participants

Message values must be either strings or nested objects.

Options

type BuildTimeI18nPluginOptions = {
  locale: string;
  localesDir?: string;
  include?: RegExp;
  functionName?: string;
  strictMissing?: boolean;
  failOnDynamicKeys?: boolean;
  includeEnvironmentLabelInWarnings?: boolean;
};

locale

Active locale code. The plugin reads <localesDir>/<locale>.json.

localesDir

Directory containing locale JSON files.

Default candidates (first existing wins, resolved from process.cwd()):

  • <projectRoot>/locales
  • <projectRoot>/i18n/locales

include

Regular expression used to choose which files run through the transform hook.

Default:

/\.[cm]?[jt]sx?$/;

functionName

Identifier name to rewrite.

Default: "t"

Only direct identifier calls are rewritten:

t("app.page.title");

These are not rewritten:

i18n.t("app.page.title");
translations[fn]("app.page.title");

strictMissing

Controls how missing keys are handled.

  • true (default): fail the build
  • false: warn and replace with the key string

failOnDynamicKeys

Controls how non-literal translation keys are handled.

  • true (default): fail the build
  • false: warn and leave the call non-precompiled

includeEnvironmentLabelInWarnings

Controls whether diagnostics include the current Vite environment label.

  • true (default): include labels such as [client], [ssr], or [unknown]
  • false: use plain [build-time-i18n] warnings without environment labels

Supported message syntax

This plugin supports a focused subset of ICU-style message formatting.

Variables

{name}

Numbers

{amount, number}
{amount, number, integer}
{amount, number, percent}
{amount, number, compact}
{amount, number, currency:EUR}

Dates and times

{when, date}
{when, date, short}
{when, date, medium}
{when, date, long}
{when, date, full}

{when, time}
{when, time, short}
{when, time, medium}
{when, time, long}
{when, time, full}

Select

{status, select, open {Open} closed {Closed} other {Unknown}}

Plural

{count, plural, =0 {No items} one {# item} other {# items}}

Rules:

  • plural and select must include other
  • # is only meaningful inside plural branches
  • invalid styles fail during catalog precompile

Diagnostics

The plugin reports diagnostics with the prefix [build-time-i18n].

By default, warnings include an environment label, for example:

  • [build-time-i18n] [client] ...
  • [build-time-i18n] [ssr] ...

Unused-key diagnostics are environment-scoped. A key may be used in one environment and unused in another.

When locale JSON cannot be parsed, errors include the file path and parser details.

It can report:

  • missing translation keys
  • unused translation keys
  • dynamic translation calls that cannot be precompiled
  • invalid message syntax or unsupported formatting styles

Caveats

  • This is not a full ICU MessageFormat implementation.
  • Only direct calls to the configured function name are rewritten.
  • The first argument must be a string literal to be precompiled.
  • The plugin applies only to Vite build mode.
  • Locale files must be valid JSON and must contain a top-level object.

Authoring Guardrails For AI Agents

This repository includes agent guidance and a validator to keep translation usage compatible with build-time precompilation.

  • Skill: .github/skills/build-time-i18n-authoring/SKILL.md
  • Instruction profile: .github/instructions/build-time-i18n-authoring.instructions.md
  • Validator command: npm run validate:i18n (runs with --allow-missing-locales in this repository)

The validator checks:

  • locale JSON parse and shape issues
  • precompile compatibility using plugin build-time checks
  • key parity across locale files
  • placeholder mismatch warnings across locales
  • dynamic translation key calls in non-test source files
  • member/computed translation calls in non-test source files that are not rewritten

Compared to established runtime translators, this plugin intentionally trades runtime flexibility for build-time replacement and diagnostics. In practice, dynamic key resolution and runtime locale behavior are more limited.

Advanced

When a message needs runtime formatting, the plugin injects a virtual helper import:

import { __i18nFormat } from "virtual:build-time-i18n-helper";

That helper uses native Intl.PluralRules, Intl.NumberFormat, and Intl.DateTimeFormat under the hood.

Development

npm install
npm run typecheck
npm run validate:i18n
npm test