Skip to content

wuchalejs/wuchale

wuchale logo


npm package build status Start new PR in StackBlitz Codeflow discord chat


📜wuchale🪶

wuchale (pronounced "wuh-cha-lay") is a compile-time internationalization toolkit that requires no code changes. Write your components naturally, and wuchale automatically extracts and replaces translatable messages at build time.

  • 🧼 No extra syntax! - Your normal code is enough, your codebase stays clean
  • 📦 Tiny catalogs to bundle - Text catalogs are just arrays, no keys necessary, like Protobuf
  • 🔌 Zero-effort integration - Add i18n to existing projects without rewriting code
  • 🧩 Framework agnostic - Works with React, Preact, Svelte(Kit), SolidJS, Astro, and plain JS/TS
  • ✨ Optional AI translation - Configurable integration for automatic on-the-fly translations
  • ⚡ Full, granular HMR support - Live updates during development, including AI auto-translation
  • 📦 Tiny footprint - Very few (less than 5) additional dependencies, no bloated node_modules
  • 🧠 Smart extraction - Uses AST analysis to handle nested markup, conditionals, loops, and complex interpolations
  • 🌍 Standard .po files - Compatible with existing translation tools and workflows

A taste

With traditional i18n:

<p>{t('Hello')}</p>
<p><Trans>Welcome {userName}</Trans></p>

With wuchale:

<p>Hello</p>
<p>Welcome {userName}</p>

No imports, no wrappers, no annotations. wuchale handles everything at compile time by analyzing your code and automatically extracting translatable strings.

Getting started

See the Getting Started guide for instructions specific to your project type.

How it works

  1. Scans your source code using AST and identify translatable text content
  2. Extracts strings into standard .po translation files for translators
  3. Compiles catalogs into compact modules which export arrays
  4. Replaces strings with translation function calls that access messages by indices from the arrays

Your original code stays clean and readable, while the build output is automatically internationalized.

Example

Let's say you have:

// src/components/Welcome.jsx
function Welcome({ name }) {
  return (
    <div>
      <h1>Welcome to our app!</h1>
      <p>Hello, {name}! How are you today?</p>
      <button>Get started</button>
    </div>
  )
}

The messages are extracted into a .po file. for Spanish for example, after translation, it looks like:

#~ src/components/Welcome.jsx
msgid "Welcome to our app!"
msgstr "¡Bienvenido a nuestra aplicación!"

#~ src/components/Welcome.jsx
msgid "Hello, {0}! How are you today?"
msgstr "¡Hola, {0}! ¿Cómo estás hoy?"

#~ src/components/Welcome.jsx
msgid "Get started"
msgstr "Comenzar"

Then they are compiled into a compact form optimized for loading (just an array):

export let c = ["¡Bienvenido a nuestra aplicación!",["¡Hola, ",0,"! ¿Cómo estás hoy?"],"Comenzar"]

And your code is transformed into a version that accesses them by index:

// src/components/Welcome.jsx
import { _load_ } from '../locales/loader.js'

function Welcome({ name }) {
  const _w_runtime_ = _load_('main')
  return (
    <div>
      <h1>{_w_runtime_(0)}</h1>
      <p>{_w_runtime_(1, [name])}</p>
      <button>{_w_runtime_(2)}</button>
    </div>
  )
}

Check out full working examples for different setups at wuchalejs/examples to see wuchale in action with different frameworks.

Supported Features

  • Complex interpolations: Welcome {userName}, you have {count} messages
  • Nested markup: <p>Visit our <a href="/help">help page</a> for more info</p>
  • Conditional content: Handles dynamic content in templates
  • Loop structures: Automatic extraction from repeated elements
  • URLs: E.g. /about to /de/uber-uns
  • Hot Module Replacement: Live translation updates during development

Repository structure

This is a monorepo that houses these packages:

Package Description Latest
wuchale Core + CLI + Vanilla adapter wuchale
@wuchale/jsx JSX adapter (for React and SolidJS) @wuchale/jsx
@wuchale/svelte Svelte adapter @wuchale/svelte
@wuchale/astro Astro adapter @wuchale/astro
@wuchale/vite-plugin The Vite plugin @wuchale/vite-plugin

🤝 Contributing

Contributions are welcome! Please check out the test suites located inside each package for examples of supported scenarios.

❤️ Sponsors

This project is supported by the community. Become a sponsor and get your name or logo listed here!

Sponsor on GitHub Donate on Open Collective

Special thanks to our supporters:

hayzamjs p-mercury perdix

And one private donor 🙏.

Inspiration

This project was inspired by Lingui especially some of its workflow. If you've used Lingui before, you'll find familiar concepts like extraction and compilation.

Where wuchale differs, among other things, is that you don't need to change your code, catalogs compile smaller than any other tool (including Lingui's), and it integrates with a wider range of frameworks.

License

MIT