Skip to content

fix(intl-pipeline): manifest paths, LLM adapter, P1 follow-ups#17982

Merged
wackerow merged 9 commits into
devfrom
intl-pipeline-v6
Apr 17, 2026
Merged

fix(intl-pipeline): manifest paths, LLM adapter, P1 follow-ups#17982
wackerow merged 9 commits into
devfrom
intl-pipeline-v6

Conversation

@myelinated-wackerow
Copy link
Copy Markdown
Collaborator

Summary

Follow-up to #17963. Fixes manifest path collisions for multiple JSON namespaces, introduces LLM adapter abstraction, reorganizes test fixtures, and addresses remaining P1 review findings.

Manifest paths:

  • Manifests moved from inline with content to dedicated .manifests/ directory
  • Structure: .manifests/{dest-file-path}/source.json | translation.json
  • Each file gets its own manifest pair -- fixes collision where multiple JSON namespaces shared one manifest
  • MANIFESTS_DIR constant in constants.ts, excluded from Next.js bundle via outputFileTracingExcludes

LLM adapter abstraction:

  • LlmAdapter interface in lib/llm/adapters.ts (models, name, coAuthor, isAvailable)
  • Active adapter selected in constants.ts -- swap LLM providers by changing one line
  • Commit messages: i18n(lang): LLM translation with Co-Authored-By from adapter
  • Removed all hardcoded Gemini references from main.ts and config.ts

P1 follow-up fixes (from #17963 (review)):

  • Validate TARGET_PATH before any filesystem reads (path traversal)
  • Wire AbortController signal to Gemini SDK calls (timeout was no-op)
  • stamp-only tasks now trigger squash/merge/PR (were silently skipped)
  • Sanitize all glossary fields against prompt injection (not just note)

Test fixtures:

  • Renamed for multi-file support: fixture-a -> fixture-1, english/ -> english-a/+english-b/
  • Added fixture-2.json (second JSON namespace, no drift between A and B)
  • 4 new tests: no-drift detection + manifest path isolation
  • Workflow input description updated for dynamic default target branch

Test plan

  • 811 local unit tests passing
  • E2E validated via GH Action: test-manual-14 series (MD + 2 JSON files, Korean)
  • Manifests land at .manifests/ paths with separate files per JSON namespace
  • No-drift JSON correctly detected and skipped
  • stamp-only mode (not tested via GH Action yet)

Generated with Claude Code

myelinated-wackerow and others added 7 commits April 16, 2026 10:07
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
Move manifests from inline with content to dedicated
.manifests/ directory. Structure:
.manifests/{dest-path}/source.json | translation.json

Fixes multi-JSON-namespace collision where one shared
manifest per locale dir lost data. Each file now gets
its own manifest pair. MANIFESTS_DIR in constants.ts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
Rename english/ to english-a/ and english-b/.
Rename fixture-a/b to fixture-1 across all dirs.
Prepares for fixture-2 (second JSON namespace).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
Second JSON namespace (4 keys, no mutations between
english-a and english-b). Tests no-drift detection
and manifest path isolation for multiple JSON files.
811 tests passing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
getManifestPath returns relative path (no process.cwd).
Absolute path used only for local fs reads. GitHub
tree API rejects paths starting with /.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
Define LlmAdapter interface in lib/llm/adapters.ts
with models, name, coAuthor, isAvailable. Active
adapter selected in constants.ts. Removes hardcoded
Gemini references from main.ts, config.ts, commits.
Commit messages: i18n(lang): LLM translation with
Co-Authored-By from adapter.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
- Validate TARGET_PATH before filesystem reads
- Wire AbortController signal to Gemini SDK call
- stamp-only tasks now trigger squash/merge/PR
- Sanitize all glossary fields (english, translation,
  note) against prompt injection

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 16, 2026

Deploy Preview for ethereumorg ready!

Name Link
🔨 Latest commit a45362c
🔍 Latest deploy log https://app.netlify.com/projects/ethereumorg/deploys/69e2c67f4918520008e56309
😎 Deploy Preview https://deploy-preview-17982.ethereum.it
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
7 paths audited
Performance: 54 (🔴 down 5 from production)
Accessibility: 94 (no change from production)
Best Practices: 100 (no change from production)
SEO: 98 (🔴 down 1 from production)
PWA: 59 (no change from production)
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions github-actions Bot added config ⚙️ Changes to configuration files tooling 🔧 Changes related to tooling of the project labels Apr 16, 2026
Copy link
Copy Markdown
Member

@pettinarip pettinarip left a comment

Choose a reason for hiding this comment

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

test("manifest paths are distinct for different JSON files in same locale", () => {
// Import the helper indirectly by testing the path pattern
const path1 = `.manifests/src/intl/ko/fixture-1.json/source.json`
const path2 = `.manifests/src/intl/ko/fixture-2.json/source.json`
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this test is always true. Probably we want to load the content?

myelinated-wackerow and others added 2 commits April 17, 2026 16:09
<span dir="ltr"> tags embedded in JSON values break next-intl's
t() function: the tags render literally on screen because ICU
MessageFormat treats them as rich markup that only t.rich()
understands. JSON values must use plain-text BiDi isolation.

Changes:
- Per-file-type RTL prompt rules in getSiteSpecificNotes():
  markdown keeps <span dir="ltr"> convention, JSON uses raw
  Unicode U+2066 (LRI) / U+2069 (PDI) with explicit anti-span
  directive.
- Thread fileType through buildIncrementalPrompt so incremental
  JSON translations get the JSON rule (main.ts caller updated).
- New sanitizer convertSpansToJsonBidi() safety net in
  processJsonFile: catches legacy spans (raw, JSON-escaped, or
  single-quoted dir attribute) and converts to raw bidi chars.
- Move "state" polysemy rule from RTL-only section to common
  site notes (affects 8+ non-Latin locales, not just ar/ur).

Tests: 10 new (7 sanitizer + 3 prompt), 841/841 passing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
Co-Authored-By: wackerow <54227730+wackerow@users.noreply.github.com>
@wackerow wackerow merged commit c1cbf66 into dev Apr 17, 2026
8 of 9 checks passed
@wackerow wackerow deleted the intl-pipeline-v6 branch April 17, 2026 23:47
@wackerow wackerow mentioned this pull request Apr 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

config ⚙️ Changes to configuration files tooling 🔧 Changes related to tooling of the project

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants