Skip to content

Write extraction only to the source locale - #36

Merged
k0d13 merged 2 commits into
mainfrom
kodie/extract-source-locale-only
Jul 19, 2026
Merged

Write extraction only to the source locale#36
k0d13 merged 2 commits into
mainfrom
kodie/extract-source-locale-only

Conversation

@k0d13

@k0d13 k0d13 commented Jul 19, 2026

Copy link
Copy Markdown
Owner

Closes #34

Summary by CodeRabbit

  • New Features

    • Added the saykit clean command to reconcile non-source locale files while preserving existing translations.
    • Added configurable per-locale fallback chains, ensuring missing translations fall back to appropriate locales and source text.
    • Extraction now writes only the source locale and creates placeholders for missing locale files.
    • Build integrations now merge locale catalogues using fallback chains.
  • Documentation

    • Updated CLI, configuration, integration, API, and quickstart guides to explain source-only extraction, fallback behaviour, and cleanup workflows.

@changeset-bot

changeset-bot Bot commented Jul 19, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 299fc6c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
Name Type
@saykit/config Major
babel-plugin-saykit Major
unplugin-saykit Major
@saykit/format-po Major
@saykit/transform-js Major
@saykit/transform-jsx Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Jul 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
saykit Ready Ready Preview, Comment Jul 19, 2026 4:39pm

@github-actions github-actions Bot added tests Modifications, additions, or fixes related to testing package: config Related to @saykit/config and the CLI package: babel-plugin Related to babel-plugin-saykit package: unplugin Related to unplugin-saykit website Updates to the documentation website labels Jul 19, 2026
@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@k0d13, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 48 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8201ebbd-cad3-4625-9ec9-3553a1c82dbd

📥 Commits

Reviewing files that changed from the base of the PR and between 484d7c0 and 299fc6c.

📒 Files selected for processing (1)
  • .changeset/source-locale-extraction.md

Walkthrough

Extraction now writes only source-locale catalogues, missing locales are bootstrapped, and saykit clean reconciles other locales. Configurable fallback chains are shared by Babel and Unplugin catalogue loading, with updated exports, tests, and documentation.

Changes

Locale catalogue flow

Layer / File(s) Summary
Catalogue contracts and fallback assembly
packages/config/src/shapes.ts, packages/config/src/features/catalogue/*, packages/config/package.json, packages/config/tsdown.config.ts
Adds fallbackLocales, fallback-chain resolution, merged catalogue records, updated reconciliation semantics, tests, and public catalogue exports.
Source-only extraction and clean command
packages/config/src/features/workers/*, packages/config/src/commands/*
Extraction writes the source locale, creates missing placeholders, preserves existing non-source files, and registers saykit clean for reconciliation.
Fallback-aware plugin loading
packages/plugin-babel/src/*, packages/plugin-unplugin/src/*
Plugins load fallback-chain files, merge translations with source-text fallbacks, and track catalogue files for rebuilds.
Documentation and distribution updates
README.md, packages/config/README.md, website/content/*
Documents source-only extraction, fallback chains, saykit clean, plugin behaviour, and the catalogue API.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ExtractCommand
  participant BucketExtractWorker
  participant LocaleFiles
  participant CleanCommand
  ExtractCommand->>BucketExtractWorker: extract messages
  BucketExtractWorker->>LocaleFiles: write source locale
  BucketExtractWorker->>LocaleFiles: create missing placeholders
  CleanCommand->>LocaleFiles: reconcile non-source locales
Loading

Possibly related PRs

Poem

A bunny found strings in a source-coloured tray,
And left translated files just where they lay.
Fallbacks hopped through locales bright,
While clean swept stale keys out of sight.
“Merge with care!” cried the rabbit with glee.

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning Extraction mostly matches, but it still creates placeholder files for non-source locales, so other locales are not completely untouched. Stop writing any non-source locale files during extract; if bootstrapping is needed, move it to TMS or a separate sync command.
Out of Scope Changes check ⚠️ Warning The PR adds fallbackLocales, catalogue helpers, clean command, and plugin/runtime changes that go beyond source-only extraction. Split fallback/clean/plugin work into a separate PR or clearly justify it as part of the extraction issue.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: extraction now writes only the source locale.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch kodie/extract-source-locale-only

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

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.

🧹 Nitpick comments (1)
packages/config/src/features/catalogue/record.ts (1)

42-47: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Prefer nullish coalescing operator for optional string fields.

If message.translation is explicitly set to an empty string (e.g. legitimately translated as empty), using the logical OR (||) operator will incorrectly fall back to message.message. Using the nullish coalescing operator (??) ensures that only null or undefined will trigger the fallback, preserving intentional empty strings.

♻️ Proposed refactor
   for (const content of [...contents].reverse()) {
     if (!content) continue;
     for (const message of bucket.formatter.parse(content)) {
-      const key = message.id || generateHash(message.message, message.context);
-      record[key] = message.translation || message.message;
+      const key = message.id ?? generateHash(message.message, message.context);
+      record[key] = message.translation ?? message.message;
     }
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/config/src/features/catalogue/record.ts` around lines 42 - 47,
Update the assignment in the record-building loop to use nullish coalescing for
message.translation, so empty-string translations are preserved and only null or
undefined values fall back to message.message.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/config/src/features/catalogue/record.ts`:
- Around line 42-47: Update the assignment in the record-building loop to use
nullish coalescing for message.translation, so empty-string translations are
preserved and only null or undefined values fall back to message.message.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 41d9ebc0-1c96-44d3-887e-79ebdd088356

📥 Commits

Reviewing files that changed from the base of the PR and between ae00b81 and 484d7c0.

📒 Files selected for processing (27)
  • README.md
  • packages/config/README.md
  • packages/config/package.json
  • packages/config/src/commands/clean.ts
  • packages/config/src/commands/index.ts
  • packages/config/src/features/catalogue/index.ts
  • packages/config/src/features/catalogue/merge.test.ts
  • packages/config/src/features/catalogue/merge.ts
  • packages/config/src/features/catalogue/record.test.ts
  • packages/config/src/features/catalogue/record.ts
  • packages/config/src/features/workers/extract-worker.test.ts
  • packages/config/src/features/workers/extract-worker.ts
  • packages/config/src/shapes.ts
  • packages/config/tsdown.config.ts
  • packages/plugin-babel/src/index.test.ts
  • packages/plugin-babel/src/index.ts
  • packages/plugin-unplugin/src/index.test.ts
  • packages/plugin-unplugin/src/index.ts
  • website/content/core-concepts/architecture.mdx
  • website/content/core-concepts/configuration.mdx
  • website/content/core-concepts/extraction.mdx
  • website/content/core-concepts/messages.mdx
  • website/content/getting-started/quickstart.mdx
  • website/content/integrations/babel.mdx
  • website/content/integrations/vite.mdx
  • website/content/reference/api/config.mdx
  • website/content/reference/cli.mdx

@k0d13
k0d13 merged commit 366cad1 into main Jul 19, 2026
10 checks passed
@k0d13
k0d13 deleted the kodie/extract-source-locale-only branch July 26, 2026 01:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

package: babel-plugin Related to babel-plugin-saykit package: config Related to @saykit/config and the CLI package: unplugin Related to unplugin-saykit tests Modifications, additions, or fixes related to testing website Updates to the documentation website

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Extraction should only write to source locale translations, not all locales

1 participant