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:
- Reads translation namespaces directly from GitHub (via the Git Trees API)
- Displays a side-by-side editor for all locales in a namespace
- Saves changes by creating a branch, committing patched JSON files, and opening a pull request
- 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
| Layer | Location | Responsibility |
|---|---|---|
| Pages | src/app/(protected)/translations/ + src/app/api/translations/ | Next.js App Router pages and API routes |
| Components | src/components/translations/ | Namespace list, namespace editor, review board |
| Lib | src/lib/translations/ | Server-only business logic (GitHub, config, caching) |
| Editor package | @workspace/translations-editor | Shared 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/blobsto fetch locale JSON files - Write:
POST /git/blobs→POST /git/trees→POST /git/commits→POST /git/refs→POST /pullsto 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:
| Tag | Scope |
|---|---|
translations:all | All translation data |
translations:catalog | Namespace list and stats |
translations:namespace:<name> | Single namespace document |
translations:reviews | Open 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
| Route | Description |
|---|---|
/translations | Redirect to /translations/namespaces |
/translations/namespaces | List all translation namespaces with completion stats |
/translations/namespaces/[namespace] | Side-by-side editor for a single namespace |
/translations/reviews | Board of open translation pull requests |
/sign-in | Clerk sign-in page (Admin app) |
/unauthorized | Access denied (account role below translator) |
API routes
| Method | Route | Description |
|---|---|---|
GET | /api/translations/catalog | Full catalog with namespace stats |
GET | /api/translations/namespace/[namespace] | Namespace document (all locales) |
POST | /api/translations/save | Save draft → create branch + PR |
GET | /api/translations/reviews/[pullRequestNumber]/comments | List PR comments |
Deployment
The tool ships with the Admin app (apps/admin), which is not deployed.
Related packages
@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