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.
- package/LICENSE +21 -0
- package/README.md +715 -0
- package/app.vue +8 -0
- package/assets/css/main.css +21 -0
- package/assets/locales/en.json +380 -0
- package/bin/cli.mjs +279 -0
- package/components/LinkedKeyPicker.vue +135 -0
- package/components/PathPicker.vue +153 -0
- package/components/PluralEditor.vue +295 -0
- package/components/ScanModal.vue +153 -0
- package/components/TranslationHistoryModal.vue +66 -0
- package/components/TranslationRow.vue +541 -0
- package/components/dashboard/WidgetConfigModal.vue +121 -0
- package/components/dashboard/WidgetGrid.vue +190 -0
- package/components/dashboard/WidgetPicker.vue +75 -0
- package/components/dashboard/widgets/ActivityWidget.vue +109 -0
- package/components/dashboard/widgets/LanguagesCoverageWidget.vue +104 -0
- package/components/dashboard/widgets/ProjectsWidget.vue +77 -0
- package/components/dashboard/widgets/ReviewWidget.vue +150 -0
- package/components/dashboard/widgets/StatWidget.vue +133 -0
- package/composables/useAuth.ts +72 -0
- package/composables/useConfig.ts +14 -0
- package/composables/useDashboard.ts +89 -0
- package/composables/useFormats.ts +100 -0
- package/composables/useKeys.ts +231 -0
- package/composables/useLanguages.ts +221 -0
- package/composables/useProfile.ts +76 -0
- package/composables/useProject.ts +180 -0
- package/composables/useReview.ts +94 -0
- package/composables/useSettings.ts +30 -0
- package/composables/useStats.ts +16 -0
- package/composables/useT.ts +38 -0
- package/composables/useUsers.ts +101 -0
- package/composables/useWidgetData.ts +50 -0
- package/consts/commons.const.ts +6 -0
- package/consts/dashboard.const.ts +94 -0
- package/consts/languages.const.ts +223 -0
- package/enums/commons.enum.ts +7 -0
- package/i18n-dashboard.config.example.js +40 -0
- package/interfaces/commons.interface.ts +23 -0
- package/interfaces/job.interface.ts +10 -0
- package/interfaces/key.interface.ts +39 -0
- package/interfaces/languages.interface.ts +23 -0
- package/interfaces/project.interface.ts +9 -0
- package/interfaces/scan.interface.ts +12 -0
- package/interfaces/settings.interface.ts +4 -0
- package/interfaces/stat.interface.ts +30 -0
- package/interfaces/translation.interface.ts +11 -0
- package/interfaces/user.interface.ts +24 -0
- package/layouts/auth.vue +5 -0
- package/layouts/default.vue +327 -0
- package/middleware/auth.global.ts +26 -0
- package/nuxt.config.ts +66 -0
- package/package.json +89 -0
- package/pages/index.vue +5 -0
- package/pages/login.vue +74 -0
- package/pages/onboarding.vue +563 -0
- package/pages/projects/[id]/formats/datetime.vue +240 -0
- package/pages/projects/[id]/formats/modifiers.vue +194 -0
- package/pages/projects/[id]/formats/number.vue +250 -0
- package/pages/projects/[id]/index.vue +182 -0
- package/pages/projects/[id]/languages.vue +537 -0
- package/pages/projects/[id]/review.vue +109 -0
- package/pages/projects/[id]/settings.vue +515 -0
- package/pages/projects/[id]/translations/[keyId].vue +642 -0
- package/pages/projects/[id]/translations/index.vue +250 -0
- package/pages/projects/[id]/users.vue +276 -0
- package/pages/projects/index.vue +334 -0
- package/pages/users/[id]/profile.vue +421 -0
- package/pages/users/index.vue +345 -0
- package/plugins/loading.client.ts +3 -0
- package/plugins/ui-i18n.ts +6 -0
- package/server/api/auth/login.post.ts +28 -0
- package/server/api/auth/logout.post.ts +7 -0
- package/server/api/auth/me.get.ts +11 -0
- package/server/api/auth/me.put.ts +31 -0
- package/server/api/auth/password.put.ts +27 -0
- package/server/api/auth/status.get.ts +16 -0
- package/server/api/config.get.ts +10 -0
- package/server/api/dashboard/layout.get.ts +18 -0
- package/server/api/dashboard/layout.post.ts +18 -0
- package/server/api/db-config.get.ts +44 -0
- package/server/api/db-config.post.ts +73 -0
- package/server/api/export.get.ts +64 -0
- package/server/api/formats/datetime/[id].delete.ts +8 -0
- package/server/api/formats/datetime/[id].put.ts +15 -0
- package/server/api/formats/datetime.get.ts +11 -0
- package/server/api/formats/datetime.post.ts +16 -0
- package/server/api/formats/modifiers/[id].delete.ts +8 -0
- package/server/api/formats/modifiers/[id].put.ts +10 -0
- package/server/api/formats/modifiers.get.ts +10 -0
- package/server/api/formats/modifiers.post.ts +14 -0
- package/server/api/formats/number/[id].delete.ts +8 -0
- package/server/api/formats/number/[id].put.ts +15 -0
- package/server/api/formats/number.get.ts +11 -0
- package/server/api/formats/number.post.ts +16 -0
- package/server/api/formats/snippet.get.ts +87 -0
- package/server/api/fs/browse.get.ts +50 -0
- package/server/api/history/[translationId].get.ts +13 -0
- package/server/api/keys/[id].delete.ts +14 -0
- package/server/api/keys/[id].get.ts +41 -0
- package/server/api/keys/[id].patch.ts +20 -0
- package/server/api/keys/index.get.ts +98 -0
- package/server/api/keys/index.post.ts +17 -0
- package/server/api/languages/[code].delete.ts +15 -0
- package/server/api/languages/[id].put.ts +24 -0
- package/server/api/languages/index.get.ts +13 -0
- package/server/api/languages/index.post.ts +42 -0
- package/server/api/onboarding.post.ts +56 -0
- package/server/api/profile.get.ts +81 -0
- package/server/api/project-snapshot.get.ts +73 -0
- package/server/api/project-snapshot.post.ts +160 -0
- package/server/api/projects/[id].delete.ts +13 -0
- package/server/api/projects/[id].put.ts +40 -0
- package/server/api/projects/index.get.ts +19 -0
- package/server/api/projects/index.post.ts +34 -0
- package/server/api/scan.post.ts +165 -0
- package/server/api/settings/index.get.ts +9 -0
- package/server/api/settings/index.post.ts +20 -0
- package/server/api/setup.post.ts +39 -0
- package/server/api/stats/global.get.ts +126 -0
- package/server/api/stats.get.ts +70 -0
- package/server/api/sync.post.ts +179 -0
- package/server/api/translate.post.ts +52 -0
- package/server/api/translations/batch-translate.post.ts +121 -0
- package/server/api/translations/bulk-status.post.ts +24 -0
- package/server/api/translations/index.post.ts +62 -0
- package/server/api/translations/job/[id].get.ts +23 -0
- package/server/api/translations/status.post.ts +30 -0
- package/server/api/translations/translate-all.post.ts +18 -0
- package/server/api/ui-locale.get.ts +39 -0
- package/server/api/users/[id]/profile.get.ts +107 -0
- package/server/api/users/[id]/roles.put.ts +67 -0
- package/server/api/users/[id].delete.ts +36 -0
- package/server/api/users/[id].put.ts +43 -0
- package/server/api/users/index.get.ts +49 -0
- package/server/api/users/index.post.ts +89 -0
- package/server/consts/auto-translate.const.ts +2 -0
- package/server/consts/commons.const.ts +10 -0
- package/server/consts/db.const.ts +3 -0
- package/server/consts/scanner.const.ts +4 -0
- package/server/consts/translation-job.const.ts +8 -0
- package/server/db/index.ts +672 -0
- package/server/enums/auth.enum.ts +5 -0
- package/server/enums/translation.enum.ts +6 -0
- package/server/interfaces/profile.interface.ts +48 -0
- package/server/interfaces/project-config.interface.ts +9 -0
- package/server/interfaces/scanner.interface.ts +18 -0
- package/server/interfaces/translation-job.interface.ts +13 -0
- package/server/middleware/auth.ts +32 -0
- package/server/plugins/db.ts +6 -0
- package/server/routes/locale/[lang].get.ts +179 -0
- package/server/types/auth.type.ts +3 -0
- package/server/utils/auth.util.ts +89 -0
- package/server/utils/auto-translate.util.ts +112 -0
- package/server/utils/lang-api.util.ts +24 -0
- package/server/utils/mailer.util.ts +80 -0
- package/server/utils/project-config.util.ts +37 -0
- package/server/utils/scanner.uti.ts +307 -0
- package/server/utils/translation-job.util.ts +142 -0
- package/services/auth.service.ts +31 -0
- package/services/base.service.ts +140 -0
- package/services/job.service.ts +10 -0
- package/services/key.service.ts +26 -0
- package/services/language.service.ts +26 -0
- package/services/profile.service.ts +14 -0
- package/services/project.service.ts +23 -0
- package/services/scan.service.ts +14 -0
- package/services/settings.service.ts +14 -0
- package/services/stats.service.ts +11 -0
- package/services/translation.service.ts +36 -0
- package/services/user.service.ts +28 -0
- package/tsconfig.json +3 -0
- package/types/commons.type.ts +3 -0
- package/types/dashboard.type.ts +26 -0
- package/utils/config.util.ts +60 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BaseService } from './base.service'
|
|
2
|
+
import type { UserProfile } from '../server/interfaces/profile.interface'
|
|
3
|
+
|
|
4
|
+
class ProfileService extends BaseService {
|
|
5
|
+
async getProfile(): Promise<UserProfile> {
|
|
6
|
+
return this.get<UserProfile>('/api/profile')
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
async getUserProfile(id: number | string): Promise<UserProfile> {
|
|
10
|
+
return this.get<UserProfile>(`/api/users/${id}/profile`)
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const profileService = new ProfileService()
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { BaseService } from './base.service'
|
|
2
|
+
import type { Project } from '../composables/useProject'
|
|
3
|
+
import type { ProjectPayload } from '../interfaces/project.interface'
|
|
4
|
+
|
|
5
|
+
class ProjectService extends BaseService {
|
|
6
|
+
async getAll(): Promise<Project[]> {
|
|
7
|
+
return this.get<Project[]>('/api/projects')
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async create(data: ProjectPayload): Promise<Project> {
|
|
11
|
+
return this.post<Project>('/api/projects', { body: data, skipDedup: true })
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async update(id: number, data: Partial<ProjectPayload>): Promise<Project> {
|
|
15
|
+
return this.put<Project>(`/api/projects/${id}`, { body: data })
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async remove(id: number): Promise<void> {
|
|
19
|
+
return this.delete(`/api/projects/${id}`)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const projectService = new ProjectService()
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BaseService } from './base.service'
|
|
2
|
+
import type { ScanResult, SyncResult } from '../interfaces/scan.interface'
|
|
3
|
+
|
|
4
|
+
class ScanService extends BaseService {
|
|
5
|
+
async scan(projectId: number): Promise<ScanResult> {
|
|
6
|
+
return this.post<ScanResult>('/api/scan', { body: { project_id: projectId }, skipDedup: true })
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
async sync(projectId: number): Promise<SyncResult> {
|
|
10
|
+
return this.post<SyncResult>('/api/sync', { body: { project_id: projectId }, skipDedup: true })
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const scanService = new ScanService()
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BaseService } from './base.service'
|
|
2
|
+
import type { SettingsPayload } from '../interfaces/settings.interface'
|
|
3
|
+
|
|
4
|
+
class SettingsService extends BaseService {
|
|
5
|
+
async getSettings(): Promise<Record<string, string>> {
|
|
6
|
+
return this.get<Record<string, string>>('/api/settings')
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
async saveSettings(data: SettingsPayload): Promise<void> {
|
|
10
|
+
return this.post('/api/settings', { body: data, skipDedup: true })
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const settingsService = new SettingsService()
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { BaseService } from './base.service'
|
|
2
|
+
import type { StatsResponse } from '../interfaces/stat.interface'
|
|
3
|
+
|
|
4
|
+
class StatsService extends BaseService {
|
|
5
|
+
async getStats(projectId?: number): Promise<StatsResponse | null> {
|
|
6
|
+
if (!projectId) return null
|
|
7
|
+
return this.get<StatsResponse>('/api/stats', { query: { project_id: projectId } })
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const statsService = new StatsService()
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { BaseService } from './base.service'
|
|
2
|
+
import type { SaveTranslationPayload, SetStatusPayload } from '../interfaces/translation.interface'
|
|
3
|
+
|
|
4
|
+
class TranslationService extends BaseService {
|
|
5
|
+
async save(data: SaveTranslationPayload): Promise<void> {
|
|
6
|
+
return this.post('/api/translations', { body: data, skipDedup: true })
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
async setStatus(data: SetStatusPayload): Promise<void> {
|
|
10
|
+
return this.post('/api/translations/status', { body: data, skipDedup: true })
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async bulkStatus(ids: number[], status: string): Promise<void> {
|
|
14
|
+
return this.post('/api/translations/bulk-status', { body: { ids, status }, skipDedup: true })
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async batchTranslate(projectId: number, targetLanguage: string): Promise<{ translated: number; skipped: number; errors: number }> {
|
|
18
|
+
return this.post('/api/translations/batch-translate', {
|
|
19
|
+
body: { project_id: projectId, target_language: targetLanguage },
|
|
20
|
+
skipDedup: true,
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async translateAll(projectId: number, languageCode: string, languageName: string): Promise<{ jobId: string }> {
|
|
25
|
+
return this.post('/api/translations/translate-all', {
|
|
26
|
+
body: { project_id: projectId, language_code: languageCode, language_name: languageName },
|
|
27
|
+
skipDedup: true,
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async translateText(text: string, from: string, to: string): Promise<{ text: string }> {
|
|
32
|
+
return this.post<{ text: string }>('/api/translate', { body: { text, from, to }, skipDedup: true })
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const translationService = new TranslationService()
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { BaseService } from './base.service'
|
|
2
|
+
import type { CreateUserPayload, RoleEntry, UserItem } from '../interfaces/user.interface'
|
|
3
|
+
|
|
4
|
+
class UserService extends BaseService {
|
|
5
|
+
async getUsers(query?: { project_id?: number }): Promise<UserItem[]> {
|
|
6
|
+
return this.get<UserItem[]>('/api/users', { query })
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
async create(data: CreateUserPayload): Promise<{ id: number; tempPassword: string; email: string; name: string }> {
|
|
10
|
+
return this.post('/api/users', { body: data, skipDedup: true })
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async update(id: number, data: { is_active?: boolean; project_id?: number }): Promise<void> {
|
|
14
|
+
return this.put(`/api/users/${id}`, { body: data })
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async updateRoles(id: number, roles: RoleEntry[]): Promise<void> {
|
|
18
|
+
return this.put(`/api/users/${id}/roles`, { body: { roles } })
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async remove(id: number, projectId?: number): Promise<void> {
|
|
22
|
+
return this.delete(`/api/users/${id}`, {
|
|
23
|
+
query: projectId ? { project_id: projectId } : undefined,
|
|
24
|
+
})
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const userService = new UserService()
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export type WidgetType =
|
|
2
|
+
| 'stat-keys'
|
|
3
|
+
| 'stat-coverage'
|
|
4
|
+
| 'stat-languages'
|
|
5
|
+
| 'stat-unused'
|
|
6
|
+
| 'projects'
|
|
7
|
+
| 'languages-coverage'
|
|
8
|
+
| 'last-activity'
|
|
9
|
+
| 'review-queue'
|
|
10
|
+
|
|
11
|
+
export type WidgetSize = 'sm' | 'md' | 'lg' | 'wide' | 'xl'
|
|
12
|
+
|
|
13
|
+
export type DataSourceType = 'global' | 'project'
|
|
14
|
+
|
|
15
|
+
export interface WidgetDataSource {
|
|
16
|
+
type: DataSourceType
|
|
17
|
+
projectId?: number // only when type === 'project'
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface WidgetConfig {
|
|
21
|
+
id: string
|
|
22
|
+
type: WidgetType
|
|
23
|
+
size: WidgetSize
|
|
24
|
+
dataSource?: WidgetDataSource // default = 'global'
|
|
25
|
+
title?: string // optional custom title override
|
|
26
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { resolve } from 'path'
|
|
2
|
+
import { existsSync } from 'fs'
|
|
3
|
+
|
|
4
|
+
export async function loadUserConfig() {
|
|
5
|
+
const configPath = resolve(process.cwd(), 'i18n-dashboard.config.js')
|
|
6
|
+
const configPathMjs = resolve(process.cwd(), 'i18n-dashboard.config.mjs')
|
|
7
|
+
|
|
8
|
+
if (existsSync(configPath)) {
|
|
9
|
+
try {
|
|
10
|
+
const mod = await import(configPath)
|
|
11
|
+
|
|
12
|
+
return mod.default || mod
|
|
13
|
+
} catch (e) {
|
|
14
|
+
console.warn('Warning: Could not load i18n-dashboard.config.js:', e.message)
|
|
15
|
+
}
|
|
16
|
+
} else if (existsSync(configPathMjs)) {
|
|
17
|
+
try {
|
|
18
|
+
const mod = await import(configPathMjs)
|
|
19
|
+
|
|
20
|
+
return mod.default || mod
|
|
21
|
+
} catch (e) {
|
|
22
|
+
console.warn('Warning: Could not load i18n-dashboard.config.mjs:', e.message)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return {}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function buildEnv(config) {
|
|
30
|
+
const env = { ...process.env }
|
|
31
|
+
|
|
32
|
+
if (config.port) env.I18N_PORT = String(config.port)
|
|
33
|
+
if (config.keySeparator) env.I18N_KEY_SEPARATOR = config.keySeparator
|
|
34
|
+
if (config.localesPath) env.I18N_LOCALES_PATH = config.localesPath
|
|
35
|
+
if (config.apiPath) env.I18N_API_PATH = config.apiPath
|
|
36
|
+
|
|
37
|
+
// Project root: explicit config > process.cwd()
|
|
38
|
+
env.I18N_PROJECT_ROOT = config.projectRoot
|
|
39
|
+
? resolve(config.projectRoot)
|
|
40
|
+
: process.cwd()
|
|
41
|
+
|
|
42
|
+
if (config.database) {
|
|
43
|
+
if (config.database.client) env.I18N_DB_CLIENT = config.database.client
|
|
44
|
+
if (config.database.connection) {
|
|
45
|
+
if (typeof config.database.connection === 'string') {
|
|
46
|
+
env.I18N_DB_CONNECTION = config.database.connection
|
|
47
|
+
} else {
|
|
48
|
+
if (config.database.connection.host) env.I18N_DB_HOST = config.database.connection.host
|
|
49
|
+
if (config.database.connection.port) env.I18N_DB_PORT = String(config.database.connection.port)
|
|
50
|
+
if (config.database.connection.user) env.I18N_DB_USER = config.database.connection.user
|
|
51
|
+
if (config.database.connection.password) env.I18N_DB_PASSWORD = config.database.connection.password
|
|
52
|
+
if (config.database.connection.database) env.I18N_DB_NAME = config.database.connection.database
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (config.googleTranslate?.apiKey) env.GOOGLE_TRANSLATE_API_KEY = config.googleTranslate.apiKey
|
|
58
|
+
|
|
59
|
+
return env
|
|
60
|
+
}
|