i18n-dashboard 0.1.0

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 (176) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +715 -0
  3. package/app.vue +8 -0
  4. package/assets/css/main.css +21 -0
  5. package/assets/locales/en.json +380 -0
  6. package/bin/cli.mjs +279 -0
  7. package/components/LinkedKeyPicker.vue +135 -0
  8. package/components/PathPicker.vue +153 -0
  9. package/components/PluralEditor.vue +295 -0
  10. package/components/ScanModal.vue +153 -0
  11. package/components/TranslationHistoryModal.vue +66 -0
  12. package/components/TranslationRow.vue +541 -0
  13. package/components/dashboard/WidgetConfigModal.vue +121 -0
  14. package/components/dashboard/WidgetGrid.vue +190 -0
  15. package/components/dashboard/WidgetPicker.vue +75 -0
  16. package/components/dashboard/widgets/ActivityWidget.vue +109 -0
  17. package/components/dashboard/widgets/LanguagesCoverageWidget.vue +104 -0
  18. package/components/dashboard/widgets/ProjectsWidget.vue +77 -0
  19. package/components/dashboard/widgets/ReviewWidget.vue +150 -0
  20. package/components/dashboard/widgets/StatWidget.vue +133 -0
  21. package/composables/useAuth.ts +72 -0
  22. package/composables/useConfig.ts +14 -0
  23. package/composables/useDashboard.ts +89 -0
  24. package/composables/useFormats.ts +100 -0
  25. package/composables/useKeys.ts +231 -0
  26. package/composables/useLanguages.ts +221 -0
  27. package/composables/useProfile.ts +76 -0
  28. package/composables/useProject.ts +180 -0
  29. package/composables/useReview.ts +94 -0
  30. package/composables/useSettings.ts +30 -0
  31. package/composables/useStats.ts +16 -0
  32. package/composables/useT.ts +38 -0
  33. package/composables/useUsers.ts +101 -0
  34. package/composables/useWidgetData.ts +50 -0
  35. package/consts/commons.const.ts +6 -0
  36. package/consts/dashboard.const.ts +94 -0
  37. package/consts/languages.const.ts +223 -0
  38. package/enums/commons.enum.ts +7 -0
  39. package/i18n-dashboard.config.example.js +40 -0
  40. package/interfaces/commons.interface.ts +23 -0
  41. package/interfaces/job.interface.ts +10 -0
  42. package/interfaces/key.interface.ts +39 -0
  43. package/interfaces/languages.interface.ts +23 -0
  44. package/interfaces/project.interface.ts +9 -0
  45. package/interfaces/scan.interface.ts +12 -0
  46. package/interfaces/settings.interface.ts +4 -0
  47. package/interfaces/stat.interface.ts +30 -0
  48. package/interfaces/translation.interface.ts +11 -0
  49. package/interfaces/user.interface.ts +24 -0
  50. package/layouts/auth.vue +5 -0
  51. package/layouts/default.vue +327 -0
  52. package/middleware/auth.global.ts +26 -0
  53. package/nuxt.config.ts +66 -0
  54. package/package.json +89 -0
  55. package/pages/index.vue +5 -0
  56. package/pages/login.vue +74 -0
  57. package/pages/onboarding.vue +563 -0
  58. package/pages/projects/[id]/formats/datetime.vue +240 -0
  59. package/pages/projects/[id]/formats/modifiers.vue +194 -0
  60. package/pages/projects/[id]/formats/number.vue +250 -0
  61. package/pages/projects/[id]/index.vue +182 -0
  62. package/pages/projects/[id]/languages.vue +537 -0
  63. package/pages/projects/[id]/review.vue +109 -0
  64. package/pages/projects/[id]/settings.vue +515 -0
  65. package/pages/projects/[id]/translations/[keyId].vue +642 -0
  66. package/pages/projects/[id]/translations/index.vue +250 -0
  67. package/pages/projects/[id]/users.vue +276 -0
  68. package/pages/projects/index.vue +334 -0
  69. package/pages/users/[id]/profile.vue +421 -0
  70. package/pages/users/index.vue +345 -0
  71. package/plugins/loading.client.ts +3 -0
  72. package/plugins/ui-i18n.ts +6 -0
  73. package/server/api/auth/login.post.ts +28 -0
  74. package/server/api/auth/logout.post.ts +7 -0
  75. package/server/api/auth/me.get.ts +11 -0
  76. package/server/api/auth/me.put.ts +31 -0
  77. package/server/api/auth/password.put.ts +27 -0
  78. package/server/api/auth/status.get.ts +16 -0
  79. package/server/api/config.get.ts +10 -0
  80. package/server/api/dashboard/layout.get.ts +18 -0
  81. package/server/api/dashboard/layout.post.ts +18 -0
  82. package/server/api/db-config.get.ts +44 -0
  83. package/server/api/db-config.post.ts +73 -0
  84. package/server/api/export.get.ts +64 -0
  85. package/server/api/formats/datetime/[id].delete.ts +8 -0
  86. package/server/api/formats/datetime/[id].put.ts +15 -0
  87. package/server/api/formats/datetime.get.ts +11 -0
  88. package/server/api/formats/datetime.post.ts +16 -0
  89. package/server/api/formats/modifiers/[id].delete.ts +8 -0
  90. package/server/api/formats/modifiers/[id].put.ts +10 -0
  91. package/server/api/formats/modifiers.get.ts +10 -0
  92. package/server/api/formats/modifiers.post.ts +14 -0
  93. package/server/api/formats/number/[id].delete.ts +8 -0
  94. package/server/api/formats/number/[id].put.ts +15 -0
  95. package/server/api/formats/number.get.ts +11 -0
  96. package/server/api/formats/number.post.ts +16 -0
  97. package/server/api/formats/snippet.get.ts +87 -0
  98. package/server/api/fs/browse.get.ts +50 -0
  99. package/server/api/history/[translationId].get.ts +13 -0
  100. package/server/api/keys/[id].delete.ts +14 -0
  101. package/server/api/keys/[id].get.ts +41 -0
  102. package/server/api/keys/[id].patch.ts +20 -0
  103. package/server/api/keys/index.get.ts +98 -0
  104. package/server/api/keys/index.post.ts +17 -0
  105. package/server/api/languages/[code].delete.ts +15 -0
  106. package/server/api/languages/[id].put.ts +24 -0
  107. package/server/api/languages/index.get.ts +13 -0
  108. package/server/api/languages/index.post.ts +42 -0
  109. package/server/api/onboarding.post.ts +56 -0
  110. package/server/api/profile.get.ts +81 -0
  111. package/server/api/project-snapshot.get.ts +73 -0
  112. package/server/api/project-snapshot.post.ts +160 -0
  113. package/server/api/projects/[id].delete.ts +13 -0
  114. package/server/api/projects/[id].put.ts +40 -0
  115. package/server/api/projects/index.get.ts +19 -0
  116. package/server/api/projects/index.post.ts +34 -0
  117. package/server/api/scan.post.ts +165 -0
  118. package/server/api/settings/index.get.ts +9 -0
  119. package/server/api/settings/index.post.ts +20 -0
  120. package/server/api/setup.post.ts +39 -0
  121. package/server/api/stats/global.get.ts +126 -0
  122. package/server/api/stats.get.ts +70 -0
  123. package/server/api/sync.post.ts +179 -0
  124. package/server/api/translate.post.ts +52 -0
  125. package/server/api/translations/batch-translate.post.ts +121 -0
  126. package/server/api/translations/bulk-status.post.ts +24 -0
  127. package/server/api/translations/index.post.ts +62 -0
  128. package/server/api/translations/job/[id].get.ts +23 -0
  129. package/server/api/translations/status.post.ts +30 -0
  130. package/server/api/translations/translate-all.post.ts +18 -0
  131. package/server/api/ui-locale.get.ts +39 -0
  132. package/server/api/users/[id]/profile.get.ts +107 -0
  133. package/server/api/users/[id]/roles.put.ts +67 -0
  134. package/server/api/users/[id].delete.ts +36 -0
  135. package/server/api/users/[id].put.ts +43 -0
  136. package/server/api/users/index.get.ts +49 -0
  137. package/server/api/users/index.post.ts +89 -0
  138. package/server/consts/auto-translate.const.ts +2 -0
  139. package/server/consts/commons.const.ts +10 -0
  140. package/server/consts/db.const.ts +3 -0
  141. package/server/consts/scanner.const.ts +4 -0
  142. package/server/consts/translation-job.const.ts +8 -0
  143. package/server/db/index.ts +672 -0
  144. package/server/enums/auth.enum.ts +5 -0
  145. package/server/enums/translation.enum.ts +6 -0
  146. package/server/interfaces/profile.interface.ts +48 -0
  147. package/server/interfaces/project-config.interface.ts +9 -0
  148. package/server/interfaces/scanner.interface.ts +18 -0
  149. package/server/interfaces/translation-job.interface.ts +13 -0
  150. package/server/middleware/auth.ts +32 -0
  151. package/server/plugins/db.ts +6 -0
  152. package/server/routes/locale/[lang].get.ts +179 -0
  153. package/server/types/auth.type.ts +3 -0
  154. package/server/utils/auth.util.ts +89 -0
  155. package/server/utils/auto-translate.util.ts +112 -0
  156. package/server/utils/lang-api.util.ts +24 -0
  157. package/server/utils/mailer.util.ts +80 -0
  158. package/server/utils/project-config.util.ts +37 -0
  159. package/server/utils/scanner.uti.ts +307 -0
  160. package/server/utils/translation-job.util.ts +142 -0
  161. package/services/auth.service.ts +31 -0
  162. package/services/base.service.ts +140 -0
  163. package/services/job.service.ts +10 -0
  164. package/services/key.service.ts +26 -0
  165. package/services/language.service.ts +26 -0
  166. package/services/profile.service.ts +14 -0
  167. package/services/project.service.ts +23 -0
  168. package/services/scan.service.ts +14 -0
  169. package/services/settings.service.ts +14 -0
  170. package/services/stats.service.ts +11 -0
  171. package/services/translation.service.ts +36 -0
  172. package/services/user.service.ts +28 -0
  173. package/tsconfig.json +3 -0
  174. package/types/commons.type.ts +3 -0
  175. package/types/dashboard.type.ts +26 -0
  176. package/utils/config.util.ts +60 -0
package/README.md ADDED
@@ -0,0 +1,715 @@
1
+ # i18n-dashboard
2
+
3
+ > A full-featured web dashboard to manage [vue-i18n](https://vue-i18n.intlify.dev/) translation keys — inspired by [Storybook](https://storybook.js.org/): run it alongside your project, manage all your translations in one place, and consume them via a ready-to-use API.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/i18n-dashboard)](https://www.npmjs.com/package/i18n-dashboard)
6
+ [![license](https://img.shields.io/npm/l/i18n-dashboard)](./LICENSE)
7
+ [![node](https://img.shields.io/node/v/i18n-dashboard)](https://nodejs.org/)
8
+
9
+ ---
10
+
11
+ ## Features
12
+
13
+ ### Core
14
+ - **Multi-project** — manage multiple Vue.js projects from one dashboard, each with its own languages, keys, and settings
15
+ - **Translation editor** — inline editing per language, keyboard shortcuts (`Ctrl+Enter` to save, `Esc` to cancel)
16
+ - **Plural forms** — dedicated plural editor supporting 2-form (EN/DE), 3-form (FR/ES), 4-form (Slavic), or custom rules
17
+ - **Key linking** — insert `@:key` linked references with optional modifiers (`.lower`, `.upper`, `.capitalize`) via a searchable modal picker
18
+ - **Escape helpers** — quick-insert toolbar for vue-i18n special characters (`{'@'}`, `{'{'}`, `\\{`, etc.)
19
+ - **Translation history** — every change (manual, sync, auto-translate) is tracked; restore any previous version
20
+ - **Inline auto-translate** — Google Translate per key (free tier, no API key required)
21
+ - **Batch auto-translate** — translate all missing keys for an entire language at once
22
+ - **Review workflow** — `Draft → Reviewed → Approved` status pipeline with role-based access control
23
+ - **Dashboard widgets** — customizable overview: coverage, total keys, unused keys, recent activity, per-language progress
24
+
25
+ ### Languages
26
+ - **BCP 47 support** — full regional codes: `fr-CA`, `en-GB`, `pt-BR`, `zh-CN`, `sr-Latn`, etc. (170+ locales)
27
+ - **Fallback chains** — configure explicit fallbacks per language (`fr-CA → fr → en`); automatic BCP 47 parent resolution
28
+ - **Auto-detect** — scan or sync automatically detects locale files and creates the corresponding languages
29
+ - **Default language** — designate one language as the source for auto-translate
30
+
31
+ ### Scan & Sync
32
+ - **Source scan (local)** — browse your file system with the built-in folder picker, detect all `$t()`, `t()`, `<i18n-t>`, `v-t`, and `<i18n>` block usages across `.vue`, `.ts`, `.js` files
33
+ - **Source scan (URL)** — fetch `en.json`, `fr.json`… from any remote URL and import all keys
34
+ - **Sync** — import existing `.json` locale files (local path or remote URL) into the database
35
+ - **Unused key detection** — keys not found in source files are automatically flagged
36
+
37
+ ### Advanced Formats
38
+ *(enable per project in Settings)*
39
+ - **Number formats** — configure `$n(value, 'currency')` presets using `Intl.NumberFormat` with live preview
40
+ - **Datetime formats** — configure `$d(date, 'short')` presets using `Intl.DateTimeFormat` with live preview
41
+ - **Custom modifiers** — define `@.modifier:key` transform functions with a built-in test runner
42
+ - **Snippet generator** — generates a ready-to-paste `createI18n()` configuration block
43
+
44
+ ### Projects
45
+ - **Inline settings** — edit project name, root path, locales folder, key separator, color, and description directly from the project settings page
46
+ - **Folder browser** — navigate your file system visually to pick the project root path
47
+ - **Project snapshot** — export a complete backup (config + languages + all keys + translations) as a single JSON file, import it on any other instance (merge or replace mode)
48
+
49
+ ### Users & Authentication
50
+ - **Role-based access** — `Super Admin`, `Admin`, `Moderator`, `Translator` — per-project assignments
51
+ - **Onboarding wizard** — guided setup on first launch
52
+ - **Multi-language UI** — the dashboard interface itself is translatable
53
+
54
+ ### Technical
55
+ - **Multi-database** — SQLite (default, zero config), PostgreSQL, MySQL/MariaDB
56
+ - **Auto-migration** — schema is created and updated automatically on startup
57
+ - **REST API** — full API for all operations, consume locale JSON from your Vue app
58
+ - **Dark mode** — system preference + manual toggle
59
+
60
+ ---
61
+
62
+ ## Requirements
63
+
64
+ - **Node.js** >= 18
65
+ - **npm** >= 9
66
+
67
+ ---
68
+
69
+ ## Installation
70
+
71
+ ### As a dev dependency (recommended — per project)
72
+
73
+ ```bash
74
+ npm install i18n-dashboard --save-dev
75
+ ```
76
+
77
+ ### Globally (use across multiple projects)
78
+
79
+ ```bash
80
+ npm install -g i18n-dashboard
81
+ ```
82
+
83
+ ---
84
+
85
+ ## Quick Start
86
+
87
+ ### 1 — Initialize
88
+
89
+ Run the interactive setup wizard from your project root:
90
+
91
+ ```bash
92
+ npx i18n-dashboard init
93
+ ```
94
+
95
+ This creates an `i18n-dashboard.config.js` file at the root of your project.
96
+
97
+ ### 2 — Start
98
+
99
+ ```bash
100
+ npx i18n-dashboard start
101
+ ```
102
+
103
+ Open **http://localhost:3333** in your browser.
104
+
105
+ The onboarding wizard will guide you through:
106
+ 1. Creating an administrator account
107
+ 2. Selecting the dashboard UI language
108
+ 3. Configuring your first project
109
+
110
+ ### 3 — Import existing locale files (optional)
111
+
112
+ If you already have `.json` locale files, import them into the database:
113
+
114
+ ```bash
115
+ npx i18n-dashboard sync
116
+ ```
117
+
118
+ > The dashboard must be running for this command to work.
119
+
120
+ ### 4 — Use the API in your Vue app
121
+
122
+ ```js
123
+ // src/i18n.js
124
+ import { createI18n } from 'vue-i18n'
125
+
126
+ export const i18n = createI18n({
127
+ locale: 'en',
128
+ fallbackLocale: 'en',
129
+ messages: {
130
+ en: await fetch('http://localhost:3333/locale/en.json').then(r => r.json()),
131
+ fr: await fetch('http://localhost:3333/locale/fr.json').then(r => r.json()),
132
+ },
133
+ })
134
+ ```
135
+
136
+ ### 5 — Add a script to your package.json
137
+
138
+ ```json
139
+ {
140
+ "scripts": {
141
+ "dev": "vite",
142
+ "i18n": "i18n-dashboard start"
143
+ }
144
+ }
145
+ ```
146
+
147
+ ---
148
+
149
+ ## Configuration
150
+
151
+ ### i18n-dashboard.config.js
152
+
153
+ ```js
154
+ // i18n-dashboard.config.js
155
+ export default {
156
+ // Port the dashboard will run on
157
+ port: 3333,
158
+
159
+ // Key separator for nested keys ('home.title' uses '.')
160
+ keySeparator: '.',
161
+
162
+ // URL path pattern for serving locale JSON files
163
+ apiPath: '/locale/[lang].json',
164
+
165
+ // Root path of your Vue project (absolute or relative)
166
+ projectRoot: './',
167
+
168
+ // Database configuration
169
+ database: {
170
+ // Options: 'better-sqlite3' (default), 'pg', 'mysql2'
171
+ client: 'better-sqlite3',
172
+
173
+ // SQLite: path to the .db file
174
+ connection: './i18n-dashboard.db',
175
+
176
+ // PostgreSQL / MySQL: use a connection object instead:
177
+ // connection: {
178
+ // host: 'localhost',
179
+ // port: 5432,
180
+ // user: 'myuser',
181
+ // password: 'mypassword',
182
+ // database: 'i18n_dashboard',
183
+ // },
184
+ },
185
+
186
+ // Google Translate API key (optional — free tier works without a key)
187
+ // googleTranslate: {
188
+ // apiKey: process.env.GOOGLE_TRANSLATE_API_KEY,
189
+ // },
190
+ }
191
+ ```
192
+
193
+ ### Environment variables
194
+
195
+ All options can be passed as environment variables (useful for CI/CD and Docker):
196
+
197
+ | Variable | Description | Default |
198
+ |---|---|---|
199
+ | `I18N_PORT` | Server port | `3333` |
200
+ | `I18N_DB_CLIENT` | DB driver (`better-sqlite3` / `pg` / `mysql2`) | `better-sqlite3` |
201
+ | `I18N_DB_CONNECTION` | SQLite file path | `./i18n-dashboard.db` |
202
+ | `I18N_DB_HOST` | PostgreSQL/MySQL host | `localhost` |
203
+ | `I18N_DB_PORT` | PostgreSQL/MySQL port | `5432` |
204
+ | `I18N_DB_USER` | Database user | — |
205
+ | `I18N_DB_PASSWORD` | Database password | — |
206
+ | `I18N_DB_NAME` | Database name | `i18n_dashboard` |
207
+ | `I18N_KEY_SEPARATOR` | Key separator | `.` |
208
+ | `I18N_API_PATH` | Locale API path pattern | `/locale/[lang].json` |
209
+ | `I18N_PROJECT_ROOT` | Project root path | `process.cwd()` |
210
+ | `I18N_LOCALES_PATH` | Locales folder (relative to root) | `src/locales` |
211
+ | `GOOGLE_TRANSLATE_API_KEY` | Google Translate API key | — |
212
+ | `SESSION_SECRET` | Session encryption secret | *(default, change in prod)* |
213
+ | `SMTP_HOST` | SMTP server for email | — |
214
+ | `DASHBOARD_URL` | Public URL of the dashboard | `http://localhost:3333` |
215
+
216
+ ---
217
+
218
+ ## CLI Commands
219
+
220
+ ```
221
+ i18n-dashboard <command> [options]
222
+
223
+ Commands:
224
+ start Start the dashboard server
225
+ stop Stop a running detached dashboard
226
+ build Build for production
227
+ init Run the interactive setup wizard
228
+ sync Import locale JSON files into the database
229
+
230
+ Options for start:
231
+ -p, --port <port> Server port (default: 3333)
232
+ --detach Run in the background (writes PID file)
233
+
234
+ Global options:
235
+ -V, --version Show version
236
+ -h, --help Show help
237
+ ```
238
+
239
+ ### Background mode
240
+
241
+ ```bash
242
+ # Start in background
243
+ npx i18n-dashboard start --detach
244
+
245
+ # Stop the background process
246
+ npx i18n-dashboard stop
247
+ ```
248
+
249
+ ---
250
+
251
+ ## Interface
252
+
253
+ ### Dashboard
254
+
255
+ Customizable widget grid. Available widgets:
256
+ - **Total keys** — overall key count
257
+ - **Coverage** — global translation coverage percentage
258
+ - **Languages** — number of configured languages
259
+ - **Unused keys** — keys not found in source code
260
+ - **Language coverage** — per-language progress bars
261
+ - **Recent activity** — latest translation edits
262
+ - **Review queue** — translations awaiting approval
263
+ - **Projects** — quick project overview
264
+
265
+ Click **Edit** to add, remove, or rearrange widgets.
266
+
267
+ ### Translations
268
+
269
+ The main translation table with:
270
+ - Search by key name (real-time)
271
+ - Filter by language and status (`All`, `Draft`, `Reviewed`, `Approved`, `Missing`, `Unused`)
272
+ - Status badge per language
273
+ - Auto-translate per key (Google Translate)
274
+ - Batch auto-translate for an entire language
275
+
276
+ Click any key to open its **detail page**:
277
+ - Edit each language with the full toolbar (params, escape helpers, plural editor, linked key picker)
278
+ - View translation history with one-click restore
279
+ - See which source files reference this key (after scan)
280
+
281
+ #### Plural editor
282
+
283
+ Switch any translation to plural mode to get a template-based form:
284
+
285
+ | Template | Languages | Example |
286
+ |---|---|---|
287
+ | 2 forms — standard | English, German, Dutch… | `car \| cars` |
288
+ | 3 forms — zero/one/many | French, Spanish, Italian… | `no cars \| {count} car \| {count} cars` |
289
+ | 4 forms — Slavic | Russian, Polish, Ukrainian… | `0 машин \| {n} машина \| {n} машины \| {n} машин` |
290
+ | Custom | Any | Define your own forms |
291
+
292
+ The `{count}` and `{n}` parameters are always available implicitly.
293
+
294
+ ### Languages
295
+
296
+ - Add languages from 170+ BCP 47 locale codes (`fr`, `fr-CA`, `en-GB`, `zh-CN`, `sr-Latn`…)
297
+ - Type any custom BCP 47 code if it's not in the list
298
+ - Set a default language (source for auto-translate)
299
+ - Configure fallback chains:
300
+ - **Automatic** — `fr-CA → fr` (BCP 47 parent)
301
+ - **Manual** — pick any other configured language
302
+ - **None** — no fallback
303
+ - The API resolves the fallback chain transparently and merges translations
304
+
305
+ ### Scan
306
+
307
+ Click **Scan project** in the sidebar to open the scan modal:
308
+
309
+ **Local mode** — browse your file system with the folder picker and scan `.vue`, `.ts`, `.js` files for:
310
+ - `$t('key')`, `$tc()`, `$te()`, `$tm()`
311
+ - `t('key')` via `useI18n()`
312
+ - `<i18n-t keypath="key">`
313
+ - `v-t="'key'"`
314
+ - `<i18n>` SFC blocks
315
+
316
+ **URL mode** — enter the base URL of your app; the scanner fetches each configured locale file (`/locale/en.json`, `/locale/fr.json`…) and imports all keys it finds.
317
+
318
+ Results (keys found, new keys, unused keys, files scanned) are displayed inline.
319
+
320
+ ### Settings
321
+
322
+ Per-project settings (editable inline):
323
+ - **Project name, root path, source URL, locales folder, key separator, color, description**
324
+ - **Advanced features** — enable/disable Number formats, Datetime formats, Custom modifiers pages
325
+ - **Scanner** — configure excluded directories
326
+ - **Google Translate** — optional API key
327
+ - **Export** — download locale JSON files per language or all at once
328
+ - **Snapshot** — export/import a full project backup
329
+
330
+ ### Number Formats *(requires enable in Settings)*
331
+
332
+ Configure `$n(value, 'formatName')` presets:
333
+ - Group by locale
334
+ - Style: `decimal`, `currency`, `percent`, `unit`
335
+ - Currency / unit selection
336
+ - Live `Intl.NumberFormat` preview
337
+
338
+ ### Datetime Formats *(requires enable in Settings)*
339
+
340
+ Configure `$d(date, 'formatName')` presets:
341
+ - Shortcut styles: `dateStyle` / `timeStyle`
342
+ - Individual fields: `year`, `month`, `day`, `hour`, `minute`, `second`, `weekday`, `era`, `timeZone`
343
+ - Live `Intl.DateTimeFormat` preview
344
+
345
+ ### Modifiers *(requires enable in Settings)*
346
+
347
+ Define custom `@.modifier:key` transform functions:
348
+ - Write JS function body
349
+ - Live test runner
350
+ - Quick templates: `snakeCase`, `camelCase`, `kebabCase`, `titleCase`
351
+
352
+ ### Snippet generator
353
+
354
+ Available on all format pages — generates a ready-to-paste `createI18n()` configuration including all your number formats, datetime formats, and custom modifiers.
355
+
356
+ ### Project Snapshot
357
+
358
+ Export a complete project backup:
359
+
360
+ ```json
361
+ {
362
+ "version": 1,
363
+ "exportedAt": "2026-01-01T00:00:00.000Z",
364
+ "project": { "name": "My App", "locales_path": "src/locales", "key_separator": "." },
365
+ "languages": [{ "code": "en", "name": "English", "is_default": true }],
366
+ "keys": [
367
+ {
368
+ "key": "home.title",
369
+ "description": "Homepage title",
370
+ "translations": {
371
+ "en": { "value": "Welcome", "status": "approved" },
372
+ "fr": { "value": "Bienvenue", "status": "reviewed" }
373
+ }
374
+ }
375
+ ]
376
+ }
377
+ ```
378
+
379
+ Import modes:
380
+ - **Merge** — add/update keys without touching existing ones
381
+ - **Replace** — delete everything and reimport clean
382
+
383
+ ---
384
+
385
+ ## vue-i18n Integration
386
+
387
+ ### Basic (load all on startup)
388
+
389
+ ```js
390
+ // src/i18n.js
391
+ import { createI18n } from 'vue-i18n'
392
+
393
+ const DASHBOARD = 'http://localhost:3333'
394
+
395
+ export const i18n = createI18n({
396
+ locale: 'en',
397
+ fallbackLocale: 'en',
398
+ messages: {
399
+ en: await fetch(`${DASHBOARD}/locale/en.json`).then(r => r.json()),
400
+ fr: await fetch(`${DASHBOARD}/locale/fr.json`).then(r => r.json()),
401
+ },
402
+ })
403
+ ```
404
+
405
+ ### With lazy loading
406
+
407
+ ```js
408
+ import { createI18n } from 'vue-i18n'
409
+
410
+ const DASHBOARD = 'http://localhost:3333'
411
+
412
+ export const i18n = createI18n({ locale: 'en', fallbackLocale: 'en', messages: {} })
413
+
414
+ export async function setLocale(locale) {
415
+ if (!i18n.global.availableLocales.includes(locale)) {
416
+ const messages = await fetch(`${DASHBOARD}/locale/${locale}.json`).then(r => r.json())
417
+ i18n.global.setLocaleMessage(locale, messages)
418
+ }
419
+ i18n.global.locale.value = locale
420
+ }
421
+ ```
422
+
423
+ ### With BCP 47 fallbacks
424
+
425
+ The API automatically resolves fallback chains. If `fr-CA` isn't fully translated, missing keys fall back to `fr`, then to the next configured fallback:
426
+
427
+ ```
428
+ GET /locale/fr-CA.json → merges fr + fr-CA (fr-CA takes precedence)
429
+ X-I18n-Fallback-Chain: fr-CA → fr
430
+ ```
431
+
432
+ No configuration needed on the client side.
433
+
434
+ ### For production
435
+
436
+ Export locale files into your project and include them in your build:
437
+
438
+ ```bash
439
+ curl http://localhost:3333/locale/en.json -o src/locales/en.json
440
+ curl http://localhost:3333/locale/fr.json -o src/locales/fr.json
441
+ ```
442
+
443
+ Or deploy the dashboard on an internal server and keep using the API.
444
+
445
+ ---
446
+
447
+ ## Database
448
+
449
+ ### SQLite (default — zero config)
450
+
451
+ ```js
452
+ database: {
453
+ client: 'better-sqlite3',
454
+ connection: './i18n-dashboard.db',
455
+ }
456
+ ```
457
+
458
+ The `.db` file is created automatically. No setup needed.
459
+
460
+ ### PostgreSQL
461
+
462
+ ```bash
463
+ npm install pg
464
+ ```
465
+
466
+ ```js
467
+ database: {
468
+ client: 'pg',
469
+ connection: {
470
+ host: 'localhost',
471
+ port: 5432,
472
+ user: 'myuser',
473
+ password: 'mypassword',
474
+ database: 'i18n_dashboard',
475
+ },
476
+ }
477
+ ```
478
+
479
+ ### MySQL / MariaDB
480
+
481
+ ```bash
482
+ npm install mysql2
483
+ ```
484
+
485
+ ```js
486
+ database: {
487
+ client: 'mysql2',
488
+ connection: {
489
+ host: 'localhost',
490
+ port: 3306,
491
+ user: 'myuser',
492
+ password: 'mypassword',
493
+ database: 'i18n_dashboard',
494
+ },
495
+ }
496
+ ```
497
+
498
+ ### Schema
499
+
500
+ Tables are created and migrated automatically on startup:
501
+
502
+ ```
503
+ projects — multi-project support
504
+ languages — per-project language list (BCP 47 codes, fallback_code)
505
+ translation_keys — key registry (key, description, is_unused, usages)
506
+ translations — values per key per language (value, status)
507
+ translation_history — full edit history (old_value, new_value, changed_by)
508
+ key_usages — source file references (file_path, line_number, function)
509
+ settings — global settings (scan_exclude, google_translate_api_key)
510
+ users — dashboard users (name, email, role, bcrypt password)
511
+ project_number_formats — Intl.NumberFormat presets
512
+ project_datetime_formats — Intl.DateTimeFormat presets
513
+ project_modifiers — custom @.modifier functions
514
+ ```
515
+
516
+ ---
517
+
518
+ ## REST API
519
+
520
+ All endpoints require a `project_id` parameter.
521
+
522
+ ### Locale export (main endpoint for vue-i18n)
523
+
524
+ ```http
525
+ GET /locale/:lang.json?project_id=1
526
+ ```
527
+
528
+ Returns nested JSON with all translations for the given language. Resolves fallback chains automatically.
529
+
530
+ **Response headers:**
531
+ - `X-I18n-Fallback-Chain: fr-CA → fr` — debug the resolved chain
532
+
533
+ ### Projects
534
+
535
+ ```http
536
+ GET /api/projects
537
+ POST /api/projects
538
+ PUT /api/projects/:id
539
+ DELETE /api/projects/:id
540
+ ```
541
+
542
+ ### Languages
543
+
544
+ ```http
545
+ GET /api/languages?project_id=1
546
+ POST /api/languages
547
+ PUT /api/languages/:id
548
+ DELETE /api/languages/:code?project_id=1
549
+ ```
550
+
551
+ ### Translation keys
552
+
553
+ ```http
554
+ GET /api/keys?project_id=1&search=&lang=&status=&page=1&limit=50
555
+ GET /api/keys/:id
556
+ POST /api/keys
557
+ PATCH /api/keys/:id
558
+ DELETE /api/keys/:id
559
+ ```
560
+
561
+ ### Translations
562
+
563
+ ```http
564
+ POST /api/translations # Save a translation value
565
+ POST /api/translations/status # Update status only
566
+ POST /api/translations/batch-translate # Auto-translate all missing for a language
567
+ ```
568
+
569
+ ### Scan & Sync
570
+
571
+ ```http
572
+ POST /api/scan # body: { project_id, mode: 'local'|'url', root_path?, url? }
573
+ POST /api/sync # body: { project_id }
574
+ ```
575
+
576
+ ### Project Snapshot
577
+
578
+ ```http
579
+ GET /api/project-snapshot?project_id=1 # Export
580
+ POST /api/project-snapshot # Import
581
+ body: { snapshot, project_id?, mode: 'merge'|'replace' }
582
+ ```
583
+
584
+ ### Advanced formats
585
+
586
+ ```http
587
+ GET /api/formats/number?project_id=1
588
+ POST /api/formats/number
589
+ PUT /api/formats/number/:id
590
+ DELETE /api/formats/number/:id
591
+
592
+ GET /api/formats/datetime?project_id=1
593
+ POST /api/formats/datetime
594
+ PUT /api/formats/datetime/:id
595
+ DELETE /api/formats/datetime/:id
596
+
597
+ GET /api/formats/modifiers?project_id=1
598
+ POST /api/formats/modifiers
599
+ PUT /api/formats/modifiers/:id
600
+ DELETE /api/formats/modifiers/:id
601
+
602
+ GET /api/formats/snippet?project_id=1 # Generate createI18n() config snippet
603
+ ```
604
+
605
+ ### Settings
606
+
607
+ ```http
608
+ GET /api/settings
609
+ POST /api/settings
610
+ ```
611
+
612
+ ### File system browser
613
+
614
+ ```http
615
+ GET /api/fs/browse?path=/some/path # List subdirectories; defaults to home dir
616
+ ```
617
+
618
+ ---
619
+
620
+ ## User Roles
621
+
622
+ | Role | Permissions |
623
+ |---|---|
624
+ | **Super Admin** | Full access to all projects, users, and global settings |
625
+ | **Admin** | Full access to assigned projects |
626
+ | **Moderator** | Edit translations, approve/reject in review queue |
627
+ | **Translator** | Edit translations, mark as reviewed (cannot approve) |
628
+
629
+ ---
630
+
631
+ ## Recommended Workflows
632
+
633
+ ### New project from scratch
634
+
635
+ ```bash
636
+ # 1. Install
637
+ npm install i18n-dashboard --save-dev
638
+
639
+ # 2. Initialize
640
+ npx i18n-dashboard init
641
+
642
+ # 3. Start
643
+ npx i18n-dashboard start
644
+
645
+ # 4. In the UI:
646
+ # - Add languages (Languages tab)
647
+ # - Add translation keys (Translations tab)
648
+ # - Use the API in your Vue app
649
+ ```
650
+
651
+ ### Migrate from existing JSON files
652
+
653
+ ```bash
654
+ # 1. Install and initialize
655
+ npm install i18n-dashboard --save-dev
656
+ npx i18n-dashboard init
657
+
658
+ # 2. Start
659
+ npx i18n-dashboard start
660
+
661
+ # 3. Sync your existing locale files
662
+ npx i18n-dashboard sync
663
+
664
+ # 4. All keys and translations are now in the database
665
+ ```
666
+
667
+ ### Team workflow with review
668
+
669
+ 1. **Translators** edit keys → status: `Draft`
670
+ 2. **Translators** mark ready → status: `Reviewed`
671
+ 3. **Moderators/Admins** approve → status: `Approved`
672
+ 4. Only `Approved` translations are exported (or all, depending on your needs)
673
+
674
+ ### Move between environments (local → production)
675
+
676
+ ```bash
677
+ # On local machine: export snapshot
678
+ # Dashboard UI → Settings → Snapshot → Export
679
+
680
+ # On production server: import snapshot
681
+ # Dashboard UI → Settings → Snapshot → Import (Merge or Replace mode)
682
+ ```
683
+
684
+ ---
685
+
686
+ ## Stack
687
+
688
+ | Technology | Version | Role |
689
+ |---|---|---|
690
+ | [Nuxt 3](https://nuxt.com/) | 3.21+ | Full-stack framework (Nitro backend + Vue 3 frontend) |
691
+ | [Nuxt UI](https://ui.nuxt.com/) | 3.3+ | UI components (Tailwind CSS v4 + Reka UI) |
692
+ | [Knex.js](https://knexjs.org/) | 3.x | Multi-database abstraction |
693
+ | [better-sqlite3](https://github.com/WiseLibs/better-sqlite3) | 11.x | SQLite driver |
694
+ | [@vitalets/google-translate-api](https://github.com/vitalets/google-translate-api) | 9.x | Google Translate (free tier) |
695
+ | [Commander.js](https://github.com/tj/commander.js) | 13.x | CLI |
696
+ | [bcryptjs](https://github.com/dcodeIO/bcrypt.js) | 2.x | Password hashing |
697
+
698
+ ---
699
+
700
+ ## Contributing
701
+
702
+ Contributions are welcome. Please open an issue before submitting a pull request for significant changes.
703
+
704
+ ```bash
705
+ git clone https://github.com/your-username/i18n-dashboard
706
+ cd i18n-dashboard
707
+ npm install
708
+ npm run dev
709
+ ```
710
+
711
+ ---
712
+
713
+ ## License
714
+
715
+ [MIT](./LICENSE)