hablas is a Vite-first i18n package that combines:
- extraction/sync plugin (
hablas/vite) - virtual runtime modules (
virtual:i18n+ framework adapters) - ICU-aware helpers for plural and select (
t.plural,t.select)
It is designed for fast DX during development: add messages in code, keep locale files synced, and consume translations through a single runtime API.
- Vite-native virtual modules for app consumption.
- Deterministic message keys based on source content hash.
- Locale file sync on startup and watch.
- Supports ICU plural/select flows and exact matches (
=0,=1, ...). - Optional AI autofill for empty locale entries.
- Framework adapters for React, React Signals, Preact, Vue, Svelte, and Solid.
npm i hablas
# or
pnpm add hablas
# or
bun add hablas// vite.config.ts
import { defineConfig } from "vite"
import react from "@vitejs/plugin-react"
import { extractedI18nPlugin } from "hablas/vite"
export default defineConfig({
plugins: [
react(),
extractedI18nPlugin({
localesDir: "locales",
sourceLocale: "en",
defaultLocale: "en",
include: ["src/**/*.{ts,tsx}"],
removeUnused: true,
verbose: true,
}),
],
})import { t } from "virtual:i18n"
t("Hello {name}", { name: "Lucas" })
t.plural(
"count",
{
"=0": "Your cart is empty.",
one: "You have {count} item.",
other: "You have {count} items.",
},
{ count: 3 }
)
t.select(
"role",
{
admin: "Welcome back, admin.",
other: "Welcome back.",
},
{ role: "admin" }
)
await t.setLocale("fr")For TypeScript, add a paths mapping (TypeScript does not resolve virtual:* specifiers by default):
// tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"virtual:i18n": ["./node_modules/hablas/types/virtual-i18n.d.ts"],
"virtual:i18n-react": ["./node_modules/hablas/types/virtual-i18n-react.d.ts"],
"virtual:i18n-react-signals": [
"./node_modules/hablas/types/virtual-i18n-react-signals.d.ts"
],
"virtual:i18n-preact": ["./node_modules/hablas/types/virtual-i18n.d.ts"],
"virtual:i18n-vue": ["./node_modules/hablas/types/virtual-i18n.d.ts"],
"virtual:i18n-svelte": ["./node_modules/hablas/types/virtual-i18n.d.ts"],
"virtual:i18n-solid": ["./node_modules/hablas/types/virtual-i18n.d.ts"]
}
}
}And include:
/// <reference types="hablas" />virtual:i18n-reactvirtual:i18n-react-signalsvirtual:i18n-preactvirtual:i18n-vuevirtual:i18n-sveltevirtual:i18n-solid
extractedI18nPlugin({
// ...
autoTranslate: {
aiGatewayApiKey: process.env.AI_GATEWAY_API_KEY!,
aiModel: process.env.AI_MODEL!,
},
})Notes:
- Skipped when
CI=trueorCI=1. - Only fills missing/empty locale values.
- Preserves placeholders and ICU structures.
npm run build
npm run lint
npm run format
npm run testThree Vite examples are included in examples/:
examples/react-hookexamples/react-signalsexamples/svelte
Each example uses the same UI/content with locales:
enfrpt-BRru-RU
Run one example:
cd examples/react-hook
npm install
npm run dev