Skip to content

feat: make orphan key handling configurable#75

Merged
Starllordz merged 1 commit into
mainfrom
feat/orphan-deletion-setting
Jul 21, 2026
Merged

feat: make orphan key handling configurable#75
Starllordz merged 1 commit into
mainfrom
feat/orphan-deletion-setting

Conversation

@Starllordz

Copy link
Copy Markdown
Collaborator

Orphan keys — keys that exist in a target locale file but not in the source — have been preserved unconditionally since 1.5.0. Some projects want the target to mirror the source exactly and treat leftovers as noise, so this makes the behaviour configurable without changing the default.

Configuration

translation:
  batchSize: 50
  orphanKeys: keep    # keep (default) | delete

Plus a per-run override:

lara-cli translate --orphan-keys delete

The flag takes precedence over the config file in both directions, so an explicit --orphan-keys keep wins over a config set to delete. It is rejected with --file/--text, which bypass the translation engine entirely, matching how --force and --paths are already handled.

Implementation

The engine turned out to be the single lever — no parser needed modification. weaveOrphans in classifyEntries is the only place orphan preservation is introduced, and every merge-based parser already derives its own graft filter from the engine's emitted data:

  • xcode-strings and xcode-stringsdict filter on kept = dataKeys / dataEntryKeys
  • xcode-xcstrings prunes target localizations absent from data
  • json, ts, vue, po are data-driven throughout

So shrinking data shrinks the graft automatically. The diff touches zero parser files.

Behaviour that does not change

  • Keys deleted from the source are removed in both modes. They appear in the changelog with state deleted, so they are not orphans.
  • Non-translatable entries are never deleted, even with delete. Android translatable="false" resources and .xcstrings shouldTranslate: false entries are skipped by parse(), so they never reach the engine — they are invisible-to-the-engine entries, not orphans. Deleting them would be data loss.

Testing

Integration coverage for all 8 keyed formats in both modes, sharing one fixture seed per format so the two halves cannot drift. Plus the Android carve-out, the schema default when the translation section is absent, CLI/config precedence in both directions, and that source-deleted keys disappear in both modes. Schema-level tests cover parsing, the default, and rejection of invalid values.

Verified the tests actually bite: disabling the engine guard fails 9 of them.

849 tests pass; build, lint and format checks are clean.

Version

Minor bump to 1.6.0 — backward-compatible addition, default behaviour unchanged.

## Changed
- Orphan keys (present in a target file, absent from the source) are still preserved by default, so existing projects are unaffected
- `lara init` now writes `translation.orphanKeys` explicitly in the generated config

## New
- `translation.orphanKeys: keep | delete` in lara.yaml, controlling whether target-only keys survive a translation run
- `lara-cli translate --orphan-keys <keep|delete>` overrides the config for a single run; rejected with `--file`/`--text`, which bypass the engine
- Source-deleted keys are still removed in both modes, and non-translatable entries (Android `translatable="false"`, `.xcstrings` `shouldTranslate: false`) are never deleted
- Docs for both the setting and the flag, plus integration coverage for every keyed format, the Android carve-out, and CLI/config precedence in both directions
Copilot AI review requested due to automatic review settings July 20, 2026 14:54

@claude claude Bot left a comment

Copy link
Copy Markdown

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 for a one-time review, or @claude review always to subscribe this PR to a review on every future push.

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

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR makes orphan key handling configurable in the translation engine and CLI, allowing projects to either preserve target-only keys (default) or delete them so targets mirror the source exactly.

Changes:

  • Add translation.orphanKeys to the config schema with modes keep (default) and delete, plus a --orphan-keys CLI override with correct precedence.
  • Update the translation engine’s orphan weaving to short-circuit when orphanKeys: delete, letting existing merge-based parsers naturally prune target-only entries.
  • Add/expand integration and schema tests and update documentation/versioning to reflect the new feature.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/modules/translation/translation.engine.ts Adds orphanKeys option and skips orphan weaving when mode is delete.
src/modules/config/config.types.ts Introduces orphan key modes/defaults and extends Zod schema with translation.orphanKeys.
src/messages/messages.ts Adds error message for invalid flag usage with direct translation modes.
src/cli/cmd/translate/translate.ts Adds --orphan-keys option, enforces incompatibility with --file/--text, and passes resolved mode into the engine.
src/cli/cmd/init/init.ts Ensures generated config explicitly includes the new translation.orphanKeys field.
src/tests/utils/config-orphan-keys.test.ts Adds schema-level tests for parsing/defaults/invalid values of translation.orphanKeys.
src/tests/integration/orphan-keys.integration.test.ts Adds end-to-end coverage for keep vs delete behavior across keyed formats and CLI/config precedence.
src/tests/integration/direct-translate.integration.test.ts Verifies --orphan-keys is rejected with direct translation (--text).
README.md Updates version badge to 1.6.0.
package.json Bumps package version to 1.6.0.
docs/config/structure.md Documents the new orphan key configuration and behavior nuances.
docs/config/README.md Updates config example and links to orphan key docs.
docs/commands/translate.md Documents --orphan-keys and clarifies orphan key behavior/options.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@Starllordz
Starllordz merged commit 7486f66 into main Jul 21, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants