Alpha
The Lingo.dev Compiler is in alpha. It is unstable, not recommended for production use, and APIs may change between releases.
The Lingo.dev Compiler creates and maintains a .lingo/ directory in your project root that stores translation metadata and cache. Understanding this directory structure helps you manage translations in version control, debug missing translations, and optimize build performance.
The .lingo/ directory#
The compiler creates this directory automatically on the first build. It contains all translation metadata used by the build pipeline:
.lingo/
metadata.json # Translation cache and content hashes
locale-resolver.server.ts # Optional: custom server-side locale resolver
locale-resolver.client.ts # Optional: custom client-side locale resolvermetadata.json#
This is the primary file in the .lingo/ directory. It stores:
- Content hashes - Stable hash-based identifiers for each translatable string
- Cached translations - Generated translations for each locale pair
- Source text snapshots - The source text at the time of translation, used to detect changes
The compiler reads this file at the start of each build. Strings with matching hashes reuse cached translations. Strings with changed or missing hashes are sent to the configured translation provider.
Commit to version control
Always commit .lingo/metadata.json to your repository. Production builds in cache-only mode read translations exclusively from this file. If it is not committed, production builds will fail.
.gitignore considerations#
Do not add .lingo/ to .gitignore. The directory should be tracked in version control. A typical .gitignore for a project using the compiler:
# Do NOT ignore .lingo/ - it contains translation cache
node_modules/
dist/
.envsourceRoot#
The sourceRoot option determines which directory the compiler scans for translatable React components:
{
sourceRoot: "./app", // Next.js App Router
// or
sourceRoot: "src", // Vite + React
}The compiler recursively scans all .tsx, .ts, .jsx, and .js files within sourceRoot for translatable JSX content. Files outside this directory are not processed.
| sourceRoot value | What gets scanned |
|---|---|
"./app" | All files in the app/ directory (Next.js convention) |
"src" | All files in the src/ directory (Vite convention) |
"." | All files in the project root (useful for monorepos with shared packages) |
A broader sourceRoot scans more files, which increases build time. Keep it as narrow as possible. If only some files need translation, use the useDirective option instead.
Opt-in mode with 'use i18n'#
By default, the compiler translates all JSX text in sourceRoot. To switch to opt-in mode, set useDirective: true:
{
useDirective: true,
}In opt-in mode, only files that start with the 'use i18n' directive are processed:
'use i18n';
export function Welcome() {
return <h1>Welcome to our app</h1>;
// This text IS translated
}Files without the directive are skipped:
export function InternalAdmin() {
return <h1>Admin Dashboard</h1>;
// This text is NOT translated
}When to use opt-in mode#
| Scenario | Recommended mode |
|---|---|
| Small app where all content should be translated | Default (useDirective: false) |
| Large codebase with only some user-facing pages | Opt-in (useDirective: true) |
| Monorepo with shared internal and external components | Opt-in (useDirective: true) |
| Gradual adoption - adding i18n to an existing app | Opt-in (useDirective: true) |
lingoDir#
The lingoDir option changes the location of the metadata directory:
{
lingoDir: ".lingo", // Default
// or
lingoDir: ".translations", // Custom location
}This is useful if .lingo/ conflicts with an existing directory in your project.
