Bridge Training

Overview

Translation management tool architecture and workflows.

What it does

The translations tool (the Translations section of the Admin app, apps/admin) is an internal tool for editing i18n JSON files stored in the monorepo. Instead of editing files by hand and opening PRs, translators use a browser-based editor that:

  1. Reads translation namespaces directly from GitHub (via the Git Trees API)
  2. Displays a side-by-side editor for all locales in a namespace
  3. Saves changes by creating a branch, committing patched JSON files, and opening a pull request
  4. Provides a review board to track open translation PRs and add comments

Architecture

┌─────────────┐     ┌──────────────┐     ┌────────────┐
│   Browser    │────▶│  Next.js App │────▶│ GitHub API │
│  (Editor UI) │◀────│  (Server)    │◀────│ (Git Data) │
└─────────────┘     └──────────────┘     └────────────┘
                           │
                     ┌─────┴──────┐
                     │   Clerk    │
                     │   (Auth)   │
                     └────────────┘

Key layers

LayerLocationResponsibility
Pagessrc/app/(protected)/translations/ + src/app/api/translations/Next.js App Router pages and API routes
Componentssrc/components/translations/Namespace list, namespace editor, review board
Libsrc/lib/translations/Server-only business logic (GitHub, config, caching)
Editor package@workspace/translations-editorShared types, document builder, branching helpers

GitHub integration

The app authenticates as a GitHub App installation (not a personal token). It uses the low-level Git Data API to avoid cloning the repository:

  • Read: GET /git/ref → GET /git/commits → GET /git/trees?recursive=1 → GET /git/blobs to fetch locale JSON files
  • Write: POST /git/blobs → POST /git/trees → POST /git/commits → POST /git/refs → POST /pulls to create a branch + commit + PR

Installation tokens are cached in memory with an expiry buffer.

Caching

Server-side data is cached with unstable_cache (Next.js) and revalidated every 30 seconds. Cache tags allow targeted invalidation:

TagScope
translations:allAll translation data
translations:catalogNamespace list and stats
translations:namespace:<name>Single namespace document
translations:reviewsOpen pull requests

JSON patching

When saving, the app does not overwrite entire JSON files. It applies surgical edits using jsonc-parser (modify + applyEdits), preserving existing formatting, key order, and comments. Only changed keys are touched.

Routes

Pages

RouteDescription
/translationsRedirect to /translations/namespaces
/translations/namespacesList all translation namespaces with completion stats
/translations/namespaces/[namespace]Side-by-side editor for a single namespace
/translations/reviewsBoard of open translation pull requests
/sign-inClerk sign-in page (Admin app)
/unauthorizedAccess denied (account role below translator)

API routes

MethodRouteDescription
GET/api/translations/catalogFull catalog with namespace stats
GET/api/translations/namespace/[namespace]Namespace document (all locales)
POST/api/translations/saveSave draft → create branch + PR
GET/api/translations/reviews/[pullRequestNumber]/commentsList PR comments

Deployment

The tool ships with the Admin app (apps/admin), which is not deployed.

  • @workspace/translations-editor — shared types (TranslationNamespaceDocument, TranslationDraftPayload), document builder, and branching/PR message helpers
  • @workspace/auth — Clerk integration
  • @workspace/i18n-messages — translation JSON files, the files being edited (packages/i18n-messages/src/locales)
  • @workspace/ui — shared UI components