Skip to content

Configuration

Lingo.dev uses two key configuration files: i18n.json and i18n.lock. These files control how Lingo.dev handles your translations and tracks changes.

i18n.json

This file defines your translation setup and file structure. It specifies the source and target languages, as well as the translation buckets (more on that later).

Here's an example i18n.json file:

json
{
  "version": 1.1,
  "locale": {
    "source": "en",
    "targets": ["es"]
  },
  "buckets": {
    "json": {
      "include": ["locales/[locale].json"]
    },
    "xcode": {
      "include": ["xcode/Localizable.xcstrings"]
    },
    "android": {
      "include": ["android/[locale].xml"]
    },
    "yaml": {
      "include": ["yaml/[locale].yml"]
    },
    "yaml-root-key": {
      "include": ["yaml-root-key/[locale].yml"]
    },
    "markdown": {
      "include": ["markdown/[locale].md"]
    }
  }
}

Now, let's break down the different sections of this file.

Locale

  • source: Your primary language for content creation.
  • targets: Languages you want to translate into.

Pro tip: there's a handy command to list supported locales:

bash
replexica show sources  # List source locales
replexica show targets  # List target locales

# Check if a specific [target] locale is supported
replexica show targets | grep fr

Buckets

Buckets define where Lingo.dev finds and saves translations. Each bucket specifies a file type and includes an include array for file patterns to translate. Optionally, you can add an exclude array to ignore certain files.

Simple example:

json
{
  "buckets": {
    "json": {
      "include": ["locales/[locale].json"],
      "exclude": ["locales/[locale]/skip.json"]
    }
  }
}

For more advanced cases, you can customize how locale codes appear in filenames. You can specify paths in two ways:

  1. Simple string pattern (uses default delimiter):
json
"include": ["locales/[locale].json"]
  1. Object with custom delimiter (overrides default):
json
"include": [
  {
    "path": "locales/[locale].json",
    "delimiter": "_"  // Use underscore instead of default delimiter
  }
]

The delimiter can be:

  • - (dash, e.g., en-US)
  • _ (underscore, e.g., en_US)

When not specified in the path object (or set to null), the delimiter defaults to the one used in your source and targets fields. For example:

json
{
  "locale": {
    "source": "en-US", // Uses dash as default delimiter
    "targets": ["es-ES", "fr-FR"]
  },
  "buckets": {
    "json": {
      "include": [
        "locales/[locale].json", // Will use dash: en-US.json, es-ES.json
        {
          "path": "other/[locale].json",
          "delimiter": "_" // Will use underscore: en_US.json, es_ES.json
        }
      ]
    }
  }
}

This is particularly useful when different files in your project use different locale code formats (e.g., some files using en-US.json while others use en_US.json).

  1. JSON (json)

    • Include pattern: locales/[locale].json
    • Requires [locale]: Yes
    • Creates separate JSON files for each language.
  2. Xcode (xcode)

    • Include pattern: xcode/Localizable.xcstrings
    • Requires [locale]: No
    • Uses a single file for all languages in Xcode's format.
  3. Android (android)

    • Include pattern: android/[locale].xml
    • Requires [locale]: Yes
    • Creates separate XML files for each language, following Android's structure.
  4. YAML (yaml)

    • Include pattern: yaml/[locale].yml
    • Requires [locale]: Yes
    • Creates separate YAML files for each language.
  5. YAML with root key (yaml-root-key)

    • Include pattern: yaml-root-key/[locale].yml
    • Requires [locale]: Yes
    • Creates YAML files with root keys, commonly used in Ruby on Rails. The key difference from the regular YAML format is that it wraps all translations under a root key (e.g., en:, es:) that matches the locale.
  6. Markdown (markdown)

    • Include pattern: markdown/[locale].md
    • Requires [locale]: Yes
    • Creates separate Markdown files for each language.

The [locale] placeholder is crucial for formats that require separate files per language. It's dynamically replaced with the actual language code (e.g., "en", "es") during processing.

TIP

You can use multiple include patterns and exclude specific files. For example:

json
"markdown": {
  "include": [
    "docs/[locale]/*.md",
    "blog/[locale]/*.md"
  ],
  "exclude": [
    "docs/[locale]/internal-*.md"
  ]
}

This will translate all Markdown files in docs and blog directories, except for those starting with internal- in the docs directory.

i18n.lock

The i18n.lock file is a key element behind Lingo.dev's efficient translation process. It stores checksums of the source content (in your repo, so you're in full control), enabling Lingo.dev to detect changes and only translate what's necessary.

yaml
version: 1
checksums:
  a07974ea09011daa56f9df706530e442:
    key: f8692d39317193acf0e2e47172703c46

Key aspects of i18n.lock:

  1. Purpose:

    • Tracks the state of source content;
    • Enables efficient updates by identifying changed content;
    • Ensures consistency across your translation workflow.
  2. Usage:

    • Automatically generated and updated by Lingo.dev;
    • Should be committed to your version control system;
    • Helps in CI/CD pipelines to determine necessary translation updates.
  3. Benefits:

    • Reduces unnecessary translation requests;
    • Speeds up the translation process in subsequent runs;
    • Provides a clear history of content changes.

By leveraging both i18n.json and i18n.lock, Lingo.dev offers a robust, efficient, and version-controlled approach to managing your project's localization infrastructure. The new bucket configuration in i18n.json allows for more granular control over which files are included in or excluded from the translation process, giving you greater flexibility in managing your localization workflow.