docs-i18n 0.8.0 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/package.json +1 -1
  2. package/template/app/utils/content-loader.ts +4 -0
  3. package/template/app/utils/docs.server.ts +7 -0
  4. package/template/content/blog/en/announcing-query-v5.md +110 -0
  5. package/template/content/blog/en/hello-world.md +26 -0
  6. package/template/content/blog/en/i18n-best-practices.md +57 -0
  7. package/template/content/blog/en/react-query-vs-swr.md +100 -0
  8. package/template/content/blog/en/state-management-2024.md +143 -0
  9. package/template/content/blog/en/tanstack-router-1.0.md +121 -0
  10. package/template/content/blog/ja/announcing-query-v5.md +110 -0
  11. package/template/content/blog/ja/hello-world.md +26 -0
  12. package/template/content/blog/zh-hans/announcing-query-v5.md +93 -0
  13. package/template/content/blog/zh-hans/hello-world.md +26 -0
  14. package/template/content/docs-i18n/docs.config.json +25 -0
  15. package/template/content/docs-i18n/en/admin.md +143 -0
  16. package/template/content/docs-i18n/en/architecture.md +222 -0
  17. package/template/content/docs-i18n/en/cli.md +324 -0
  18. package/template/content/docs-i18n/en/configuration.md +331 -0
  19. package/template/content/docs-i18n/en/deployment.md +209 -0
  20. package/template/content/docs-i18n/en/getting-started.md +168 -0
  21. package/template/content/docs.config.json +25 -0
  22. package/template/content/en/admin.md +151 -0
  23. package/template/content/en/architecture.md +222 -0
  24. package/template/content/en/cli.md +269 -0
  25. package/template/content/en/configuration.md +331 -0
  26. package/template/content/en/deployment.md +209 -0
  27. package/template/content/en/getting-started.md +168 -0
  28. package/template/content/form/docs.config.json +18 -0
  29. package/template/content/form/en/guides/validation.md +175 -0
  30. package/template/content/form/en/installation.md +63 -0
  31. package/template/content/form/en/overview.md +71 -0
  32. package/template/content/form/en/quick-start.md +121 -0
  33. package/template/content/form/ja/installation.md +63 -0
  34. package/template/content/form/ja/overview.md +71 -0
  35. package/template/content/form/zh-hans/installation.md +63 -0
  36. package/template/content/form/zh-hans/overview.md +71 -0
  37. package/template/content/query/docs.config.json +32 -0
  38. package/template/content/query/en/guides/mutations.md +126 -0
  39. package/template/content/query/en/guides/pagination.md +98 -0
  40. package/template/content/query/en/guides/queries.md +120 -0
  41. package/template/content/query/en/installation.md +78 -0
  42. package/template/content/query/en/overview.md +72 -0
  43. package/template/content/query/en/quick-start.md +108 -0
  44. package/template/content/query/ja/installation.md +78 -0
  45. package/template/content/query/ja/overview.md +72 -0
  46. package/template/content/query/zh-hans/guides/mutations.md +126 -0
  47. package/template/content/query/zh-hans/guides/pagination.md +98 -0
  48. package/template/content/query/zh-hans/guides/queries.md +120 -0
  49. package/template/content/query/zh-hans/installation.md +95 -0
  50. package/template/content/query/zh-hans/overview.md +72 -0
  51. package/template/content/query/zh-hans/quick-start.md +108 -0
  52. package/template/content/router/docs.config.json +18 -0
  53. package/template/content/router/en/guides/routing-concepts.md +131 -0
  54. package/template/content/router/en/installation.md +57 -0
  55. package/template/content/router/en/overview.md +74 -0
  56. package/template/content/router/en/quick-start.md +88 -0
  57. package/template/content/router/ja/installation.md +57 -0
  58. package/template/content/router/ja/overview.md +78 -0
  59. package/template/content/router/zh-hans/guides/routing-concepts.md +131 -0
  60. package/template/content/router/zh-hans/installation.md +57 -0
  61. package/template/content/router/zh-hans/overview.md +81 -0
  62. package/template/content/router/zh-hans/quick-start.md +88 -0
  63. package/template/content/table/docs.config.json +18 -0
  64. package/template/content/table/en/guides/column-definitions.md +135 -0
  65. package/template/content/table/en/installation.md +56 -0
  66. package/template/content/table/en/overview.md +79 -0
  67. package/template/content/table/en/quick-start.md +112 -0
  68. package/template/content/table/ja/installation.md +56 -0
  69. package/template/content/table/ja/overview.md +79 -0
  70. package/template/content/table/zh-hans/installation.md +56 -0
  71. package/template/content/table/zh-hans/overview.md +79 -0
  72. package/template/content/virtual/docs.config.json +18 -0
  73. package/template/content/virtual/en/guides/dynamic-sizing.md +129 -0
  74. package/template/content/virtual/en/installation.md +57 -0
  75. package/template/content/virtual/en/overview.md +74 -0
  76. package/template/content/virtual/en/quick-start.md +114 -0
  77. package/template/content/virtual/ja/installation.md +57 -0
  78. package/template/content/virtual/ja/overview.md +74 -0
  79. package/template/content/virtual/zh-hans/installation.md +57 -0
  80. package/template/content/virtual/zh-hans/overview.md +74 -0
@@ -0,0 +1,209 @@
1
+ ---
2
+ title: Deployment
3
+ description: Using docs-i18n in CI/CD pipelines, deploying the admin dashboard, and runtime translation with Cloudflare D1.
4
+ ---
5
+
6
+ # Deployment
7
+
8
+ ## CI/CD with GitHub Actions
9
+
10
+ docs-i18n works well in CI/CD pipelines. Since translations are cached in SQLite, you only pay for API calls on new or changed content.
11
+
12
+ ### Basic translation workflow
13
+
14
+ ```yaml
15
+ name: Translate Docs
16
+ on:
17
+ push:
18
+ branches: [main]
19
+ paths:
20
+ - 'content/**'
21
+
22
+ jobs:
23
+ translate:
24
+ runs-on: ubuntu-latest
25
+ steps:
26
+ - uses: actions/checkout@v4
27
+
28
+ - uses: actions/setup-node@v4
29
+ with:
30
+ node-version: 20
31
+
32
+ - run: npm ci
33
+
34
+ # Restore the SQLite cache from a previous run
35
+ - uses: actions/cache@v4
36
+ with:
37
+ path: .cache
38
+ key: i18n-cache-${{ hashFiles('content/**') }}
39
+ restore-keys: |
40
+ i18n-cache-
41
+
42
+ # Rescan source files to detect changes
43
+ - run: npx docs-i18n rescan
44
+
45
+ # Translate all configured languages
46
+ - run: npx docs-i18n translate --lang zh-hans
47
+ env:
48
+ OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
49
+
50
+ - run: npx docs-i18n translate --lang ja
51
+ env:
52
+ OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
53
+
54
+ # Assemble output files
55
+ - run: npx docs-i18n assemble
56
+
57
+ # Commit translated files (or use them in a build step)
58
+ - uses: stefanzweifel/git-auto-commit-action@v5
59
+ with:
60
+ commit_message: 'chore: update translations'
61
+ file_pattern: '.cache/content/**'
62
+ ```
63
+
64
+ ### Tips for CI/CD
65
+
66
+ - **Cache the SQLite database.** The `.cache/translations.db` file contains all cached translations. Restoring it between runs avoids re-translating unchanged content. Use `actions/cache` with a key based on your content files.
67
+ - **Run `rescan` before `translate`.** This detects new, changed, and deleted source files, and cleans up orphaned translations.
68
+ - **Use `--dry-run` in PR checks.** Add a CI step that runs `docs-i18n translate --lang zh-hans --dry-run` to report how many nodes need translation without spending API credits.
69
+ - **Limit concurrency.** In CI, you may want `--concurrency 1` to avoid rate limiting from your LLM provider.
70
+ - **Set `--max` for budgeting.** Use `--max 10` to cap the number of API calls per run if you want to translate incrementally across multiple CI runs.
71
+
72
+ ### PR status check
73
+
74
+ ```yaml
75
+ name: Translation Status
76
+ on:
77
+ pull_request:
78
+ paths:
79
+ - 'content/**'
80
+
81
+ jobs:
82
+ check:
83
+ runs-on: ubuntu-latest
84
+ steps:
85
+ - uses: actions/checkout@v4
86
+ - uses: actions/setup-node@v4
87
+ with:
88
+ node-version: 20
89
+ - run: npm ci
90
+
91
+ - uses: actions/cache@v4
92
+ with:
93
+ path: .cache
94
+ key: i18n-cache-${{ hashFiles('content/**') }}
95
+ restore-keys: |
96
+ i18n-cache-
97
+
98
+ - run: npx docs-i18n rescan
99
+ - run: npx docs-i18n status
100
+ - run: npx docs-i18n translate --lang zh-hans --dry-run
101
+ ```
102
+
103
+ ## Admin Dashboard Deployment
104
+
105
+ The admin dashboard is a TanStack Start application that runs locally. It is designed for development use, not production deployment.
106
+
107
+ To start it:
108
+
109
+ ```bash
110
+ npx docs-i18n admin
111
+ # or
112
+ npx docs-i18n admin --port 4000
113
+ ```
114
+
115
+ The dashboard starts a Vite dev server pointed at the `src/admin` directory within the docs-i18n package. It reads your `docs-i18n.config.ts` to discover projects, versions, and languages.
116
+
117
+ **Prerequisites:**
118
+
119
+ Your project must have `vite` and `@vitejs/plugin-react` installed as dev dependencies:
120
+
121
+ ```bash
122
+ npm install -D vite @vitejs/plugin-react
123
+ ```
124
+
125
+ ## Runtime Translation with D1
126
+
127
+ For SSR sites that fetch markdown at runtime (e.g., TanStack Start on Cloudflare Workers), docs-i18n provides a lightweight runtime translator that queries Cloudflare D1 for cached translations.
128
+
129
+ ### How it works
130
+
131
+ The `createTranslator` function from `docs-i18n/serve` creates a translator instance. When `translate()` is called:
132
+
133
+ 1. The markdown is parsed into AST nodes using the same parser as the CLI.
134
+ 2. Translatable nodes' MD5 keys are collected.
135
+ 3. A batch query is sent to D1 to look up all translations for the given language.
136
+ 4. The content is reassembled: translated nodes use the D1 cache value, untranslated nodes fall back to the original English text.
137
+
138
+ ### Setup
139
+
140
+ #### 1. Export translations to D1
141
+
142
+ First, translate your content using the CLI as normal. Then export the SQLite cache to D1. You can use Wrangler to create a D1 database and import the translations:
143
+
144
+ ```bash
145
+ # Create a D1 database
146
+ wrangler d1 create docs-translations
147
+
148
+ # Export the translations table from your local SQLite
149
+ sqlite3 .cache/translations.db ".dump translations" > translations.sql
150
+
151
+ # Import into D1
152
+ wrangler d1 execute docs-translations --file=translations.sql
153
+ ```
154
+
155
+ Make sure the D1 database has the same `translations` table schema:
156
+
157
+ ```sql
158
+ CREATE TABLE IF NOT EXISTS translations (
159
+ lang TEXT NOT NULL,
160
+ key TEXT NOT NULL,
161
+ value TEXT NOT NULL,
162
+ created_at INTEGER NOT NULL DEFAULT (unixepoch()),
163
+ updated_at INTEGER NOT NULL DEFAULT (unixepoch()),
164
+ PRIMARY KEY (lang, key)
165
+ );
166
+ ```
167
+
168
+ #### 2. Use the translator in your Worker
169
+
170
+ ```ts
171
+ import { createTranslator } from 'docs-i18n/serve';
172
+
173
+ const translator = createTranslator();
174
+
175
+ // In your request handler (e.g., TanStack Start server function):
176
+ export async function getTranslatedDoc(
177
+ repo: string,
178
+ branch: string,
179
+ filePath: string,
180
+ lang: string,
181
+ env: { DB: D1Database },
182
+ ) {
183
+ // Fetch the English markdown from GitHub
184
+ const enMarkdown = await fetchFromGitHub(repo, branch, filePath);
185
+
186
+ // If the requested language is English, return as-is
187
+ if (lang === 'en') return enMarkdown;
188
+
189
+ // Translate using D1 cache
190
+ const translated = await translator.translate(enMarkdown, lang, env.DB);
191
+ return translated;
192
+ }
193
+ ```
194
+
195
+ #### 3. Bind D1 in wrangler.toml
196
+
197
+ ```toml
198
+ [[d1_databases]]
199
+ binding = "DB"
200
+ database_name = "docs-translations"
201
+ database_id = "your-database-id"
202
+ ```
203
+
204
+ ### Performance considerations
205
+
206
+ - The translator uses a single batch query to D1, so latency scales with the number of translatable nodes (typically under 50ms for a standard documentation page).
207
+ - English content (`lang === 'en'`) short-circuits immediately without parsing or querying.
208
+ - The parser runs on every request since the English source is fetched at runtime. For heavy traffic, consider caching the translated output at the edge.
209
+ - Untranslated nodes gracefully fall back to English, so partial translations work without errors.
@@ -0,0 +1,168 @@
1
+ ---
2
+ title: Getting Started
3
+ description: Install docs-i18n and translate your first documentation file in minutes.
4
+ ---
5
+
6
+ # Getting Started
7
+
8
+ ## What is docs-i18n?
9
+
10
+ docs-i18n is a universal documentation translation engine. It parses markdown and MDX files into translatable AST nodes, translates them via LLM, caches results in SQLite, and assembles translated output files. It is framework-agnostic and works with any documentation site built on Next.js, Astro, TanStack Start, or similar tools.
11
+
12
+ Key characteristics:
13
+
14
+ - **Incremental** -- only changed or new content is sent to the LLM.
15
+ - **AST-based** -- uses remark to parse markdown into nodes, producing stable MD5 keys for deduplication.
16
+ - **SQLite-backed** -- concurrent-safe cache with WAL mode. No manual save steps.
17
+ - **Multi-project** -- supports multiple documentation projects and versions in a single config.
18
+ - **Admin dashboard** -- web UI for monitoring progress, managing jobs, and previewing translations.
19
+ - **Runtime serve** -- optional D1-compatible translator for SSR sites on Cloudflare Workers.
20
+
21
+ ## Requirements
22
+
23
+ - Node.js 20+ or Bun
24
+ - An API key for an LLM provider (OpenRouter, OpenAI, or Anthropic)
25
+ - For the admin dashboard: `vite` and `@vitejs/plugin-react` as dev dependencies
26
+
27
+ ## Installation
28
+
29
+ ```bash
30
+ npm install docs-i18n
31
+ ```
32
+
33
+ Or with Bun:
34
+
35
+ ```bash
36
+ bun add docs-i18n
37
+ ```
38
+
39
+ ## Quick Start
40
+
41
+ ### 1. Create a configuration file
42
+
43
+ Create `docs-i18n.config.ts` in your project root:
44
+
45
+ ```ts
46
+ import { defineConfig } from 'docs-i18n';
47
+
48
+ export default defineConfig({
49
+ projects: {
50
+ mydocs: {
51
+ sources: {
52
+ latest: 'content/docs',
53
+ },
54
+ },
55
+ },
56
+ languages: ['zh-hans', 'ja', 'es'],
57
+ llm: {
58
+ provider: 'openrouter',
59
+ model: 'deepseek/deepseek-chat-v3-0324:free',
60
+ apiKey: process.env.OPENROUTER_API_KEY,
61
+ },
62
+ });
63
+ ```
64
+
65
+ The `projects` object maps project names to their source directories. Each project can have multiple versions (e.g., `latest`, `v1`, `v2`). The `languages` array lists the target language codes to translate into.
66
+
67
+ ### 2. Scan your source files
68
+
69
+ Before translating, scan your English source files to build the source index:
70
+
71
+ ```bash
72
+ npx docs-i18n rescan
73
+ ```
74
+
75
+ This parses every markdown/MDX file in your source directories, extracts translatable nodes, and stores them in the SQLite cache.
76
+
77
+ ### 3. Check translation status
78
+
79
+ ```bash
80
+ npx docs-i18n status
81
+ ```
82
+
83
+ This displays a progress bar for each language showing how many nodes have been translated.
84
+
85
+ ### 4. Run your first translation
86
+
87
+ ```bash
88
+ npx docs-i18n translate --lang zh-hans
89
+ ```
90
+
91
+ This sends untranslated nodes to your configured LLM, receives translations, and stores them in the cache. Only new or changed content is translated -- cached translations are reused.
92
+
93
+ ### 5. Assemble output files
94
+
95
+ ```bash
96
+ npx docs-i18n assemble
97
+ ```
98
+
99
+ This produces translated markdown files by combining your English sources with cached translations. Output is written to `.cache/content/<version>/<lang>/` by default.
100
+
101
+ ## Minimal Working Example
102
+
103
+ Given this project structure:
104
+
105
+ ```
106
+ my-docs/
107
+ content/
108
+ docs/
109
+ getting-started.md
110
+ api-reference.md
111
+ docs-i18n.config.ts
112
+ package.json
113
+ ```
114
+
115
+ With this config:
116
+
117
+ ```ts
118
+ import { defineConfig } from 'docs-i18n';
119
+
120
+ export default defineConfig({
121
+ projects: {
122
+ docs: {
123
+ sources: { latest: 'content/docs' },
124
+ },
125
+ },
126
+ languages: ['zh-hans'],
127
+ llm: {
128
+ provider: 'openrouter',
129
+ apiKey: process.env.OPENROUTER_API_KEY,
130
+ model: 'deepseek/deepseek-chat-v3-0324:free',
131
+ contextLength: 32768,
132
+ maxTokens: 16384,
133
+ },
134
+ context: 'MyProject is a TypeScript library for building web apps.',
135
+ });
136
+ ```
137
+
138
+ Run these commands:
139
+
140
+ ```bash
141
+ npx docs-i18n rescan
142
+ npx docs-i18n translate --lang zh-hans
143
+ npx docs-i18n assemble --lang zh-hans
144
+ ```
145
+
146
+ The translated files will appear at:
147
+
148
+ ```
149
+ .cache/content/latest/zh-hans/getting-started.md
150
+ .cache/content/latest/zh-hans/api-reference.md
151
+ ```
152
+
153
+ ## Adding npm scripts
154
+
155
+ Add these convenience scripts to your `package.json`:
156
+
157
+ ```json
158
+ {
159
+ "scripts": {
160
+ "i18n": "docs-i18n",
161
+ "i18n:status": "docs-i18n status",
162
+ "i18n:translate": "docs-i18n translate",
163
+ "i18n:assemble": "docs-i18n assemble",
164
+ "i18n:rescan": "docs-i18n rescan",
165
+ "i18n:admin": "docs-i18n admin"
166
+ }
167
+ }
168
+ ```
@@ -0,0 +1,25 @@
1
+ {
2
+ "sections": [
3
+ {
4
+ "label": "Getting Started",
5
+ "children": [
6
+ { "label": "Introduction", "to": "getting-started" }
7
+ ]
8
+ },
9
+ {
10
+ "label": "Usage",
11
+ "children": [
12
+ { "label": "CLI Commands", "to": "cli" },
13
+ { "label": "Configuration", "to": "configuration" },
14
+ { "label": "Admin Dashboard", "to": "admin" }
15
+ ]
16
+ },
17
+ {
18
+ "label": "Advanced",
19
+ "children": [
20
+ { "label": "Architecture", "to": "architecture" },
21
+ { "label": "Deployment", "to": "deployment" }
22
+ ]
23
+ }
24
+ ]
25
+ }
@@ -0,0 +1,151 @@
1
+ ---
2
+ title: Admin Dashboard
3
+ description: Web UI for monitoring translation progress, managing translation jobs, previewing files, and browsing LLM models.
4
+ ---
5
+
6
+ # Admin Dashboard
7
+
8
+ The docs-i18n admin dashboard is a web-based UI for managing your translations. It is built with TanStack Start and React, and runs as a local development server.
9
+
10
+ ## Starting the Dashboard
11
+
12
+ ```bash
13
+ npx docs-i18n admin
14
+ ```
15
+
16
+ The dashboard opens at `http://localhost:3456`. Use `--port` to change the port:
17
+
18
+ ```bash
19
+ npx docs-i18n admin --port 4000
20
+ ```
21
+
22
+ **Prerequisites:**
23
+
24
+ Your project must have `vite` and `@vitejs/plugin-react` installed:
25
+
26
+ ```bash
27
+ npm install -D vite @vitejs/plugin-react
28
+ ```
29
+
30
+ The dashboard reads your `docs-i18n.config.ts` to discover projects, versions, and languages.
31
+
32
+ ## Features
33
+
34
+ ### Translation Overview
35
+
36
+ The main dashboard page shows a grid of all versions and languages with translation progress. For each version/language pair, you see:
37
+
38
+ - Total number of source nodes (EN content units).
39
+ - Number of translated nodes.
40
+ - Percentage complete.
41
+ - Breakdown by section (e.g., `docs/`, `blog/`, `learn/`), showing file counts and node counts per section.
42
+
43
+ English is always shown as 100% complete since it is the source language.
44
+
45
+ The overview auto-scans source files on load. If source files have not been scanned yet, the dashboard triggers a scan automatically.
46
+
47
+ ### File Browser
48
+
49
+ Clicking on a version/language cell opens a file-level coverage list. Each file shows:
50
+
51
+ - File path (relative to the source directory).
52
+ - Total translatable nodes in that file.
53
+ - Number of translated nodes.
54
+
55
+ Files are sorted by path. You can click on any file to open the block-level preview.
56
+
57
+ ### File Preview
58
+
59
+ The file preview shows every block (AST node) in a file side by side:
60
+
61
+ - **Source** -- the original English text.
62
+ - **Translation** -- the cached translation for the selected language, or empty if not yet translated.
63
+
64
+ Each block displays its type (heading, paragraph, list, blockquote, frontmatter, code, html) and MD5 key. Non-translatable blocks (code, pure HTML tags, gaps between nodes) are shown but clearly distinguished.
65
+
66
+ ### Cache Management
67
+
68
+ From the file preview, you can delete individual cache entries. This is useful when a translation is incorrect and you want to re-translate a specific node. After deleting, run the translate command again to get a fresh translation for that key.
69
+
70
+ The dashboard also supports rescanning source files for a specific version via the UI. This rebuilds the source index and cleans orphaned entries.
71
+
72
+ ### Translation Jobs
73
+
74
+ The dashboard includes a job management system for running translations directly from the UI instead of the command line.
75
+
76
+ #### Creating a Job
77
+
78
+ Click the job creation button and configure:
79
+
80
+ - **Language** -- target language code.
81
+ - **Version** -- which version to translate.
82
+ - **Project** -- optionally filter to a specific project.
83
+ - **Model** -- LLM model to use (can be selected from the model browser).
84
+ - **Model rotation** -- optionally provide multiple models to rotate through.
85
+ - **Max chunks** -- limit the number of API call chunks.
86
+ - **Concurrency** -- number of parallel API calls (default: 3).
87
+ - **Files** -- optionally select specific files to translate.
88
+
89
+ #### Job Status
90
+
91
+ Running jobs show:
92
+
93
+ - Status: `running`, `completed`, `failed`, or `cancelled`.
94
+ - Start time and finish time.
95
+ - Number of translated chunks and total chunks.
96
+ - Current chunk being processed.
97
+ - Live log output (last 20 lines displayed, up to 500 lines stored).
98
+
99
+ You can cancel a running job, which sends SIGTERM to the translation process. Completed or failed jobs can be removed from the list.
100
+
101
+ #### How Jobs Work
102
+
103
+ Under the hood, the job manager spawns a child process running the `docs-i18n translate` CLI command with the configured options. It captures stdout and stderr, parses progress information from the output, and exposes it through the dashboard API. The child process inherits the API key from your config or environment variables.
104
+
105
+ ### Model Browser
106
+
107
+ The dashboard includes an OpenRouter model browser that fetches the list of available models from the OpenRouter API. For each model, it displays:
108
+
109
+ - Model ID and name.
110
+ - Pricing (prompt and completion per million tokens).
111
+ - Context length and maximum output tokens.
112
+ - Whether the model supports JSON response format and tool use.
113
+ - Provider name.
114
+ - Whether the model is free.
115
+
116
+ The model list is cached for 5 minutes. It only shows text-to-text models (filtered by architecture modality) and excludes models with negative pricing. Models are sorted by prompt price (cheapest first).
117
+
118
+ This is useful for selecting a model when creating a translation job.
119
+
120
+ ### Open in Editor
121
+
122
+ The dashboard can open source files in your local editor. It tries the following editors in order:
123
+
124
+ 1. The value of the `EDITOR_CMD` environment variable (if set).
125
+ 2. `code` (VS Code)
126
+ 3. `cursor` (Cursor)
127
+ 4. `zed` (Zed)
128
+
129
+ If none are found, it falls back to the system default (`open` on macOS, `xdg-open` on Linux, `start` on Windows).
130
+
131
+ ## Architecture
132
+
133
+ The admin dashboard uses:
134
+
135
+ - **TanStack Start** -- Full-stack React framework with server functions.
136
+ - **TanStack React Query** -- For data fetching and cache management.
137
+ - **TanStack Router** -- For client-side routing.
138
+ - **Vite** -- Dev server and build tool.
139
+ - **Hono** -- HTTP server (used by TanStack Start internally).
140
+
141
+ Server functions are defined in `src/admin/server/functions/` and handle:
142
+
143
+ - `fetchStatus` / `fetchFileCoverage` / `fetchFileBlocks` -- Read translation status from SQLite.
144
+ - `deleteCacheEntry` -- Delete a specific translation from the cache.
145
+ - `rescanVersion` -- Rescan source files for a version.
146
+ - `createJob` / `fetchJobs` / `fetchJob` / `deleteJob` -- Manage translation jobs.
147
+ - `fetchModels` -- Fetch available models from OpenRouter.
148
+ - `fetchVersion` / `fetchConfig` -- Get docs-i18n version and project root.
149
+ - `openFile` -- Open a file in the local editor.
150
+
151
+ The dashboard shares the same `TranslationCache` and `parseMdx` functions as the CLI, ensuring consistent behavior.