---
url: /guide/getting-started.md
---
# Getting Started
This guide will help you set up `@intl-ai/unplugin` in your project.
## Installation
### Prerequisites
* Node.js 22+
* A package manager: npm, pnpm, or yarn
* An AI model provider (see [AI Model Setup](/guide/ai-model) for options)
### Install the Package
::: code-group
```sh [npm]
npm install @intl-ai/unplugin
```
```sh [pnpm]
pnpm add @intl-ai/unplugin
```
```sh [yarn]
yarn add @intl-ai/unplugin
```
```sh [bun]
bun add @intl-ai/unplugin
```
:::
### For Next.js Projects
Install the `@intl-ai/next` package in your Next.js project:
::: code-group
```sh [npm]
npm install @intl-ai/next
```
```sh [pnpm]
pnpm add @intl-ai/next
```
```sh [yarn]
yarn add @intl-ai/next
```
```sh [bun]
bun add @intl-ai/next
```
:::
## Quick Start
### 1. Create Configuration File
Create an `intl-ai.config.ts` file in your project root.
If you do not have a local model or cloud API key, you can use OpenRouter's free tier with no account setup beyond an API key.
### Local model (LM Studio)
```typescript
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
const lmstudio = createOpenAICompatible({
name: "lmstudio",
baseURL: "http://127.0.0.1:1234/v1",
});
export default {
model: lmstudio("your-model-name"),
defaultLocale: "en",
locales: ["en", "de", "es", "fr"],
localeDir: "./locales",
};
```
### Cloud model (OpenRouter free tier)
```typescript
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
const openrouter = createOpenAICompatible({
name: "openrouter",
baseURL: "https://openrouter.ai/api/v1",
});
export default {
model: openrouter("google/gemini-2.0-flash-exp:free"),
defaultLocale: "en",
locales: ["en", "de", "es", "fr"],
localeDir: "./locales",
};
```
See [AI model setup](/guide/ai-model) for all provider options.
**Key Configuration:**
* `model`: Your AI model instance (see [AI model setup](/guide/ai-model) for other providers)
* `defaultLocale`: The primary language for your application
* `locales`: Array of supported language codes
* `localeDir`: Directory where translation files will be stored
### 2. Set Up Your Bundler
::: code-group
```typescript [Vite]
import { defineConfig } from "vite";
import intlAi from "@intl-ai/unplugin/vite";
export default defineConfig({
plugins: [intlAi()],
});
```
```javascript [Webpack]
const IntlAiPlugin = require("@intl-ai/unplugin/webpack");
module.exports = {
plugins: [new IntlAiPlugin()],
};
```
:::
See [Build systems](/guide/build-systems/) for Next.js, Rollup, esbuild, Rspack, Rolldown, Farm, and more.
### 3. Create Directory and Translation Files
Create the directory specified in your config (default: `./locales`), then add your first translation file for the default locale:
**locales/en.json:**
```json
{
"greeting": "Hello, {name}!",
"welcome": "Welcome to our application",
"description": "This is a sample translation"
}
```
## Supported Bundlers
`@intl-ai/unplugin` works with all major bundlers. See [Build systems](/guide/build-systems/) for dedicated setup guides:
* [Vite](/guide/build-systems/vite) - Modern, fast build tool
* [Webpack](/guide/build-systems/webpack) - Industry standard bundler
* [Rollup](/guide/build-systems/rollup) - Flexible module bundler
* [esbuild](/guide/build-systems/esbuild) - Extremely fast JavaScript bundler
* [Rspack](/guide/build-systems/rspack) - Rust-based, webpack-compatible bundler
* [Rolldown](/guide/build-systems/rolldown) - Rust-powered Rollup-compatible bundler
* [Farm](/guide/build-systems/farm) - Rust-based web build tool
* [Next.js](/guide/build-systems/next-js) - React framework with Turbopack bridge
## Verify Installation
To verify everything is working:
1. Start your development server: `npm run dev`, `pnpm dev`, or `yarn dev`
2. Check that your bundler loads without errors and translation files are being processed
3. Verify translations render correctly in your application
If you encounter issues, check the [AI model setup](/guide/ai-model) guide to ensure your model provider is configured correctly.
---
---
url: /guide/installation.md
---
# Installation
Choose the install method that fits your platform and workflow.
## Install script (macOS / Linux)
Download a pre-built binary from GitHub Releases:
```bash
curl -fsSL https://intl-ai.pages.dev/install.sh | bash
```
Override the install directory or version with environment variables:
```bash
export INTL_AI_INSTALL_DIR="$HOME/.local/bin"
export INTL_AI_VERSION="v0.3.0"
curl -fsSL https://intl-ai.pages.dev/install.sh | bash
```
## npm / npx (any platform with Node.js 22+)
Run without installing:
```bash
npx @intl-ai/cli fill
```
Or add to your project:
```bash
npm install -D @intl-ai/cli
pnpm add -D @intl-ai/cli
bun add -D @intl-ai/cli
```
## Homebrew (macOS / Linux)
The tap formula is populated automatically as part of the release, so `brew install sigilco/tap-intl-ai/intl-ai` works immediately after each release.
```bash
brew tap sigilco/tap-intl-ai
brew install intl-ai
brew upgrade intl-ai
```
## mise (version pinning)
Add to your project's `.mise.toml`:
```toml
[tools]
intl-ai = "0.3.0"
```
Then run:
```bash
mise install
```
Note: until the registry entry is merged into mise's official registry, use `mise use npm:intl-ai@0.3.0` or add `packaging/mise/intl-ai.toml` from this repo to your custom registry.
## Verify
```bash
intl-ai --help
intl-ai fill --help
```
## Next steps
* [Set up your AI model](/guide/ai-model)
* [Get started with a bundler](/guide/getting-started)
---
---
url: /guide/ai-model.md
---
# AI model setup
Translation is structured and instruction-following. Budget models handle it well, so you do not need a flagship model.
## Pick a provider
Three paths work: local, cloud, or an aggregator.
### Local: LM Studio
[LM Studio](https://lmstudio.ai) runs models locally. This is ideal for development, testing, and privacy-sensitive work.
Download LM Studio, load any model that fits your hardware, and start the local server.
```typescript
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
const lmstudio = createOpenAICompatible({
name: "lmstudio",
baseURL: "http://127.0.0.1:1234/v1",
});
export default {
model: lmstudio("your-model-name"),
};
```
### Cloud: OpenAI-compatible providers
Any provider with an OpenAI-compatible endpoint works the same way: import the provider wrapper, pass a model identifier, and set your API key in the environment.
* **OpenAI**: set `OPENAI_API_KEY`. See [platform.openai.com](https://platform.openai.com).
* **Anthropic**: set `ANTHROPIC_API_KEY`. See [console.anthropic.com](https://console.anthropic.com).
* **Google**: set `GOOGLE_GENERATIVE_AI_API_KEY`. See [aistudio.google.com](https://aistudio.google.com).
* **Azure OpenAI**, **Cohere**, **Mistral**, and others: use the matching Vercel AI SDK provider package.
Example with OpenAI:
```typescript
import { openai } from "@ai-sdk/openai";
export default {
model: openai("your-model-name"),
};
```
### Aggregator: OpenRouter
[OpenRouter](https://openrouter.ai) gives you one API key for many providers and a free tier.
A stable free model at the time of writing is `google/gemini-2.0-flash-exp:free`.
If it stops working, check OpenRouter's free model list and update this single reference.
```typescript
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
const openrouter = createOpenAICompatible({
name: "openrouter",
baseURL: "https://openrouter.ai/api/v1",
headers: {
"HTTP-Referer": "https://your-site.com",
"X-Title": "your-app-name",
},
});
export default {
model: openrouter("google/gemini-2.0-flash-exp:free"),
};
```
## Context window
Use a model with a minimum context window of 16,000 tokens. Every provider listed above exceeds this.
## Troubleshooting
If translation fails, check:
* The API key environment variable is set.
* The provider's server is reachable from your machine.
* Your model identifier matches the provider's documentation.
---
---
url: /guide/configuration.md
---
# Configuration
intl-ai reads a single config file. The JSON format is validated against a published JSON Schema and works in any runtime.
## Config file discovery
The CLI and bundler plugins look for one of these files in your project root:
* `intl-ai.config.json` (recommended for runtime-agnostic setups and non-Node consumers)
* `intl-ai.config.ts` (when you need a live Vercel AI SDK model instance)
## JSON config
```json
{
"$schema": "https://www.schemastore.org/intl-ai.json",
"defaultLocale": "en",
"locales": ["en", "es", "fr"],
"localeDir": "./locales",
"model": "your-provider/your-model",
"apiKey": "${OPENAI_API_KEY}",
"baseURL": "https://api.openai.com/v1",
"maxRetries": 3
}
```
## Required options
### `defaultLocale`
Source language for translations.
```json
"defaultLocale": "en"
```
### `locales`
All supported locale codes.
```json
"locales": ["en", "es", "fr"]
```
### `localeDir`
Directory containing locale JSON files.
```json
"localeDir": "./locales"
```
### `model`
Model identifier for your provider. Use the full `provider/name` form if your provider supports it.
```json
"model": "your-provider/your-model"
```
### `apiKey`
API key for your provider. We recommend reading it from an environment variable.
```json
"apiKey": "${OPENAI_API_KEY}"
```
## Optional options
### `baseURL`
Provider endpoint. Defaults to `https://api.openai.com/v1`.
```json
"baseURL": "https://api.openai.com/v1"
```
### `glossary`
Terms to preserve during translation.
```json
"glossary": {
"React": "React",
"TypeScript": "TypeScript"
}
```
### `maxRetries`
Maximum retry attempts for failed translations. Default is `3`.
```json
"maxRetries": 3
```
### `processor`
Syntax processor. Use `icu` for ICU MessageFormat or omit for passthrough.
```json
"processor": "icu"
```
Built-in processors: `passthrough`, `icu`.
## Editor intellisense
Add `"$schema": "https://www.schemastore.org/intl-ai.json"` to your JSON config for autocomplete and validation in VS Code, JetBrains, and other editors.
## CI validation
Validate a config file in CI with any JSON Schema tool:
```bash
# check-jsonschema
pip install check-jsonschema
check-jsonschema --schemafile https://www.schemastore.org/intl-ai.json intl-ai.config.json
```
## TypeScript config
When you need to pass a live Vercel AI SDK model instance, use a TypeScript config:
```typescript
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
const lmstudio = createOpenAICompatible({
name: "lmstudio",
baseURL: "http://127.0.0.1:1234/v1",
});
export default {
model: lmstudio("your-model-name"),
defaultLocale: "en",
locales: ["en", "es"],
localeDir: "./locales",
};
```
See [AI model setup](/guide/ai-model) for provider details.
---
---
url: /guide/i18n-libraries.md
---
# i18n libraries
intl-ai generates translation files at build time. You choose the runtime i18n library. This page lists the supported options and their ICU compatibility.
## ICU MessageFormat
Most modern i18n libraries speak ICU MessageFormat. The main exceptions are i18next (uses `{{var}}` and plural suffixes) and vue-i18n (uses its own syntax by default). Pick a library that fits your app's needs.
## Library compatibility
| Library | Native ICU | Setup | Best for |
|---|---|---|---|
| react-intl | Yes | None | React apps that need ICU |
| @formatjs/intl | Yes | None | Framework-agnostic ICU runtime |
| lingui | Yes | Build macro | Compile-time safety, any framework |
| i18next-icu | Yes (via plugin) | Install `i18next-icu` | Existing i18next apps migrating to ICU |
| vue-i18n + intl-messageformat | Yes (via custom compiler) | Custom `messageCompiler` | Vue apps that need ICU |
| svelte-i18n | Partial | Manual formatter calls | Svelte apps |
| @cookbook/solid-intl | Yes | None | Solid apps that need ICU |
| @lit/localize | Partial | Community workaround | Web components |
| typesafe-i18n | No | N/A | Type-safe i18n without ICU |
| rosetta | No | N/A | Tiny footprint (298 bytes) |
| @solid-primitives/i18n | No | N/A | Minimal Solid i18n |
## Configuration
Set `processor: "icu"` in your `intl-ai.config.ts` if your target library uses ICU MessageFormat. Without it, intl-ai uses the default processor which preserves literal `{{var}}` placeholders for i18next.
```ts
// intl-ai.config.ts
export default {
// ... your model setup
defaultLocale: "en",
locales: ["en", "es", "fr"],
localeDir: "./locales",
processor: "icu", // omit for i18next's {{var}} style
};
```
## Per-library guides
* [Vue (vue-i18n)](/guide/vue-i18n)
* [i18next](/guide/i18next)
## Choosing a library
| Need | Use |
|---|---|
| React + ICU | `react-intl` |
| Vue + ICU | `vue-i18n` with `intl-messageformat` compiler |
| i18next syntax (no ICU) | `i18next` + `react-i18next` |
| Compile-time type safety | `lingui` or `typesafe-i18n` |
| Smallest bundle | `rosetta` |
---
---
url: /guide/build-systems.md
---
# Build systems
intl-ai runs at build time via `@intl-ai/unplugin`. It supports every major bundler through [unjs/unplugin](https://github.com/unjs/unplugin). Choose your bundler below.
* [Vite](/guide/build-systems/vite) - Modern, fast build tool
* [Webpack](/guide/build-systems/webpack) - Industry standard bundler
* [Rollup](/guide/build-systems/rollup) - Flexible module bundler
* [esbuild](/guide/build-systems/esbuild) - Extremely fast JavaScript bundler
* [Rspack](/guide/build-systems/rspack) - Rust-based, webpack-compatible bundler
* [Rolldown](/guide/build-systems/rolldown) - Rust-powered Rollup-compatible bundler
* [Farm](/guide/build-systems/farm) - Rust-based web build tool
* [Next.js](/guide/build-systems/next-js) - React framework with Turbopack bridge
If you use a framework, wire up the bundler here and pair it with an i18n library from [i18n libraries](/guide/i18n-libraries).
---
---
url: /guide/build-systems/vite.md
---
# Vite
## Installation
::: code-group
```sh [npm]
npm install @intl-ai/unplugin
```
```sh [pnpm]
pnpm add @intl-ai/unplugin
```
```sh [yarn]
yarn add @intl-ai/unplugin
```
```sh [bun]
bun add @intl-ai/unplugin
```
:::
## Configuration
Create an `intl-ai.config.ts` at your project root. See [Configuration](/guide/configuration) for the full schema.
```typescript
import { defineConfig } from "vite";
import IntlAi from "@intl-ai/unplugin/vite";
export default defineConfig({
plugins: [IntlAi()],
});
```
Works with any Vite-based framework (Vue, React, Svelte, Solid). Pair with an i18n library from [i18n libraries](/guide/i18n-libraries).
---
---
url: /guide/build-systems/webpack.md
---
# Webpack
## Installation
::: code-group
```sh [npm]
npm install @intl-ai/unplugin
```
```sh [pnpm]
pnpm add @intl-ai/unplugin
```
```sh [yarn]
yarn add @intl-ai/unplugin
```
```sh [bun]
bun add @intl-ai/unplugin
```
:::
## Configuration
Create an `intl-ai.config.ts` at your project root. See [Configuration](/guide/configuration) for the full schema.
```javascript
const IntlAi = require("@intl-ai/unplugin/webpack");
module.exports = {
plugins: [new IntlAi()],
};
```
For Next.js, see [Next.js](/guide/build-systems/next-js). Pair with an i18n library from [i18n libraries](/guide/i18n-libraries).
---
---
url: /guide/build-systems/rollup.md
---
# Rollup
## Installation
::: code-group
```sh [npm]
npm install @intl-ai/unplugin
```
```sh [pnpm]
pnpm add @intl-ai/unplugin
```
```sh [yarn]
yarn add @intl-ai/unplugin
```
```sh [bun]
bun add @intl-ai/unplugin
```
:::
## Configuration
Create an `intl-ai.config.ts` at your project root. See [Configuration](/guide/configuration) for the full schema.
```javascript
import IntlAi from "@intl-ai/unplugin/rollup";
export default {
plugins: [IntlAi()],
};
```
Pair with an i18n library from [i18n libraries](/guide/i18n-libraries).
---
---
url: /guide/build-systems/esbuild.md
---
# esbuild
## Installation
::: code-group
```sh [npm]
npm install @intl-ai/unplugin
```
```sh [pnpm]
pnpm add @intl-ai/unplugin
```
```sh [yarn]
yarn add @intl-ai/unplugin
```
```sh [bun]
bun add @intl-ai/unplugin
```
:::
## Configuration
Create an `intl-ai.config.ts` at your project root. See [Configuration](/guide/configuration) for the full schema.
```javascript
import IntlAi from "@intl-ai/unplugin/esbuild";
import { build } from "esbuild";
build({
plugins: [IntlAi()],
});
```
Pair with an i18n library from [i18n libraries](/guide/i18n-libraries).
---
---
url: /guide/build-systems/rspack.md
---
# Rspack
## Installation
::: code-group
```sh [npm]
npm install @intl-ai/unplugin
```
```sh [pnpm]
pnpm add @intl-ai/unplugin
```
```sh [yarn]
yarn add @intl-ai/unplugin
```
```sh [bun]
bun add @intl-ai/unplugin
```
:::
## Configuration
Create an `intl-ai.config.ts` at your project root. See [Configuration](/guide/configuration) for the full schema.
```javascript
const IntlAi = require("@intl-ai/unplugin/rspack");
module.exports = {
plugins: [new IntlAi()],
};
```
Pair with an i18n library from [i18n libraries](/guide/i18n-libraries).
---
---
url: /guide/build-systems/rolldown.md
---
# Rolldown
## Installation
::: code-group
```sh [npm]
npm install @intl-ai/unplugin
```
```sh [pnpm]
pnpm add @intl-ai/unplugin
```
```sh [yarn]
yarn add @intl-ai/unplugin
```
```sh [bun]
bun add @intl-ai/unplugin
```
:::
## Configuration
Create an `intl-ai.config.ts` at your project root. See [Configuration](/guide/configuration) for the full schema.
```javascript
import IntlAi from "@intl-ai/unplugin/rolldown";
export default {
plugins: [IntlAi()],
};
```
Pair with an i18n library from [i18n libraries](/guide/i18n-libraries).
---
---
url: /guide/build-systems/farm.md
---
# Farm
## Installation
::: code-group
```sh [npm]
npm install @intl-ai/unplugin
```
```sh [pnpm]
pnpm add @intl-ai/unplugin
```
```sh [yarn]
yarn add @intl-ai/unplugin
```
```sh [bun]
bun add @intl-ai/unplugin
```
:::
## Configuration
Create an `intl-ai.config.ts` at your project root. See [Configuration](/guide/configuration) for the full schema.
```javascript
import IntlAi from "@intl-ai/unplugin/farm";
export default {
plugins: [IntlAi()],
};
```
Pair with an i18n library from [i18n libraries](/guide/i18n-libraries).
---
---
url: /guide/build-systems/next-js.md
---
# Next.js
Next.js 15+ defaults to Turbopack. Use `@intl-ai/next` to register the Turbopack loader. For Next.js 14 with webpack only, use `@intl-ai/unplugin/webpack` directly.
## Installation
::: code-group
```sh [npm]
npm install @intl-ai/next
```
```sh [pnpm]
pnpm add @intl-ai/next
```
```sh [yarn]
yarn add @intl-ai/next
```
```sh [bun]
bun add @intl-ai/next
```
:::
## Configuration
Create an `intl-ai.config.ts` at your project root. See [Configuration](/guide/configuration) for the full schema.
```typescript
import withIntlAi from "@intl-ai/next";
export default withIntlAi({
reactStrictMode: true,
});
```
No changes to your app code required. Translations are generated at build time with zero runtime overhead.
## Next.js 14 (webpack only)
If you are on Next.js 14 with webpack, use `@intl-ai/unplugin/webpack` directly:
```typescript
import intlAiWebpackPlugin from "@intl-ai/unplugin/webpack";
export default {
webpack(config) {
config.plugins = config.plugins || [];
config.plugins.push(intlAiWebpackPlugin());
return config;
},
};
```
Pair with an i18n library from [i18n libraries](/guide/i18n-libraries).
---
---
url: /guide/vue-i18n.md
---
# Vue (vue-i18n)
This guide covers vue-i18n consumption. For bundler setup, see [Build systems](/guide/build-systems/).
## Overview
intl-ai generates translation JSON files at build time. vue-i18n consumes these files at runtime in your Vue application. This guide shows how to set up both tools together.
## Installation
Install intl-ai and vue-i18n:
::: code-group
```sh [npm]
npm install @intl-ai/unplugin vue-i18n
```
```sh [pnpm]
pnpm add @intl-ai/unplugin vue-i18n
```
```sh [yarn]
yarn add @intl-ai/unplugin vue-i18n
```
```sh [bun]
bun add @intl-ai/unplugin vue-i18n
```
:::
You only need `@intl-ai/unplugin`. The translation engine lives in `@intl-ai/api` and is bundled automatically.
## Configuration
Create an `intl-ai.config.ts` (or `.json`) at your project root. See [Configuration](/guide/configuration) for the full schema. For a live Vercel AI SDK model instance:
```typescript
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
const openai = createOpenAICompatible({
name: "openai",
baseURL: "https://api.openai.com/v1",
apiKey: process.env.OPENAI_API_KEY,
});
export default {
model: openai("your-model-name"),
defaultLocale: "en",
locales: ["en", "es", "fr"],
localeDir: "./locales",
processor: "icu",
};
```
## Vue App Setup
### Locale File Structure
intl-ai generates JSON files like:
```json
// locales/en.json
{
"greeting": "Hello, {name}!",
"items": {
"one": "You have {count} item",
"other": "You have {count} items"
}
}
```
### Create i18n Instance
```typescript
import { createI18n } from "vue-i18n";
import en from "./locales/en.json";
import es from "./locales/es.json";
const i18n = createI18n({
locale: "en",
fallbackLocale: "en",
messages: { en, es },
});
app.use(i18n);
```
### Using Translations
In Vue templates:
```vue
{{ $t("greeting", { name: "World" }) }}
{{ $t("items.one", { count: 5 }) }}
```
In Composition API:
```vue
```
## Processor Note
vue-i18n supports ICU MessageFormat. Set `processor: "icu"` in your config so AI-generated translations preserve ICU placeholders correctly.
---
---
url: /guide/i18next.md
---
# i18next
This guide covers i18next consumption. For bundler setup, see [Build systems](/guide/build-systems/).
## Overview
intl-ai generates translation JSON files at build time. i18next consumes these files at runtime. This guide shows how to integrate both tools.
## Installation
::: code-group
```sh [npm]
npm install @intl-ai/unplugin i18next react-i18next
```
```sh [pnpm]
pnpm add @intl-ai/unplugin i18next react-i18next
```
```sh [yarn]
yarn add @intl-ai/unplugin i18next react-i18next
```
```sh [bun]
bun add @intl-ai/unplugin i18next react-i18next
```
:::
You only need `@intl-ai/unplugin`. The translation engine lives in `@intl-ai/api` and is bundled automatically.
## i18next Syntax Note
i18next uses `{{variable}}` for interpolation (not ICU `{variable}`). For example:
```json
{
"greeting": "Hello, {{name}}!",
"items": "You have {{count}} items"
}
```
## Configuration
Create an `intl-ai.config.ts` (or `.json`) at your project root. See [Configuration](/guide/configuration) for the full schema. For a live Vercel AI SDK model instance:
```typescript
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
const openai = createOpenAICompatible({
name: "openai",
baseURL: "https://api.openai.com/v1",
apiKey: process.env.OPENAI_API_KEY,
});
export default {
model: openai("your-model-name"),
defaultLocale: "en",
locales: ["en", "es", "de"],
localeDir: "./public/locales",
};
```
## React App Usage
```typescript
import i18next from "i18next";
import { initReactI18next } from "react-i18next";
import en from "./locales/en.json";
import es from "./locales/es.json";
i18next.use(initReactI18next).init({
lng: "en",
fallbackLng: "en",
resources: {
en: { translation: en },
es: { translation: es },
},
});
```
### Using Translations
```tsx
import { useTranslation } from "react-i18next";
function App() {
const { t } = useTranslation();
return (
{t("greeting", { name: "World" })}
{t("items", { count: 5 })}
);
}
```
---
---
url: /guide/mobile/expo.md
---
# Expo
The Expo integration is provided as a self-contained config plugin in [`examples/expo/plugin`](https://github.com/sigilco/intl-ai/tree/main/examples/expo/plugin). It runs `intl-ai fill` during `expo prebuild` and has zero runtime overhead because all translations are written to disk before Metro bundles your app.
## Copy the plugin
Copy `examples/expo/plugin/` into your Expo project (for example, to `./plugins/intl-ai/`). The plugin is not published as an npm package, so you own and can customize the code.
## Configure `app.json`
Reference the local plugin in your `app.json`:
```json
{
"expo": {
"plugins": [["./plugins/intl-ai", { "configPath": "intl-ai.config.json" }]]
}
}
```
## Create `intl-ai.config.json`
```json
{
"$schema": "https://www.schemastore.org/intl-ai.json",
"defaultLocale": "en",
"locales": ["en", "es"],
"localeDir": "locales",
"model": "your-provider/your-model",
"apiKey": "${OPENAI_API_KEY}",
"baseURL": "https://api.openai.com/v1",
"maxRetries": 3
}
```
## Run prebuild
```bash
expo prebuild
```
The plugin invokes:
```bash
npx intl-ai fill --config intl-ai.config.json
```
## Plugin options
| Option | Type | Default | Description |
| ----------------- | --------- | --------------------- | ------------------------------------------------------- |
| `configPath` | `string` | `intl-ai.config.json` | Path to your JSON config, relative to the project root. |
| `verbose` | `boolean` | `false` | Forward CLI output to the parent process. |
| `continueOnError` | `boolean` | `false` | Allow prebuild to continue if translation fails. |
## Runtime usage
Load the generated JSON files directly with your preferred i18n library (`i18next`, `react-intl`, etc.). The plugin only writes translations; it does not impose a runtime API.
## Example
See [`examples/expo`](https://github.com/sigilco/intl-ai/tree/main/examples/expo) for a complete working app.
---
---
url: /guide/mobile/flutter.md
---
# Flutter
The Flutter integration is provided as a self-contained [`build_runner`](https://pub.dev/packages/build_runner) builder in [`examples/flutter/plugin`](https://github.com/sigilco/intl-ai/tree/main/examples/flutter/plugin). It runs `intl-ai fill` during `flutter pub run build_runner build` and has zero runtime overhead because all translations are written to disk before the Flutter app is bundled.
## Copy the builder
Copy `examples/flutter/plugin/` into your Flutter project (for example, to `./tools/intl_ai_builder/`). The builder is not published as a package, so you own and can customize the code.
## Configure `build.yaml`
Add the builder to your app's `build.yaml`:
```yaml
targets:
$default:
builders:
intl_ai_flutter|intl_ai:
enabled: true
options:
configPath: "intl-ai.config.json"
executable: "intl-ai"
verbose: false
```
Update the `import` path in `build.yaml` to match where you copied the builder, for example:
```yaml
builders:
intl_ai:
import: "package:my_app/tools/intl_ai_builder/lib/builder.dart"
```
## Create `intl-ai.config.json`
```json
{
"$schema": "https://www.schemastore.org/intl-ai.json",
"defaultLocale": "en",
"locales": ["en", "es"],
"localeDir": "assets/locales",
"model": "your-provider/your-model",
"apiKey": "${OPENAI_API_KEY}",
"baseURL": "https://api.openai.com/v1",
"maxRetries": 3
}
```
## Run build\_runner
```bash
flutter pub get
flutter pub run build_runner build --delete-conflicting-outputs
```
The builder invokes:
```bash
intl-ai fill --config intl-ai.config.json
```
## Builder options
| Option | Type | Default | Description |
| ------------ | -------- | --------------------- | -------------------------------------------------------------------------------------------------------- |
| `configPath` | `String` | `intl-ai.config.json` | Path to your JSON config, relative to the package root. |
| `executable` | `String` | `intl-ai` | Command used to invoke the CLI. Use `npx intl-ai` or `bunx intl-ai` if you do not want a global install. |
| `verbose` | `bool` | `false` | Forward CLI output to the build runner log. |
## How it works
The builder is registered on the `$package$` asset and writes an `intl-ai.done` marker file. When `build_runner` runs, it invokes the `intl-ai` CLI once per package. Add `intl-ai.done` to your `.gitignore`; it is only used to track build completion.
## Runtime usage
Load the generated JSON files with your preferred i18n library (`easy_localization`, `i18n_extension`, `flutter_gen`, etc.). The builder only writes translations; it does not impose a runtime API.
## Requirements
* Dart SDK 3.0+
* `intl-ai` CLI on `PATH`
* An `intl-ai.config.json` file and locale directory
## Example
See [`examples/flutter`](https://github.com/sigilco/intl-ai/tree/main/examples/flutter) for a complete working app.
---
---
url: /guide/mobile/swiftui.md
---
# SwiftUI
You can integrate `intl-ai` into a SwiftUI project by running the CLI as an Xcode build script phase. All translations happen at build time, so there is zero runtime overhead.
## Project layout
```
MyApp/
├── intl-ai.config.json
├── locales/
│ ├── en.json
│ └── es.json
├── MyApp/
│ ├── MyApp.swift
│ └── Resources/
│ └── locales/
│ ├── en.json
│ └── es.json
└── MyApp.xcodeproj/
```
Store source locale files in a project directory, then copy the generated translations into your app bundle as a build step.
## Add a build script phase
1. Select your app target in Xcode.
2. Open **Build Phases** and add a new **Run Script** phase named **"Translate Locales"**.
3. Paste the following script:
```bash
set -e
# Run intl-ai fill to generate missing translations.
if command -v intl-ai &> /dev/null; then
intl-ai fill --config "$SRCROOT/intl-ai.config.json"
else
echo "warning: intl-ai not found in PATH. Skipping translation."
fi
# Copy generated locale files into the app bundle.
LOCALES_DIR="$SRCROOT/locales"
DEST_DIR="$BUNDLE_RESOURCE_PATH/locales"
if [ -d "$LOCALES_DIR" ]; then
mkdir -p "$DEST_DIR"
cp -R "$LOCALES_DIR"/*.json "$DEST_DIR/"
fi
```
4. Drag the **Translate Locales** phase before **Copy Bundle Resources**.
## Load translations at runtime
Use `Bundle.main.url(forResource:withExtension:)` or `Bundle.main.decode(_:)` helpers to load JSON files from the bundle:
```swift
import Foundation
extension Bundle {
func decode(_ file: String, as type: T.Type = T.self) -> T {
guard let url = self.url(forResource: file, withExtension: nil) else {
fatalError("Failed to locate \(file) in bundle.")
}
guard let data = try? Data(contentsOf: url) else {
fatalError("Failed to load \(file) from bundle.")
}
let decoder = JSONDecoder()
guard let loaded = try? decoder.decode(T.self, from: data) else {
fatalError("Failed to decode \(file) from bundle.")
}
return loaded
}
}
struct Localizations: Decodable {
let hello: String
let goodbye: String
}
let en = Bundle.main.decode("en.json", as: Localizations.self)
```
## Requirements
* `intl-ai` installed on your `PATH` (see [Installation](/guide/installation)).
* `intl-ai.config.json` at project root.
## Example
See the project layout above and adapt it to your own SwiftUI app. `intl-ai` only writes translations; it does not impose a runtime API.
---
---
url: /guide/mobile/jetpack.md
---
# Android Jetpack
You can integrate `intl-ai` into an Android Jetpack project by adding a Gradle task that runs the CLI before the build. All translations happen at build time, so there is zero runtime overhead.
## Project layout
```
app/
├── build.gradle.kts
├── intl-ai.config.json
└── src/main/assets/locales/
├── en.json
└── es.json
```
Store source locale files in `src/main/assets/locales/`, run `intl-ai fill` as a Gradle task, and load them from assets at runtime.
## Add a Gradle task
In your `app/build.gradle.kts`, register a task that invokes the CLI before resources are merged:
```kotlin
import java.io.ByteArrayOutputStream
plugins {
alias(libs.plugins.android.application)
}
android { /* ... */ }
tasks.register("intlAiFill") {
group = "intl-ai"
description = "Translate missing locale keys with intl-ai"
commandLine("intl-ai", "fill", "--config", "${projectDir}/intl-ai.config.json")
// Only run when source locale files change.
inputs.dir("${projectDir}/src/main/assets/locales")
outputs.dir("${projectDir}/src/main/assets/locales")
doFirst {
if (org.gradle.internal.os.OperatingSystem.current().isWindows) {
commandLine("cmd", "/c", "intl-ai", "fill", "--config", "${projectDir}/intl-ai.config.json")
}
}
}
tasks.named("preBuild").configure {
dependsOn("intlAiFill")
}
```
For Windows, the task falls back to `cmd /c` so the binary can be found on `PATH`.
## Load translations at runtime
Read JSON files from assets and parse them with your JSON library of choice:
```kotlin
import android.content.Context
import kotlinx.serialization.json.Json
import kotlinx.serialization.Serializable
@Serializable
data class LocaleMessages(
val hello: String,
val goodbye: String
)
fun loadLocale(context: Context, locale: String): LocaleMessages {
val json = context.assets.open("locales/$locale.json").bufferedReader().use { it.readText() }
return Json.decodeFromString(LocaleMessages.serializer(), json)
}
```
## Requirements
* `intl-ai` installed on your `PATH` (see [Installation](/guide/installation)).
* `intl-ai.config.json` in `app/`. Adjust `localeDir` to point to `src/main/assets/locales`.
## Example
Use the project layout above and adapt it to your own Jetpack Compose or View-based app. `intl-ai` only writes translations; it does not impose a runtime API.
---
---
url: /guide/desktop/dotnet.md
---
# .NET / C\#
You can integrate `intl-ai` into a .NET project by adding an MSBuild target that runs the CLI before the build. All translations happen at build time, so there is zero runtime overhead.
## Project layout
```
MyApp/
├── MyApp.csproj
├── intl-ai.config.json
└── Resources/
├── en.json
└── es.json
```
Store source locale files in `Resources/`, run `intl-ai fill` as an MSBuild target, and embed or copy them into the output directory.
## Add an MSBuild target
Add the following target to your `.csproj` file:
```xml
Exe
net8.0
PreserveNewest
```
The `IntlAiFill` target runs before every build, invoking the CLI to fill missing translations. Because the `Resources\*.json` items use `CopyToOutputDirectory=PreserveNewest`, the generated files are copied to the output folder automatically.
## Load translations at runtime
Use `System.Text.Json` to load locale files from the output directory:
```csharp
using System.Text.Json;
public record LocaleMessages(string Hello, string Goodbye);
public static class Translations
{
public static LocaleMessages Load(string locale)
{
var path = Path.Combine(AppContext.BaseDirectory, "Resources", $"{locale}.json");
var json = File.ReadAllText(path);
return JsonSerializer.Deserialize(json)!;
}
}
```
## Requirements
* `intl-ai` installed on your `PATH` (see [Installation](/guide/installation)).
* `intl-ai.config.json` next to your `.csproj` file. Adjust `localeDir` to point to `Resources`.
## Example
Use the project layout above and adapt it to your own WPF, WinUI, ASP.NET, or console app. `intl-ai` only writes translations; it does not impose a runtime API.
---
---
url: /guide/api.md
---
# API reference
`@intl-ai/api` is the runtime-agnostic core of intl-ai. It exposes one function and one config type.
## `runFill(config, options?)`
```typescript
import { runFill } from "@intl-ai/api";
import type { IntlAiConfig, RunFillOptions, RunFillResult } from "@intl-ai/api";
const result: RunFillResult = await runFill(config, {
locale: "es",
force: false,
dryRun: false,
});
```
The function walks your locale files, translates missing keys, updates the lockfile, and writes the new translations to disk.
### Options
| Option | Type | Description |
| -------- | --------- | -------------------------------------- |
| `locale` | `string` | Translate only this locale. |
| `force` | `boolean` | Re-translate human-edited entries. |
| `dryRun` | `boolean` | Preview changes without writing files. |
### Result
| Field | Type | Description |
| ------------ | ---------- | ---------------------------------- |
| `translated` | `number` | Number of keys translated. |
| `skipped` | `number` | Number of keys already up to date. |
| `errors` | `number` | Number of translation errors. |
| `locales` | `string[]` | Locales that were processed. |
## `IntlAiConfig`
```typescript
interface IntlAiConfig {
defaultLocale: string;
locales: string[];
localeDir: string;
model: unknown; // pass a Vercel AI SDK LanguageModel instance
processor?: IntlAiProcessor;
glossary?: Record;
maxRetries?: number;
}
```
For JSON config files, use `IntlAiJsonConfigSchema` and `jsonConfigToIntlAiConfig` from `@intl-ai/api/internal`.
## JSON Schema
A JSON Schema for `intl-ai.config.json` is published at:
```text
https://www.schemastore.org/intl-ai.json
```
Add it to your config for editor intellisense and CI validation:
```json
{
"$schema": "https://www.schemastore.org/intl-ai.json",
"defaultLocale": "en",
"locales": ["en", "es"],
"localeDir": "./locales",
"model": "your-provider/your-model",
"apiKey": "${OPENAI_API_KEY}"
}
```
---
---
url: /guide/contributing.md
---
# Contributing to the documentation
Thank you for your interest in improving the intl-ai documentation. This guide covers everything you need to know about contributing to the docs.
For general contribution guidelines, branch workflows, commit conventions, and the full development process, see our [main Contributing Guide](https://github.com/sigilco/intl-ai/blob/main/CONTRIBUTING.md).
## Documentation setup
The docs are built with [VitePress](https://vitepress.dev/), a static site generator optimized for technical documentation.
### Prerequisites
* Node.js 22+ and pnpm 11+
* Basic familiarity with Markdown
* A text editor (VS Code recommended)
### Installation
```bash
pnpm install
```
## Running docs locally
Start the development server to preview your changes in real-time:
```bash
pnpm docs:dev
```
This starts a local dev server (typically at `http://localhost:5173`) with hot module replacement for instant preview updates.
## Building for production
```bash
pnpm docs:build
```
This generates optimized static files in the `docs/.vitepress/dist/` directory.
## Previewing the production build
After building, preview the production version locally:
```bash
pnpm docs:preview
```
## Documentation writing guidelines
### File structure
```
docs/
.vitepress/
config.ts
guide/
getting-started.md
installation.md
ai-model.md
configuration.md
api.md
migration.md
contributing.md
next-js.md
vue-i18n.md
i18next.md
mobile/
expo.md
flutter.md
swiftui.md
jetpack.md
desktop/
dotnet.md
public/
logo.svg
index.md
```
### Markdown conventions
* **Headings:** Use `#` for page title, `##` for sections, `###` for subsections
* **Code blocks:** Specify language for syntax highlighting (` ```bash `, ` ```typescript `, etc.)
* **Links:** Use relative paths for internal links: `[link text](/guide/page-name)`
* **Line length:** Keep lines under 100 characters
### Frontmatter
Every documentation page must include YAML frontmatter at the top:
```yaml
---
title: Page title
---
```
### Internal links
```markdown
[Getting started guide](/guide/getting-started)
```
### External links
External links open in a new tab automatically.
## Adding new guide pages
1. Create a new `.md` file in `docs/guide/`.
2. Add the required YAML frontmatter with a `title` field.
3. Add the page to the sidebar in `docs/.vitepress/config.ts`.
4. Run `pnpm docs:dev` and verify your page appears and renders correctly.
5. Submit a pull request following the [main Contributing Guide](https://github.com/sigilco/intl-ai/blob/main/CONTRIBUTING.md).
## Documentation commands reference
| Command | Purpose |
| ------------------- | ---------------------------------------------- |
| `pnpm docs:dev` | Start local development server with hot reload |
| `pnpm docs:build` | Build production-ready static files |
| `pnpm docs:preview` | Preview the production build locally |
## Deployment
Documentation is deployed to Cloudflare Pages at `https://intl-ai.pages.dev/` when changes are merged to the `main` branch.
The deployment process:
1. Detects changes to the `docs/` directory
2. Runs `pnpm docs:build` to generate static files
3. Deploys the output to Cloudflare Pages
No manual deployment steps are required.
## Before submitting documentation changes
* Run `pnpm docs:dev` and verify all pages render correctly
* Check that internal links work (no 404s)
* Verify code examples are accurate and runnable
* Ensure frontmatter is present on all new pages
* Update the sidebar navigation if adding new pages
* Follow Markdown conventions and style guidelines
* Proofread for spelling and grammar
## Code of conduct
All contributors must adhere to our [Code of Conduct](https://github.com/sigilco/intl-ai/blob/main/CODE_OF_CONDUCT.md). We are committed to providing a welcoming and inclusive environment for all contributors.
## Questions or issues?
* Documentation questions: Open a GitHub Discussion
* Found a typo or error: Open an issue or submit a PR
* Feature suggestions: Open an issue to discuss before implementing
---
---
url: /guide/internals.md
---
# Internals
This page is for contributors who want to understand how intl-ai is built. User-facing documentation lives under [Guide](/guide/getting-started).
## Package layout
| Package | Purpose |
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `@intl-ai/api` | Runtime-agnostic translation core. Public surface: `runFill`, `IntlAiConfig`, `RunFillOptions`, `RunFillResult`, `IntlAiConfigSchema`. |
| `@intl-ai/cli` | `intl-ai fill` and `intl-ai check` commands. Loads `intl-ai.config.ts` or `intl-ai.config.json`. |
| `@intl-ai/unplugin` | Universal bundler plugin adapters. Loads config and calls `runFill` at `buildStart`. |
| `@intl-ai/next` | Next.js wrapper around the webpack plugin and Turbopack loader. Loads config at startup and on the webpack `emit` hook. |
## Internal subpath
Modules that SDK consumers do not need are exposed through `@intl-ai/api/internal`. Sibling packages in this monorepo may import them, but external SDKs and plugins should stay on the public surface. The internal barrel includes engine, lockfile, processor, formats, utilities, and JSON config schemas.
## JSON Schema generation
`packages/api/src/schema/intl-ai.schema.json` is generated from `IntlAiJsonConfigSchema` in `packages/api/src/schema/json-config.ts`. Run:
```bash
pnpm --filter @intl-ai/api schema:build
```
This writes both the package-local schema and `docs/public/schema/v1.json`, which GitHub Pages serves at `/intl-ai/schema/v1.json`.
## SchemaStore
The schema is submitted to SchemaStore so editors discover it automatically for files matching `intl-ai.config.ts` and `intl-ai.config.json`. See the plan at `.agents/plans/2026-06-22-runtime-agnostic-rethink.md` for the catalog entry format.
## Release pipeline
* Binaries are built with `bun build --compile` for `bun-darwin-arm64`, `bun-linux-x64`, and `bun-linux-arm64`.
* npm packages are published with changesets.
* Docs are built with VitePress and deployed to GitHub Pages.
See `.github/workflows/release.yml` for details.
---
---
url: /prd.md
---
# Product Requirements Document: intl-ai
## Table of Contents
* [Vision](#vision)
* [Product Vision](#product-vision)
* [Technical Decisions](#technical-decisions)
* [Research Findings](#research-findings)
* [Success Metrics](#success-metrics)
* [0.1.0 Release Blockers](#010-release-blockers)
* [Scope Boundaries](#scope-boundaries)
## Vision
### Core Objective (One Sentence)
AI-powered build-time i18n translation plugin that works with any bundler and any AI model. Plug in, translate, ship.
### Product Positioning
**Swiss army knife (modular):** core plugin + CLI + management features, not a full platform
**Target Users:** Indie developers AND mid-size companies
**Core Differentiators:**
1. Build-time AI translation: zero runtime overhead, works with existing i18n libraries
2. Universal bundler support: one plugin via unplugin, works with every bundler
3. Model agnostic / privacy: use any AI model (local, self-hosted, or cloud), no vendor lock-in
## Product Vision
### Delivered (as of 0.1.0):
* **Core plugin:** `@intl-ai/core` AI translation pipeline
* **Bundler plugins:** unplugin for Vite, Webpack, Rollup, esbuild, Rspack
* **Next.js integration:** `@intl-ai/next`
* **CLI:** `packages/cli` with `fill` and `check` commands
### 12-Month Feature Roadmap (Modules in Scope):
1. \~~**CLI**~~: **DELIVERED**: `packages/cli` with `fill` + `check` commands
2. **Incremental/delta translation:** git diff based, only translate new/changed keys
3. **Translation quality scoring:** LLM-as-a-Judge (same model, different session, self-score 0-1 per key, flag low scores)
### 0.1.0 Release Scope:
**Minimal:** ship current state as-is (bundler plugin works, basic translation works)
Get it out, iterate from there.
### Monetization:
**Free / OSS only:** fully open source, no paid tiers, community-driven
## Technical Decisions
### i18n Library Support (All of These):
* vue-i18n (already documented)
* i18next (already documented)
* next-intl
* FormatJS / react-intl
* Paraglide
* Any JSON-based i18n setup (generic)
### Test Strategy:
**Tests-after** with existing vitest infrastructure (confirmed across all packages)
Agent-executed QA via Playwright for docs site
### Open Questions (Deferred, decide during implementation):
* Delta translation: git diff at key level (new keys + changed values). Deleted keys: TBD.
* Quality scoring: scoring prompt design, confidence threshold TBD.
* Paraglide: generic JSON support, no specific integration needed.
### Timeline:
* **0.1.0**: Release NOW, iterate fast
* **Post-0.1.0**: Monthly iterations
## Research Findings
**From codebase exploration:**
* **Monorepo**: pnpm workspaces + Turborepo + changesets
* **4 packages**: core, unplugin, next, cli + shared typescript-config
* **Docs**: VitePress site at `docs/` with existing guides (getting-started, ai-model, configuration, next-js, vue-i18n, i18next, contributing)
* **CHANGELOG**: empty (unreleased)
* **Version bumps**: to 0.1.0 already done locally (not committed)
* **JSR publishing**: removed from CI
* **Registry**: `localhost:4873` is Verdaccio local dev (expected, not a blocker)
## Success Metrics
### Primary: Adoption / Community Growth
* Repos using it
* Blog posts
* Word of mouth
### NOT Primarily
* Stars/downloads (vanity metrics)
* Feature milestones
## 0.1.0 Release Blockers (Must Complete Before Publish):
* \[ ] Merge develop to main
* \[ ] Publish to npm
* \[ ] Docs site live (VitePress)
* \[ ] Working examples (next, vite, webpack at minimum)
## Scope Boundaries
### INCLUDE:
* Build-time translation (bundler plugin)
* On-demand CLI translation (packages/cli, already delivered)
* Incremental/delta translation (git diff based)
* Translation quality scoring (LLM-as-a-Judge, same model, different session)
* i18n library support: vue-i18n, i18next, next-intl, FormatJS, Paraglide, any JSON-based
* Model agnosticism: any AI model via AI SDK compatible API
* Documentation: one guide per supported library, one guide per AI provider
* Privacy: no telemetry, no data collection
### EXCLUDE (Explicit Guardrails):
* No cloud dashboard / SaaS platform
* No paid tiers or license tiers
* No user accounts / authentication
* No translation memory hosted by the project (local git-based TM only)
* No automatic translation updates without human consent (human-in-the-loop)
* No CLI subcommands beyond `fill` and `check` (no serve, deploy, config wizard)
* No external evaluation service for quality scoring (same model, different session only)
* No support for binary i18n formats (PO, XLIFF) unless community-contributed
* No RTL-specific handling (out of scope; handled by user's i18n lib)