# Configuration
Better i18n CLI automatically detects your project context from `i18n.config.ts`. This file is the source of truth for your translation workflow.
## Basic Configuration
For simple projects, you only need to export the project slug and default locale.
```ts title="i18n.config.ts"
export const project = "your-org/your-project";
export const defaultLocale = "en";
```
## Workspace Configuration
For full control over scanning and linting behavior, use the `i18nWorkspaceConfig` export.
```ts title="i18n.config.ts"
export const project = "your-org/your-project";
export const defaultLocale = "en";
export const i18nWorkspaceConfig = {
project,
defaultLocale,
lint: {
// Glob patterns for files to scan
include: ["src/**/*.tsx", "app/**/*.tsx"],
// Files to explicitly ignore (merges with defaults)
exclude: [
"**/skeletons.tsx", // UI skeletons
"**/*.stories.tsx", // Storybook
"**/*.test.tsx", // Tests
"**/components/ui/**", // UI library components (e.g., shadcn)
],
// Rule configuration
rules: {
"jsx-text": "warning", // Show as warning
"jsx-attribute": "warning",
"ternary-locale": "error", // Block CI if detected
},
},
};
```
## Lint Options
| Option | Type | Description |
| -------------- | ---------- | --------------------------------------------------------------------------- |
| `lint.include` | `string[]` | Files to scan. Default: `["src", "app", "components", "pages"]` |
| `lint.exclude` | `string[]` | Files to ignore. These are merged with system defaults like `node_modules`. |
| `lint.rules` | `object` | Customize the severity of detection rules. |
## Rule Severities
You can set each rule to one of three levels:
* **`error`**: Reports as an error and causes `better-i18n scan --ci` to fail with exit code 1.
* **`warning`**: Reports as a warning but does not fail the CI (unless `--ci` is combined with specific flags).
* **`off`**: Disables the rule entirely.
## Default Exclusions
The CLI automatically ignores these directories to ensure high performance and fewer false positives:
* `node_modules/**`
* `.next/**` (Next.js build artifacts)
* `dist/**` / `build/**` (Production bundles)
* `.git/**`
* `public/**` (Static assets)
# Introduction
Better i18n CLI helps you manage the entire lifecycle of your translation keys, from detecting hardcoded strings to auditing remote sync status.
## Core Capabilities
* **`scan`**: Find hardcoded strings that need translation.
* **`sync`**: Compare your local `t()` calls with Better i18n cloud (Remote) and detect missing or unused keys.
## Why use the CLI?
Managing i18n manually is error-prone. The CLI provides a "Senior Tooling" experience to ensure your translations are always consistent and fully covered.
```tsx
// ❌ Detected by 'scan'
Welcome to our app
// ✅ Analyzed by 'sync'
{t('welcome')}
// Linked to 'home.welcome' namespace
```
## Installation
```bash
# With npx (no install needed)
npx @better-i18n/cli scan
# Or install globally
npm install -g @better-i18n/cli
```
## Workflow
1. **Scan**: Run `better-i18n scan` to find untranslated text.
2. **Translate**: Wrap text with `t()` calls using `@better-i18n/next`.
3. **Sync**: Run `better-i18n sync` to verify your local keys exist in Better i18n cloud.
## Features
* ✅ **Lexical Scope Tracking** - Smart namespace detection for both `useTranslations` and `getTranslations`.
* ✅ **Server Component Support** - Full support for Next.js App Router async server functions.
* ✅ **Compact Tree Output** - Human-readable grouping of missing/unused keys.
* ✅ **Senior Audit Log** - Deep transparency with `--verbose`.
* ✅ **CI/CD Ready** - Enforce 100% key coverage in your pipeline.
* ✅ **Smart Filtering** - Automatically ignores CSS, URLs, and constants.
**Cmd+Click** on any file path in the terminal to jump directly to the code in VS Code!
# scan
Scan your codebase for hardcoded strings that need translation. Better i18n CLI uses a robust AST parser to differentiate between UI text and developer symbols.
## Usage
```bash
better-i18n scan # Scan current directory
better-i18n scan --dir ./src # Scan specific directory
better-i18n scan --format json # JSON output for tooling
better-i18n scan --ci # Exit code 1 if issues found
better-i18n scan --staged # Only staged files
better-i18n scan --verbose # Detailed output with scan stats
```
## Options
| Option | Description |
| ----------------- | ---------------------------------------------------------- |
| `--dir ` | Directory to scan |
| `--format ` | `eslint` (default) or `json` |
| `--ci` | Exit with code 1 if issues found. Useful for blocking PRs. |
| `--staged` | Only scan git staged files. Perfect for pre-commit hooks. |
| `--verbose` | Shows detailed output and a **Scan Audit** summary. |
## Example Output
```text
✓ Project: better-i18n/landing
✓ Found 246 files
components/sign-up.tsx (3)
24:13 missing "Create an account" i18n/jsx-text
32:22 missing "Name" i18n/jsx-text
40:22 missing "Email" i18n/jsx-text
✖ 87 problems (87 missing translations)
Scanned 246 files in 0.85s
```
### Scan Details (with --verbose)
When running with `--verbose`, the CLI provides a breakdown of its discovery process:
```text
🔍 Scan Details:
- Root-scoped translators: 4
- Unbound translators: 0
- Dynamic namespaces skipped: 12
- Dynamic keys skipped: 5
```
## Detection Rules
| Rule | Catches | Example |
| ----------------- | -------------------- | --------------------------------- |
| `jsx-text` | Hardcoded JSX text | `Hello
` |
| `jsx-attribute` | Hardcoded attributes | `
` |
| `toast-message` | Toast notifications | `toast.error("Failed")` |
| `ternary-locale` | Locale-based logic | `locale === 'en' ? 'Hi' : 'Hola'` |
| `string-variable` | String variables | `const x = "Hello"` |
## Ignored Patterns
The CLI is smart enough to ignore common developer symbols and technical strings:
* **HTML entities**: `"`, `&`, `'`
* **Tailwind/CSS classes**: `className="flex items-center bg-blue-500"`
* **URLs & Paths**: `href="https://..."`, `src="/images/..."`
* **Technical strings**: `SCREAMING_CASE`, variables, and numbers.
## CI/CD Integration
### GitHub Actions
Enforce zero hardcoded strings in your main branch:
```yaml
name: i18n Check
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npx @better-i18n/cli scan --ci
```
### Pre-commit Hook
Catch issues before they are even committed:
```bash
# Using husky
npx husky init
echo "npx @better-i18n/cli scan --staged --ci" > .husky/pre-commit
```
# sync
Compare your codebase's `t()` calls with translations stored in Better i18n (remote) and audit your project for consistency.
## When to use sync
The `sync` command is a powerful auditing tool. Common scenarios include:
* **Before opening a PR**: Ensure all new translation keys are present in Better i18n.
* **After adding new pages**: Automatically identify and log missing keys.
* **After refactors**: Detect "dead" keys that are no longer referenced in code.
* **Before shipping a new locale**: Verify that the source keys are stable.
* **Debugging**: Use `--verbose` to trace why certain keys are not being picked up.
* **CI Gating**: Use `--format json` to fail builds if missing keys are detected.
***
## Workflow
1. **Run `sync`**: See the tree of missing or unused keys.
2. **Dashboard/AI**: Add the missing keys via the Better i18n dashboard or AI suggestions.
3. **Verify**: Run `sync --summary` to confirm `missingCount` is 0.
4. **Enforce**: Integrate into CI to prevent missing keys from reaching production.
***
## Usage
```bash
better-i18n sync # Grouped tree output (default)
better-i18n sync --summary # High-level metrics only
better-i18n sync --verbose # Deep audit & verification
better-i18n sync --format json # JSON output for automation
better-i18n sync -d ./src # Scan specific directory
```
## Options
| Option | Description |
| ------------------ | -------------------------------------------------------------------------------------------------------------- |
| `--format ` | `eslint` (default) for humans, `json` for machines. |
| `--verbose` | Detailed audit log: invariant checks (PASS/FAIL), scoping summary, dynamic key skips, and specific key probes. |
| `--summary` | Show only top-level percentage coverage and counts without the detailed tree. |
| `-d, --dir ` | Specify the directory to scan (default: current directory). |
***
## Output Example
The default output provides a 2-level compact tree of mismatches.
```text
📊 Translation Keys Comparison
Source locale: en
Coverage:
Local → Remote: 59%
Remote Used: 63%
⊕ Missing in Remote (473 keys)
Keys used in code but not uploaded to Better i18n
pages (300)
affordableEnglishLearning (meta.title, meta.description, meta.keywords, hero.badge, ...+12)
bestApps (hero.badge, title_prefix, title_accent, subtitle)
hero (5)
hero (ariaLabel, imageAlt, ...)
⊖ Unused in Code (386 keys)
Keys in Better i18n but not detected in code usage
features (25)
practiceSpeaking (title, subtitle, icon)
Scanned 246 files in 0.85s
✓ Comparison complete
```
***
## How namespace binding works
The CLI uses **Lexical Scope Tracking** to resolve namespaces automatically for both client and server components.
### Client Components (React Hooks)
```tsx
// All t() calls inside this scope become 'hero.key'
const t = useTranslations('hero');
return {t('title')}
; // Detected as: hero.title
```
### Server Components (Async Functions)
```tsx
// ✅ Direct string namespace
const t = await getTranslations('welcome');
return {t('title')}
; // Detected as: welcome.title
// ✅ Object with namespace property
const t = await getTranslations({
locale: params.locale,
namespace: 'maintenance'
});
return {t('message')}
; // Detected as: maintenance.message
// ⚠️ Root scoped (no namespace)
const t = await getTranslations();
return {t('global.title')}
; // Detected as: global.title (root scope)
```
### Supported Patterns
* **`useTranslations('namespace')`** - Client component with namespace
* **`getTranslations('namespace')`** - Server component with namespace
* **`getTranslations({ locale, namespace: 'namespace' })`** - Server with locale
* **`useTranslations()` / `getTranslations()`** - Root scoped (no namespace prefix)
* **Standard Methods**: All patterns support `t()`, `t.raw()`, `t.rich()`, and `t.has()`.
### Dynamic Namespaces
If a namespace is a variable or template literal (e.g., ``useTranslations(`pages.${slug}`)``), it is reported as **unknown-scoped** in `--verbose` mode and skipped from metrics to prevent false positives.
***
## Flattening rules
To ensure CLI metrics match the Better i18n UI:
1. **Primitives are leaves**: Strings, numbers, and booleans are counted as keys.
2. **Arrays are leaves**: `meta.keywords: ["i18n", "cli"]` is counted as **one key**, not two. This matches the UI's "Base Key" counting.
3. **Objects are containers**: Keys like `pages.home.hero` representing a grouping of sub-keys are ignored in the final key count.
***
## JSON Output
Use `--format json` for CI scripts and automation.
```json
{
"project": {
"workspace": "my-org",
"slug": "my-app",
"sourceLocale": "en"
},
"localKeys": {
"total": 1223
},
"comparison": {
"missingInRemote": { "pages.bestApps": ["pages.bestApps.meta.title"] },
"unusedInCode": { "old": ["old.unused_key"] },
"missingCount": 473,
"unusedCount": 386
},
"coverage": {
"local": 59,
"remote": 63
},
"files": 246,
"duration": 850
}
```
***
## CI Integration
### Fail build on missing keys
```bash
# Using jq to check missingCount
better-i18n sync --format json | jq -e '.comparison.missingCount == 0' > /dev/null || exit 1
```
### List missing keys in CI logs
```bash
better-i18n sync --format json | jq '.comparison.missingInRemote'
```
# Setup
Better i18n MCP (Model Context Protocol) allows AI assistants like Claude and Cursor to directly interact with your translation workspace.
### Get your API Key
1. Sign in to [dash.better-i18n.com](https://dash.better-i18n.com).
2. Go to **Settings > API Keys**.
3. Create a new key and copy it.
### Configure Project Context
The MCP server needs to know which project to manage. It looks for a `project` identifier in your `i18n.config.ts`.
```ts title="i18n.config.ts"
import { createI18n } from "@better-i18n/next";
export const i18n = createI18n({
project: "your-org/your-project", // MCP uses this ID
defaultLocale: "en",
});
```
### Configure your AI Assistant
Pass your API key using the `BETTER_I18N_API_KEY` environment variable.
Add this to your MCP settings in Cursor (`~/.cursor/mcp.json`):
```json title="~/.cursor/mcp.json"
{
"mcpServers": {
"better-i18n": {
"command": "npx",
"args": ["@better-i18n/mcp"],
"env": {
"BETTER_I18N_API_KEY": "your-api-key"
}
}
}
}
```
Add this to your Claude Desktop config:
```json
{
"mcpServers": {
"better-i18n": {
"command": "npx",
"args": ["@better-i18n/mcp"],
"env": {
"BETTER_I18N_API_KEY": "your-api-key"
}
}
}
}
```
### Verify Connectivity
Ask your AI assistant a translation-related question to verify the setup:
> "Show me the translation status for my current project."
If configured correctly, the AI will use the `getProject` tool to fetch your real-time stats.
## Environment Variables
| Variable | Required | Description |
| --------------------- | -------- | ---------------------------------------------- |
| `BETTER_I18N_API_KEY` | Yes | Your organization API key |
| `BETTER_I18N_API_URL` | No | Custom API URL (default: dash.better-i18n.com) |
| `BETTER_I18N_DEBUG` | No | Enable detailed debug logging |
# Introduction
Better i18n MCP (Model Context Protocol) is the bridge between your AI assistant and your translation workspace. It allows tools like Cursor and Claude to directly manage your project's I18n lifecycle without you leaving your IDE.
## Core Features
* 🤖 **AI-Native Workflow** - Empower your AI to fix missing translations and create keys.
* ⚡ **Zero Scan Latency** - Uses your `i18n.config.ts` to immediately connect to the cloud.
* 🔄 **Efficient Bulk Updates** - Single commands to update hundreds of values in seconds.
* 🔍 **Context-Aware** - AI understands your namespaces and project structure.
## Quick Start
The fastest way to get started is by configuring your favorite AI assistant:
Add the server to Cursor's MCP pool:
```bash
npx @better-i18n/mcp
```
See the [Setup Guide](/docs/mcp/setup) for detailed environment configuration.
Configure Claude Desktop to include `@better-i18n/mcp`. See [Setup](/docs/mcp/setup).
## Why use MCP?
Instead of manually copying keys and text to the dashboard, you can simply ask:
> "Translate the new auth namespace to Turkish and German."
The AI assistant will:
1. Verify the keys exist.
2. Generate accurate translations in context.
3. Apply them directly to your project using the [Available Tools](/docs/mcp/tools).
# Available Tools
The Better i18n MCP server provides a set of tools that allow AI assistants to manage translations, create keys, and perform bulk updates.
All tools require `orgSlug` and `projectSlug` parameters. The AI assistant
automatically reads these from your `i18n.config.ts`.
## Discovery Tools
List all projects the user has access to across all organizations.
**Use this first** to discover available projects before other operations.
**Returns:**
* Project slugs in `org/project` format
* Source and target languages
* Organization names
**Example Prompts:**
* "What projects do I have access to?"
* "List my translation projects"
Get detailed project information including structure and coverage stats.
**Returns:**
* Available namespaces
* Available languages with translation coverage percentages
* Total key count
**Example Prompts:**
* "Show my project stats"
* "How many translation keys do I have?"
* "What's the translation coverage for Turkish?"
## Reading Tools
Fetch ALL translation keys with their translations in a single request.
Designed for AI usage - no pagination, returns everything.
**Parameters:**
* `namespaces` (optional): Filter by specific namespaces
* `search` (optional): Search keys by name
**Example Prompts:**
* "Show me all translations"
* "Get all keys in the auth namespace"
List translation keys with pagination and filtering options.
**Parameters:**
* `search`: Search by key name (partial match)
* `namespaces`: Filter by namespaces
* `missingLanguage`: Find keys that DON'T have a translation for this language
* `page`, `limit`: Pagination
**Example Prompts:**
* "Which keys are not yet translated to Turkish?"
* "List keys in the common namespace"
* "Find keys missing German translations"
## Writing Tools
Create one or more translation keys with optional translations.
Handles both single key creation and bulk operations efficiently.
**Parameters:**
* `k`: Array of keys to create, each containing:
* `n`: Unique key identifier (e.g., "submit\_button", "nav.home")
* `ns`: Namespace for grouping (default: "default")
* `v`: Source language text
* `t`: Target language translations (optional object: `{ "de": "...", "fr": "..." }`)
**Important:** Don't include the source language in translations (`t`) - it goes in `v`.
**Example Prompts:**
* "Create a new key called auth.login.title with source text 'Sign In'"
* "Add a new translation key for the submit button"
* "Create these new keys: nav.home, nav.about, nav.contact"
* "Add all these hardcoded strings as translation keys"
Update translations for one or more keys.
Handles both single updates and bulk operations. Works for both source and target languages.
**Parameters:**
* `t`: Array of updates, each containing:
* `k`: The key identifier to update
* `n`: Key name (optional)
* `ns`: Namespace of the key
* `l`: Language code to update
* `t`: New translation text
* `s`: Boolean flag, true if updating source language (optional)
**Note:** If `s` is true or `l` matches the source language, it updates the source text.
**Example Prompts:**
* "Update the Turkish translation for auth.login.title"
* "Change the German text for nav.home"
* "Translate all missing keys to Turkish"
* "Update these 10 translations"
* "Apply these translations to the project"
Add a new target language to the project.
**Parameters:**
* `languageCode`: ISO 639-1 code (e.g., "fr", "ja", "de")
**Example Prompts:**
* "Add Japanese to my project"
* "I want to support French"
***
## Best Practices
1. **Discover First**: Start with `listProjects` to find available projects.
2. **Analyze Structure**: Use `getProject` to understand namespaces and coverage.
3. **Find Gaps**: Use `listKeys` with `missingLanguage` to find untranslated keys.
4. **Use Array-based Tools**: `createKeys` and `updateKeys` handle both single and bulk operations efficiently.
5. **Human Verification**: Always review critical translations before shipping.
# API Reference
Complete API reference for the Next.js SDK.
## createI18n
The main entry point for the SDK. It returns an object containing everything needed for Next.js i18n integration.
```ts
import { createI18n } from "@better-i18n/next";
const i18n = createI18n(config);
```
### Return Properties
Configuration object intended for the `next-intl` request handler in `src/i18n/request.ts`.
Next.js middleware function that handles locale detection and URL routing (e.g., adding `/tr` prefix).
***
## Core Methods
Fetches the project manifest from the Better i18n CDN. This includes the list of supported languages and project metadata.
```ts
const manifest = await i18n.getManifest();
// Force refresh (bypass internal cache)
const manifest = await i18n.getManifest({ forceRefresh: true });
```
Fetches the full translation dictionary for a specific locale.
```ts
const messages = await i18n.getMessages("tr");
// Returns: { common: { welcome: "Hoş geldiniz" }, ... }
```
Returns an array of all available locale codes configured in your project.
```ts
const locales = await i18n.getLocales();
// ["en", "tr", "de", "fr"]
```
***
## Types
Commonly used types for manual integrations and custom logic.
```ts
import type {
I18nConfig,
LanguageOption,
Locale,
ManifestResponse,
Messages,
} from "@better-i18n/next";
```
# Configuration
The `createI18n` function is the entry point for the SDK. It accepts a configuration object that defines your project context and delivery preferences.
## Basic Configuration
The absolute minimum required is your project indentifier and default locale.
```ts title="i18n.config.ts"
import { createI18n } from "@better-i18n/next";
export const i18n = createI18n({
project: "your-org/your-project",
defaultLocale: "en",
});
```
The `project` value uses `org/project` format. This same value is used by the [CLI](/docs/cli) and [MCP](/docs/mcp) to identify your project.
You can also configure CLI-specific options (like linting rules and file exclusions) in this same file. See [CLI Configuration](/docs/cli/configuration) for details.
## Full Reference
| Option | Type | Default | Description |
| --------------------------- | ---------------------------------------- | ------------- | ------------------------------------------ |
| `project` | `string` | required | Project identifier in `org/project` format |
| `defaultLocale` | `string` | required | Default/fallback locale code |
| `cdnBaseUrl` | `string` | auto | CDN base URL (auto-detected) |
| `localePrefix` | `"as-needed"` \| `"always"` \| `"never"` | `"as-needed"` | URL locale prefix behavior |
| `debug` | `boolean` | `false` | Enable debug logging |
| `logLevel` | `LogLevel` | `"warn"` | Logging verbosity |
| `manifestCacheTtlMs` | `number` | `60000` | Manifest cache TTL in ms |
| `manifestRevalidateSeconds` | `number` | `60` | Next.js revalidate for manifest |
| `messagesRevalidateSeconds` | `number` | `60` | Next.js revalidate for messages |
***
## Behavior Customization
Control how locales appear in your URLs.
```ts
// /page for default, /tr/page for others
createI18n({ localePrefix: "as-needed" });
// always includes locale: /en/page, /tr/page
createI18n({ localePrefix: "always" });
// never includes locale in URL
createI18n({ localePrefix: "never" });
```
Configure TTL for edge and runtime caching.
```ts
createI18n({
// Cache manifest in memory for 5 minutes
manifestCacheTtlMs: 5 * 60 * 1000,
// Next.js ISR revalidation times
manifestRevalidateSeconds: 300,
messagesRevalidateSeconds: 300,
});
```
Enable detailed logging for troubleshooting.
```ts
createI18n({
debug: true,
logLevel: "debug",
});
```
# Getting Started
Get started with Better i18n in your Next.js app. Our SDK integrates seamlessly with `next-intl` to provide a type-safe, CDN-powered translation experience.
### Create a Project
1. Go to [dash.better-i18n.com](https://dash.better-i18n.com)
2. Create an organization (e.g., `my-company`)
3. Create a project (e.g., `web-app`)
Your project identifier will be in the format: `my-company/web-app`.
### Install the SDK
Install the package via your preferred package manager:
```bash
npm install @better-i18n/next
```
```bash
yarn add @better-i18n/next
```
```bash
pnpm add @better-i18n/next
```
```bash
bun add @better-i18n/next
```
### Configure i18n
Create an `i18n.config.ts` file in your project root. This file is shared between the SDK and the Better i18n CLI.
```ts title="i18n.config.ts"
import { createI18n } from "@better-i18n/next";
export const i18n = createI18n({
project: "my-company/web-app",
defaultLocale: "en",
});
```
### Set Up next-intl
Configure the `next-intl` request handler using the exported configuration.
```ts title="src/i18n/request.ts"
import { i18n } from "../i18n.config";
export default i18n.requestConfig;
```
### Add Middleware
Register the i18n middleware in your `middleware.ts`.
```ts title="middleware.ts"
import { i18n } from "./i18n.config";
export const middleware = i18n.middleware;
export const config = {
matcher: ["/((?!api|_next|.*\\..*).*)"],
};
```
### Use Translations
Now you can use standard `next-intl` hooks. The CLI will automatically track these scopes for syncing.
```tsx title="app/page.tsx"
import { useTranslations } from "next-intl";
export default function Home() {
const t = useTranslations("common");
return {t("welcome")}
;
}
```
## Next Steps
* Configure [caching and revalidation](/docs/next/configuration)
* Set up [middleware options](/docs/next/middleware)
* Explore the [API reference](/docs/next/api)
* Audit your keys with the [CLI](/docs/cli/sync)
# Middleware
Configure locale routing with the middleware.
## Basic Setup
```ts title="middleware.ts"
import { i18n } from "./src/i18n";
export const middleware = i18n.middleware;
export const config = {
matcher: ["/((?!api|_next|.*\\..*).*)"],
};
```
## Matcher Patterns
The matcher determines which routes use i18n:
```ts
export const config = {
matcher: [
// Skip API routes and static files
"/((?!api|_next|.*\\..*).*)",
],
};
```
## How It Works
1. Middleware detects locale from URL, cookies, or headers
2. Sets `x-locale` header for server components
3. Redirects to localized URL if needed
## Locale Detection Order
1. URL path (`/tr/about` → `tr`)
2. Cookie (`NEXT_LOCALE`)
3. Accept-Language header
4. Default locale from config
# Introduction
`@better-i18n/next` is the official SDK for integrating Better i18n translations into your Next.js application. It handles manifest fetching, caching, and provides a seamless integration with `next-intl`.
## Features
* ⚡ **Zero-Config Sync** - Connects to your project via `i18n.config.ts`.
* 🌍 **Edge-Ready Caching** - Built-in support for manifest and message caching.
* 🧪 **Type-Safe** - Full TypeScript support for your translation keys.
* 🤝 **next-intl First** - Designed to work perfectly as a message provider for `next-intl`.
## Installation
```bash
npm install @better-i18n/next
```
```bash
yarn add @better-i18n/next
```
```bash
pnpm add @better-i18n/next
```
```bash
bun add @better-i18n/next
```
## Quick Start
Create your configuration file to establish project context:
```ts title="i18n.config.ts"
import { createI18n } from "@better-i18n/next";
export const i18n = createI18n({
project: "your-org/your-project",
defaultLocale: "en",
});
```
## SDK Methods
The `createI18n` function returns a suite of tools to manage your i18n lifecycle:
| Method | Description |
| --------------------- | ------------------------------------------------------------------- |
| `requestConfig` | Ready-to-use configuration for `next-intl` request handler. |
| `middleware` | Next.js middleware for handling locale-based routing. |
| `getManifest()` | Fetches the latest project manifest (languages, metadata). |
| `getMessages(locale)` | Fetches the standard dictionary for a specific locale from the CDN. |
| `getLocales()` | Returns an array of available locale codes for the project. |
| `config` | The resolved configuration object. |