Skip to main content

Configuration

Champollion works zero-config — it auto-detects locale files, format, and target languages from your project. For more control, create champollion.config.json in your project root, or run:

npx champollion init

Full Config Reference

champollion.config.json
{
"version": 3,
"inputLocale": "en",
"localesDir": "./locales",
"contentDir": null,
"translatableFields": null,
"format": "auto",
"model": "google/gemini-3.5-flash",
"temperature": 0.3,
"defaultMethod": "llm",
"batchSize": 80,
"coachingFile": null,
"promptContext": null,
"jsonConcurrency": 200,
"contentConcurrency": 48,
"fallbackPrefix": "[EN] ",
"apiKeyEnvVar": "OPENROUTER_API_KEY",
"baseUrl": "",
"pairs": {},
"languages": {},
"lint": {
"srcDir": null,
"ignore": ["node_modules", ".next", "dist"],
"minLength": 2
},
"seo": {
"urlPattern": "/:locale/:path",
"pages": null
},
"typegen": {
"output": null,
"autoGenerate": false
}
}

:::note typegen is not yet implemented The typegen config block is recognized and preserved by the config loader, but TypeScript type generation is not yet implemented. This is a placeholder for a planned feature. Setting these values has no effect. :::

Fields

FieldTypeDefaultDescription
versionnumber3Config schema version. Always 3.
inputLocalestring"en"Source language code (BCP 47).
localesDirstring"./locales"Path to locale files. Champollion scans this directory.
contentDirstringnullHugo content directory. Enables Markdown body translation.
translatableFieldsstring[]nullOverride default translatable frontmatter fields for content translation. null uses built-in defaults (title, description, summary).
formatstring"auto"File format: json, toml, yaml, or auto (detect from extension).
modelstring"google/gemini-3.5-flash"Default model for LLM methods. Accepts full OpenRouter slugs (provider/model) or short aliases from shared/model-aliases.json (e.g., gemini-flash). Direct providers use bare names (e.g., gpt-4o).
temperaturenumber0.3LLM temperature (0.0–2.0). Lower = more deterministic.
defaultMethodstring"llm"Default translation method: llm, llm-coached, google-translate, deepl, microsoft-translator, libretranslate, openai, anthropic, gemini, api. Overridden by --method CLI flag.
batchSizenumber80Keys per translation batch. Higher = fewer API calls, but larger prompts.
coachingFilestringnullPath to a free-text coaching prompt file (relative to project root). Contents are read at startup and injected into the system prompt as a Coaching guidance: block.
promptContextstringnullApplication context string injected into the system prompt (e.g., "E-commerce product descriptions"). Helps the model tailor translations to your domain.
jsonConcurrencynumber200Max parallel locale translations for JSON key sync. Overridden by --json-concurrency CLI flag.
contentConcurrencynumber48Max parallel API calls for content (Markdown/MDX) translation. Overridden by --content-concurrency CLI flag.
fallbackPrefixstring"[EN] "Marker prefix used by audit and verify to detect legacy untranslated values from prior runs. Champollion does not write this prefix — it only reads it for detection.
apiKeyEnvVarstring"OPENROUTER_API_KEY"Environment variable name for the API key. Override for custom env var names.
baseUrlstring""Base URL for SEO artifact generation (hreflang, sitemaps, JSON-LD).
pairsobject{}Per-pair method, model, and quality overrides. See Pair Configuration.
languagesobject{}Per-language overrides. See Language Configuration.
lint.srcDirstringnullSource directory for lint scanning. null = auto-detect from framework.
lint.ignorestring[]["node_modules", ...]Glob patterns to exclude from lint.
lint.minLengthnumber2Minimum string length to flag as hardcoded.
seo.urlPatternstring"/:locale/:path"URL pattern template for hreflang tag generation.
seo.pagesstring[]nullExplicit page list for SEO. null = auto-detect from locale keys.
typegen.outputstringnullOutput path for generated TypeScript types. null = disabled.
typegen.autoGeneratebooleanfalseAuto-regenerate types after each sync.

Pair Configuration

Each source→target pair can be independently configured:

{
"pairs": {
"en:fr": {
"method": "google-translate",
"qualityTier": "high"
},
"en:ja": {
"method": "llm",
"model": "google/gemini-2.5-pro"
},
"en:crk": {
"methodPlugin": "crk-coached-v1"
}
}
}

Pair Fields

FieldTypeDescription
methodstringTranslation method: llm, llm-coached, google-translate, deepl, microsoft-translator, libretranslate, openai, anthropic, gemini, api
methodPluginstringName of an installed plugin (from .champollion/methods/)
modelstringOverride the default model for this pair
temperaturenumberOverride the default temperature for this pair
batchSizenumberOverride the default batch size for this pair
registerstringRegister/tone override (preset key or freeform text)
endpointstringRemote API endpoint URL. Required when method is api.
coachingFilestringPath to a coaching prompt file for this pair
promptContextstringApplication context for this pair
qualityTierstringDisplay tier: standard, high, research, verified

Language Configuration

Languages accept three formats:

Array of codes (simplest)

{
"languages": ["fr", "de", "ja"]
}

Each language gets its default register from the built-in register table. Languages without a default get "Professional register.".

Object with register strings

The value can be a preset key from the language's card, or custom register text:

{
"languages": {
"fr": "casual-tu",
"ko": "formal-hapsyo",
"ja": "Custom: Polite Japanese for a gaming app."
}
}

Champollion checks if the string matches a preset key in the language card. If it does, the full register prompt from the card is used. If not, the string is used as-is. See Supported Languages for available presets.

Object with full config

{
"languages": {
"crk": {
"name": "Plains Cree",
"register": "SRO syllabics with grammatical precision.",
"model": "google/gemini-2.5-pro",
"batchSize": 5,
"maxRetries": 5,
"script": "cans"
}
}
}

You can mix shorthand and full objects in the same block.

Language Fields

FieldTypeDescription
registerstringStyle/tone instructions. Can be a preset key (e.g., casual-tu, formal-hapsyo) or custom text. See Language Cards.
namestringHuman-readable language name (for status display)
modelstringOverride the default model
temperaturenumberOverride the default temperature
batchSizenumberOverride the default batch size
coachingFilestringPath to a coaching prompt file for this language
promptContextstringApplication context for this language
maxRetriesnumberMaximum retry budget for failed batches (default: 3)
scriptstringISO 15924 script code. Triggers script validation in the quality gate.

:::info Inheritance chain Settings resolve in this order (first wins):

pair-levellanguage-levelglobal configdefaults

For example, if pairs["en:fr"] sets model, it overrides both the language-level and global model values. :::

Non-English Source

If your source language isn't English:

# CLI flag (one-time)
npx champollion sync --source fr
champollion.config.json (permanent)
{
"inputLocale": "fr"
}

Lock File

Champollion creates .champollion.lock to track SHA-256 hashes of translated source values. Commit this file so all developers share the same translation baseline.

When a source value changes, the hash no longer matches, and champollion re-translates that key on the next sync.

.champollionignore

Create .champollionignore in your project root to exclude files from lint scanning. Uses glob patterns, like .gitignore:

.champollionignore
src/components/legacy/**
src/utils/constants.js
**/*.test.js

.champollion/ Directory

Champollion creates a .champollion/ directory in your project root for internal state. You should generally add this to .gitignore — it's local optimization, not project source:

.champollion/
FilePurposeCommit?
tm.jsonTranslation Memory cache — stores previous translations keyed by source text + locale + methodNo (local cache)
xliff/*.xliffXLIFF export files for professional translator reviewNo (transient)
methods/Installed method plugin manifestsYes (shared config)
backups/Pre-wrap backups (created by wrap --undo)No (safety net)

See Translation Memory for details on tm.json and how it saves API costs.


Programmatic API

For build scripts and custom integrations, import directly from the package:

import { GeminiMethod, runSync, resolveConfig } from 'champollion';

// Use a method class directly
const gemini = new GeminiMethod();
const result = await gemini.translate(
['greeting', 'farewell'],
{ greeting: 'Hello', farewell: 'Goodbye' },
{ target: 'fr', name: 'French', register: 'formal', model: 'gemini-2.5-flash' },
{ cwd: process.cwd() }
);
// result = { greeting: 'Bonjour', farewell: 'Au revoir' }

Available Exports

ExportWhat It Does
TranslationMethodBase class for all methods
LLMMethodBase class for LLM methods (OpenRouter)
DirectLLMMethodBase class for direct LLM providers (OpenAI, Anthropic, Gemini)
OpenAIMethod, AnthropicMethod, GeminiMethodDirect LLM provider classes
DeepLMethod, MicrosoftTranslatorMethod, LibreTranslateMethodTraditional MT classes
GoogleTranslateMethodGoogle Cloud Translation
LLMCoachedMethodCoached LLM (OpenRouter + coaching data)
APIMethodRemote API client
runSync, runContentSyncFull sync pipeline
resolveConfig, resolvePairsConfig resolution
validateTranslationsQuality gate
loadCoachingData, findDictionaryMatchesCoaching utilities

Custom Provider Extension

Extend DirectLLMMethod to add a new LLM provider in ~40 lines:

import { DirectLLMMethod } from 'champollion';

class MistralMethod extends DirectLLMMethod {
constructor(options) {
super(options);
this.name = 'mistral';
}
_getApiKeyEnvVar() { return 'MISTRAL_API_KEY'; }
_getApiKeyOptionsKey() { return 'mistralApiKey'; }
_getDefaultModel() { return 'mistral-large-latest'; }
_getProviderLabel() { return 'Mistral'; }

_buildApiRequest({ prompt, systemMessage, apiKey, model, temperature }) {
return {
url: 'https://api.mistral.ai/v1/chat/completions',
headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' },
body: {
model,
messages: [
...(systemMessage ? [{ role: 'system', content: systemMessage }] : []),
{ role: 'user', content: prompt },
],
temperature,
},
};
}

_extractResponseText(json) {
return json.choices?.[0]?.message?.content;
}

// Optional but recommended: provider-specific setup help when translation fails
getSetupHelp() {
if (!process.env.MISTRAL_API_KEY) {
return [
'',
' ┌─ Missing API Key ─────────────────────────────────────────────┐',
' │ Mistral requires an API key from https://console.mistral.ai │',
' │ Run: export MISTRAL_API_KEY=... │',
' └────────────────────────────────────────────────────────────────┘',
];
}
return [' API key is set but translation failed. Check your Mistral dashboard.'];
}
}

You get translate, coaching, retry loops, model validation, quality tiers, and setup help for free. Only the HTTP request shape is provider-specific. For non-LLM adapters that use raw fetch(), use the shared fetchWithRetry() helper from lib/methods/fetch-with-retry.js instead of writing your own retry loop.


See Also