How Translations Are Managed and Implemented in tldr-pages

The tldr-pages project manages translations through parallel directory structures and automated Python sync scripts that propagate changes from English source files to localized versions using standardized templates.

The tldr-pages repository maintains command-line cheat sheets in dozens of languages, requiring a robust system to keep content synchronized across locales. Rather than using monolithic localization files, the project implements a file-based architecture where each language mirrors the English directory structure. This design enables automated synchronization through shared utilities in scripts/_common.py that detect locales, discover page paths, and apply language-specific boilerplate.

Directory Structure and Locale Detection

Translations reside in sibling directories to the main pages/ folder, following the naming convention pages.<locale> (e.g., pages.fr/, pages.pt_BR/). Each directory maintains identical platform subdirectories (common/, linux/, osx/, windows/) as the English source, allowing tooling to process all languages uniformly.

The get_locale() function in [scripts/_common.py](https://github.com/tldr-pages/tldr/blob/main/scripts/_common.py) extracts the language code from the parent directory name:

def get_locale(path: Path) -> str:
    pages_dirname = path.parents[1].name      # e.g. "pages.fr"

    if "." in pages_dirname:
        _, locale = pages_dirname.split(".")
    else:
        locale = "en"
    return locale

This function parses the directory structure to return "fr" for files in pages.fr/ and "en" for files in the base pages/ directory. The get_pages_dirs() function discovers all translation directories automatically by scanning for folders starting with "pages":

def get_pages_dirs(root: Path) -> list[Path]:
    return [
        d for d in root.iterdir()
        if d.name.startswith("pages") and not d.is_symlink()
    ]

Translation Templates

Standardized boilerplate for recurring sections like "More information" and "See also" lives in contributing-guides/translation-templates/. These Markdown files contain placeholder text that translators customize for each language.

The get_templates() function in _common.py reads these template files and returns a dictionary mapping locale codes to their specific translations:

def get_templates(root: Path, filename: str):
    template_file = root / "contributing-guides/translation-templates" / filename
    with template_file.open(encoding="utf-8") as f:
        lines = f.readlines()
    # … parses markdown sections …

    return templates   # { "fr": "...", "es": "...", ... }

For example, more-info-link.md contains localized versions of the > More information: <https://example.com> line, which sync scripts substitute with actual URLs while preserving the translated text.

Automated Sync Scripts

Four Python utilities in the scripts/ directory propagate changes from English pages to translations:

Each script imports helpers from _common.py and follows the same pattern: detect the locale, load the appropriate template, modify the target file, and optionally stage changes with Git.

The link synchronization logic in set-more-info-link.py demonstrates this workflow:

def set_link(path: Path, link: str, dry_run: bool = False,
              language_to_update: str = "") -> str:
    locale = get_locale(path)
    if language_to_update and locale != language_to_update:
        return ""

    with path.open(encoding="utf-8") as f:
        lines = f.readlines()

    # locate description block

    for i, line in enumerate(lines):
        if line.startswith(">") and desc_start == 0:
            desc_start = i
        if not lines[i + 1].startswith(">") and desc_start != 0:
            desc_end = i
            break

    new_line = config.templates[locale].replace("https://example.com", link)

    if lines[desc_end] == new_line:
        return ""                           # nothing to do

    if re.search(r"^>.*<.+>", lines[desc_end]):   # existing link

        lines[desc_end] = new_line
        action = "updated"
    else:                                          # add link

        lines.insert(desc_end + 1, new_line)
        action = "added"

    status = get_status(action, dry_run, "link")
    if not dry_run:
        with path.open("w", encoding="utf-8") as f:
            f.writelines(lines)
    return status

This function locates the description block (lines starting with >), determines whether to update an existing link or insert a new one, and applies the locale-specific template before writing changes.

Practical Workflow for Maintainers

Contributors use these scripts through a command-line interface that supports dry-run verification and Git staging. The typical workflow involves updating the English source first, then propagating changes across all translations.


# Add a "More information" link to the English page

python3 scripts/set-more-info-link.py -p common/tar https://tldr.sh/pages/common/tar

# Preview changes across all translations without writing files

python3 scripts/set-more-info-link.py -S -n

# Apply changes and stage modified files for commit

python3 scripts/set-more-info-link.py -S -s

The -S or --sync flag instructs the script to read the English source and apply it to all language directories. The -n flag enables dry-run mode for safety, while -s stages changes using Git.

Summary

  • Parallel directory architecture separates translations into pages.<locale>/ folders that mirror the English pages/ structure.
  • Locale detection occurs through get_locale() in _common.py, which parses directory names to determine language codes.
  • Translation templates in contributing-guides/translation-templates/ provide standardized boilerplate for common sections across all languages.
  • Sync scripts (set-more-info-link.py, set-page-title.py, etc.) automate propagation of changes from English sources to translations using shared utilities for file discovery and template application.
  • Git integration allows maintainers to stage changes automatically via the -s flag, streamlining the contribution workflow.

Frequently Asked Questions

How does tldr-pages determine the language of a specific page?

The repository uses the get_locale() function in scripts/_common.py to inspect the parent directory name. If the directory is pages.fr, the function returns "fr"; for pages.pt_BR, it returns "pt_BR"; and for the base pages directory, it defaults to "en". This inference happens at runtime whenever a sync script processes a file.

What are translation templates and where are they stored?

Translation templates are Markdown files containing boilerplate text for recurring elements like "More information" links and "See also" sections. They reside in contributing-guides/translation-templates/ and provide the canonical wording that translators adapt. The get_templates() function loads these files and maps content to specific locales for use by synchronization scripts.

How do sync scripts handle existing content in translations?

Scripts like set-more-info-link.py parse the target file to determine whether content exists or needs insertion. For documentation links, the script checks if a URL pattern already exists using regex; if found, it updates the line with the new link while preserving the translated text from the template. If no link exists, the script inserts a new line after the description block, ensuring content is added without overwriting unrelated text.

Can I synchronize changes to only one specific language?

Yes. All sync scripts accept a language_to_update parameter (typically via the -L flag) that filters processing to a single locale. When specified, the script compares the detected locale from get_locale() against the requested language and skips files that do not match, allowing targeted updates without affecting other translations.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →