🎉 v1.0

Get started

  • Welcome
  • Documentation
  • Pricing
    Soon

Tools

  • I18n MCP
  • CLI
  • CI/CD Integrations
  • Compiler
    Alpha
  • Connect Your Engine

Resources

  • Languages
  • LLM Models
  • Guides

Company

  • Enterprise
  • CareersHiring!
Dashboard

Lingo.dev Compiler

  • How it works
  • Setup

Framework Integration

  • Next.js
  • Vite + React

Configuration

  • Configuration Reference
  • Translation Providers
  • Build Modes

Features

  • Manual Overrides
  • Custom Locale Resolvers
  • Automatic Pluralization
  • Locale Switching

Development

  • Development Tools
  • Project Structure

Guides

  • Best Practices
  • Migration Guide
  • Troubleshooting

Project Structure

Max PrilutskiyMax Prilutskiy·Updated 5 days ago·3 min read

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:

text
.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 resolver

metadata.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:

gitignore
# Do NOT ignore .lingo/ - it contains translation cache
node_modules/
dist/
.env

sourceRoot#

The sourceRoot option determines which directory the compiler scans for translatable React components:

ts
{
  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 valueWhat 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:

ts
{
  useDirective: true,
}

In opt-in mode, only files that start with the 'use i18n' directive are processed:

tsx
'use i18n';

export function Welcome() {
  return <h1>Welcome to our app</h1>;
  // This text IS translated
}

Files without the directive are skipped:

tsx
export function InternalAdmin() {
  return <h1>Admin Dashboard</h1>;
  // This text is NOT translated
}

When to use opt-in mode#

ScenarioRecommended mode
Small app where all content should be translatedDefault (useDirective: false)
Large codebase with only some user-facing pagesOpt-in (useDirective: true)
Monorepo with shared internal and external componentsOpt-in (useDirective: true)
Gradual adoption - adding i18n to an existing appOpt-in (useDirective: true)

lingoDir#

The lingoDir option changes the location of the metadata directory:

ts
{
  lingoDir: ".lingo",  // Default
  // or
  lingoDir: ".translations",  // Custom location
}

This is useful if .lingo/ conflicts with an existing directory in your project.

Next Steps#

Build Modes
How metadata.json is used in each mode
Custom Locale Resolvers
Add resolver files to .lingo/
Configuration Reference
sourceRoot, lingoDir, and useDirective options
Best Practices
Version control and project setup tips

Was this page helpful?