Skip to content

feat(cli): add fern docs translation generate command for interactive i18n setup#15479

Open
dsinghvi wants to merge 5 commits intomainfrom
devin/1777353141-docs-translate-command
Open

feat(cli): add fern docs translation generate command for interactive i18n setup#15479
dsinghvi wants to merge 5 commits intomainfrom
devin/1777353141-docs-translate-command

Conversation

@dsinghvi
Copy link
Copy Markdown
Member

@dsinghvi dsinghvi commented Apr 28, 2026

Description

Add a new fern docs translation generate command that interactively sets up internationalization for Fern documentation sites.

Changes Made

  • Added docsTranslate.ts — core command that detects existing translations/languages config, prompts for default and target languages, updates docs.yml, and creates translations/<lang>/ directories
  • Registered fern docs translation generate subcommand in cli.ts (nested command group)
  • Supports 15 languages with native-script display names
  • Handles fresh setup, existing translations config, and legacy languages field
  • Rich formatted logging with progress indicators and next-step guidance
  • Fixed regex to properly capture multi-line YAML translation entries (e.g., entries with default: true continuation lines)
  • Updated changelog entry

Testing

  • Local compilation (94/94 tasks pass)
  • Lint and format checks pass
  • Interactive flow tested with fresh docs.yml (no existing translations) — prompts for default language + target languages, updates YAML, creates directories
  • Interactive flow tested with existing translations block (en + ja, adding ko) — detects existing config, skips default prompt, only offers remaining languages, merges correctly
  • Verified docs.yml output correctness in both scenarios
  • Verified translation directories created correctly

Link to Devin session: https://app.devin.ai/sessions/ccd7fd9e45ce416287a246d4a0a31b51
Requested by: @dsinghvi

Co-Authored-By: Deep Singhvi <deep@buildwithfern.com>
@devin-ai-integration
Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

Comment on lines +92 to +94
const translationsRegex = /^translations:\s*\n(?:\s+-[^\n]*\n?)*/m;
if (translationsRegex.test(rawContent)) {
return rawContent.replace(translationsRegex, translationsBlock + "\n");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regex pattern doesn't correctly match multi-line YAML list items. The pattern (?:\s+-[^\n]*\n?)* only matches lines that start with a dash (-), but YAML list items can have additional indented properties without dashes (like default: true).

For example, this existing block:

translations:
  - lang: en
    default: true
  - lang: es

Would only match up to - lang: en\n, stopping at default: true because it lacks a dash. This causes incomplete replacement, leaving orphaned YAML and corrupting the docs.yml file.

Fix: Use a more comprehensive regex that matches the entire YAML block:

const translationsRegex = /^translations:\s*\n(?:(?:  |\t)+-[^\n]*\n(?:(?:    |\t\t)+[^\n]+\n)*)*(?=\S|$)/m;

Or use a YAML parser library to safely manipulate the structure instead of regex replacement.

Suggested change
const translationsRegex = /^translations:\s*\n(?:\s+-[^\n]*\n?)*/m;
if (translationsRegex.test(rawContent)) {
return rawContent.replace(translationsRegex, translationsBlock + "\n");
const translationsRegex = /^translations:\s*\n(?:[ \t]+[^\n]*\n?)*/m;
if (translationsRegex.test(rawContent)) {
return rawContent.replace(translationsRegex, translationsBlock + "\n");

Spotted by Graphite

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

devin-ai-integration Bot and others added 2 commits April 30, 2026 18:37
…ion generate`

Co-Authored-By: Deep Singhvi <deep@buildwithfern.com>
Co-Authored-By: Deep Singhvi <deep@buildwithfern.com>
@devin-ai-integration devin-ai-integration Bot changed the title feat(cli): add fern docs translate command for interactive i18n setup feat(cli): add fern docs translation generate command for interactive i18n setup Apr 30, 2026
devin-ai-integration Bot and others added 2 commits April 30, 2026 19:11
…ssues in CI

Co-Authored-By: Deep Singhvi <deep@buildwithfern.com>
Co-Authored-By: Deep Singhvi <deep@buildwithfern.com>
@devin-ai-integration
Copy link
Copy Markdown
Contributor

E2E Test Report

Both tests passed after fixing a bug found during testing.

Bug Found & Fixed

The regex in updateDocsYamlContent (/^translations:\s*\n(?:\s+-[^\n]*\n?)*/m) only captured lines starting with - (dash lines) but not continuation lines like default: true. This caused partial replacement when existing translations had multi-line entries, resulting in duplicate/malformed YAML output. Fixed with a simpler regex that captures all indented lines under the translations: key.

Test Results

Test Result
Fresh docs.yml (no existing translations) Passed
Existing translations (en + ja, adding ko) Passed
Test 1: Fresh docs.yml

Setup: Minimal fern project with docs.yml containing only instances: [] and navigation.

Assertions:

  • Command reachable at fern docs translation generate — passed
  • Header "🌐 Fern Docs — Internationalization Setup" displayed — passed
  • Prompted "Is English your default documentation language?" — passed (answered Yes)
  • Checkbox prompt for target languages appeared — passed (selected Spanish, French)
  • docs.yml updated with correct translations block — passed:
    translations:
      - lang: en
        default: true
      - lang: es
      - lang: fr
  • translations/es/ and translations/fr/ directories created — passed
  • Summary with "Internationalization setup complete!" and next steps displayed — passed
Test 2: Existing translations

Setup: Fern project with docs.yml containing existing translations: block with en (default) and ja.

Assertions:

  • "Existing translations detected: English, Japanese" displayed — passed
  • "Default language: English" displayed — passed
  • Did NOT prompt for default language (already set) — passed
  • Checkbox did NOT include English or Japanese — passed (selected Korean)
  • docs.yml correctly merged all languages — passed:
    translations:
      - lang: en
        default: true
      - lang: ja
      - lang: ko
  • Only translations/ko/ directory created (not ja) — passed

Devin session

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant