@lastbrain/app 2.0.18 → 2.0.21
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/dist/app-shell/not-found.js +2 -2
- package/dist/components/LanguageSwitcher.d.ts +7 -0
- package/dist/components/LanguageSwitcher.d.ts.map +1 -0
- package/dist/components/LanguageSwitcher.js +62 -0
- package/dist/config/version.d.ts.map +1 -1
- package/dist/config/version.js +19 -21
- package/dist/i18n/LanguageProvider.d.ts +4 -0
- package/dist/i18n/LanguageProvider.d.ts.map +1 -0
- package/dist/i18n/LanguageProvider.js +6 -0
- package/dist/i18n/TranslationsScript.d.ts +8 -0
- package/dist/i18n/TranslationsScript.d.ts.map +1 -0
- package/dist/i18n/TranslationsScript.js +10 -0
- package/dist/i18n/cookies.d.ts +6 -0
- package/dist/i18n/cookies.d.ts.map +1 -0
- package/dist/i18n/cookies.js +24 -0
- package/dist/i18n/langHrefHelper.d.ts +36 -0
- package/dist/i18n/langHrefHelper.d.ts.map +1 -0
- package/dist/i18n/langHrefHelper.js +41 -0
- package/dist/i18n/server-helpers.d.ts +33 -0
- package/dist/i18n/server-helpers.d.ts.map +1 -0
- package/dist/i18n/server-helpers.js +39 -0
- package/dist/i18n/server-lang.d.ts +10 -0
- package/dist/i18n/server-lang.d.ts.map +1 -0
- package/dist/i18n/server-lang.js +42 -0
- package/dist/i18n/server.d.ts +10 -0
- package/dist/i18n/server.d.ts.map +1 -0
- package/dist/i18n/server.js +8 -0
- package/dist/i18n/types.d.ts +38 -0
- package/dist/i18n/types.d.ts.map +1 -0
- package/dist/i18n/types.js +4 -0
- package/dist/i18n/useLangRouter.d.ts +12 -0
- package/dist/i18n/useLangRouter.d.ts.map +1 -0
- package/dist/i18n/useLangRouter.js +18 -0
- package/dist/i18n/useLink.d.ts +34 -0
- package/dist/i18n/useLink.d.ts.map +1 -0
- package/dist/i18n/useLink.js +58 -0
- package/dist/i18n/useModuleTranslation.d.ts +11 -0
- package/dist/i18n/useModuleTranslation.d.ts.map +1 -0
- package/dist/i18n/useModuleTranslation.js +23 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/layouts/AdminLayout.js +1 -1
- package/dist/layouts/AppProviders.d.ts +4 -1
- package/dist/layouts/AppProviders.d.ts.map +1 -1
- package/dist/layouts/AppProviders.js +18 -8
- package/dist/layouts/AuthLayout.js +1 -1
- package/dist/layouts/AuthLayoutWithSidebar.d.ts.map +1 -1
- package/dist/layouts/AuthLayoutWithSidebar.js +5 -3
- package/dist/layouts/RootLayout.d.ts +4 -1
- package/dist/layouts/RootLayout.d.ts.map +1 -1
- package/dist/layouts/RootLayout.js +2 -2
- package/dist/scripts/i18n-build.d.ts +7 -0
- package/dist/scripts/i18n-build.d.ts.map +1 -0
- package/dist/scripts/i18n-build.js +100 -0
- package/dist/scripts/init-app.js +12 -12
- package/dist/scripts/module-build.d.ts.map +1 -1
- package/dist/scripts/module-build.js +384 -81
- package/dist/styles.css +1 -1
- package/dist/templates/DefaultDoc.d.ts.map +1 -1
- package/dist/templates/DefaultDoc.js +90 -2
- package/dist/templates/middleware-i18n.example.d.ts +16 -0
- package/dist/templates/middleware-i18n.example.d.ts.map +1 -0
- package/dist/templates/middleware-i18n.example.js +72 -0
- package/package.json +14 -3
- package/src/app-shell/not-found.tsx +2 -2
- package/src/components/LanguageSwitcher.tsx +156 -0
- package/src/config/version.ts +19 -21
- package/src/i18n/LanguageProvider.tsx +7 -0
- package/src/i18n/README_LANG_HELPERS.md +187 -0
- package/src/i18n/TranslationsScript.tsx +17 -0
- package/src/i18n/cookies.ts +24 -0
- package/src/i18n/langHrefHelper.ts +51 -0
- package/src/i18n/server-helpers.ts +48 -0
- package/src/i18n/server-lang.ts +51 -0
- package/src/i18n/server.ts +13 -0
- package/src/i18n/types.ts +39 -0
- package/src/i18n/useLangRouter.ts +21 -0
- package/src/i18n/useLink.ts +60 -0
- package/src/i18n/useModuleTranslation.ts +27 -0
- package/src/index.ts +20 -0
- package/src/layouts/AdminLayout.tsx +1 -1
- package/src/layouts/AppProviders.tsx +35 -16
- package/src/layouts/AuthLayout.tsx +1 -1
- package/src/layouts/AuthLayoutWithSidebar.tsx +5 -3
- package/src/layouts/RootLayout.tsx +12 -5
- package/src/scripts/i18n-build.ts +122 -0
- package/src/scripts/init-app.ts +12 -12
- package/src/scripts/module-build.ts +476 -94
- package/src/templates/DefaultDoc.tsx +511 -1
- package/src/templates/middleware-i18n.example.ts +92 -0
- package/dist/app-shell/(admin)/dashboard/page.d.ts +0 -2
- package/dist/app-shell/(admin)/dashboard/page.d.ts.map +0 -1
- package/dist/app-shell/(admin)/dashboard/page.js +0 -5
- package/dist/app-shell/(admin)/page.d.ts +0 -2
- package/dist/app-shell/(admin)/page.d.ts.map +0 -1
- package/dist/app-shell/(admin)/page.js +0 -5
- package/dist/app-shell/(auth)/dashboard/page.d.ts +0 -2
- package/dist/app-shell/(auth)/dashboard/page.d.ts.map +0 -1
- package/dist/app-shell/(auth)/dashboard/page.js +0 -5
- package/dist/app-shell/(auth)/page.d.ts +0 -2
- package/dist/app-shell/(auth)/page.d.ts.map +0 -1
- package/dist/app-shell/(auth)/page.js +0 -5
- package/dist/components/TableStructure.d.ts +0 -8
- package/dist/components/TableStructure.d.ts.map +0 -1
- package/dist/components/TableStructure.js +0 -37
- package/dist/hooks/useNotificationsSimple.d.ts +0 -20
- package/dist/hooks/useNotificationsSimple.d.ts.map +0 -1
- package/dist/hooks/useNotificationsSimple.js +0 -37
- package/dist/module-build.d.ts +0 -2
- package/dist/module-build.d.ts.map +0 -1
- package/dist/module-build.js +0 -50
- package/dist/modules/index.d.ts +0 -3
- package/dist/modules/index.d.ts.map +0 -1
- package/dist/modules/index.js +0 -2
- package/dist/src/__tests__/module-registry.test.d.ts +0 -2
- package/dist/src/__tests__/module-registry.test.d.ts.map +0 -1
- package/dist/src/__tests__/module-registry.test.js +0 -53
- package/dist/src/app-shell/(admin)/layout.d.ts +0 -4
- package/dist/src/app-shell/(admin)/layout.d.ts.map +0 -1
- package/dist/src/app-shell/(admin)/layout.js +0 -5
- package/dist/src/app-shell/(auth)/layout.d.ts +0 -4
- package/dist/src/app-shell/(auth)/layout.d.ts.map +0 -1
- package/dist/src/app-shell/(auth)/layout.js +0 -5
- package/dist/src/app-shell/(public)/page.d.ts +0 -2
- package/dist/src/app-shell/(public)/page.d.ts.map +0 -1
- package/dist/src/app-shell/(public)/page.js +0 -5
- package/dist/src/app-shell/layout.d.ts +0 -3
- package/dist/src/app-shell/layout.d.ts.map +0 -1
- package/dist/src/app-shell/layout.js +0 -3
- package/dist/src/app-shell/not-found.d.ts +0 -2
- package/dist/src/app-shell/not-found.d.ts.map +0 -1
- package/dist/src/app-shell/not-found.js +0 -10
- package/dist/src/auth/authHelpers.d.ts +0 -7
- package/dist/src/auth/authHelpers.d.ts.map +0 -1
- package/dist/src/auth/authHelpers.js +0 -19
- package/dist/src/auth/useAuthSession.d.ts +0 -7
- package/dist/src/auth/useAuthSession.d.ts.map +0 -1
- package/dist/src/auth/useAuthSession.js +0 -49
- package/dist/src/cli.d.ts +0 -3
- package/dist/src/cli.d.ts.map +0 -1
- package/dist/src/cli.js +0 -143
- package/dist/src/components/NotificationContainer.d.ts +0 -2
- package/dist/src/components/NotificationContainer.d.ts.map +0 -1
- package/dist/src/components/NotificationContainer.js +0 -8
- package/dist/src/hooks/useNotifications.d.ts +0 -30
- package/dist/src/hooks/useNotifications.d.ts.map +0 -1
- package/dist/src/hooks/useNotifications.js +0 -165
- package/dist/src/index.d.ts +0 -22
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/index.js +0 -22
- package/dist/src/layouts/AdminLayout.d.ts +0 -4
- package/dist/src/layouts/AdminLayout.d.ts.map +0 -1
- package/dist/src/layouts/AdminLayout.js +0 -4
- package/dist/src/layouts/AdminLayoutWithSidebar.d.ts +0 -10
- package/dist/src/layouts/AdminLayoutWithSidebar.d.ts.map +0 -1
- package/dist/src/layouts/AdminLayoutWithSidebar.js +0 -62
- package/dist/src/layouts/AppProviders.d.ts +0 -27
- package/dist/src/layouts/AppProviders.d.ts.map +0 -1
- package/dist/src/layouts/AppProviders.js +0 -48
- package/dist/src/layouts/AuthLayout.d.ts +0 -4
- package/dist/src/layouts/AuthLayout.d.ts.map +0 -1
- package/dist/src/layouts/AuthLayout.js +0 -4
- package/dist/src/layouts/AuthLayoutWithSidebar.d.ts +0 -12
- package/dist/src/layouts/AuthLayoutWithSidebar.d.ts.map +0 -1
- package/dist/src/layouts/AuthLayoutWithSidebar.js +0 -60
- package/dist/src/layouts/PublicLayout.d.ts +0 -8
- package/dist/src/layouts/PublicLayout.d.ts.map +0 -1
- package/dist/src/layouts/PublicLayout.js +0 -6
- package/dist/src/layouts/PublicLayoutWithSidebar.d.ts +0 -9
- package/dist/src/layouts/PublicLayoutWithSidebar.d.ts.map +0 -1
- package/dist/src/layouts/PublicLayoutWithSidebar.js +0 -60
- package/dist/src/layouts/RootLayout.d.ts +0 -6
- package/dist/src/layouts/RootLayout.d.ts.map +0 -1
- package/dist/src/layouts/RootLayout.js +0 -9
- package/dist/src/modules/module-loader.d.ts +0 -5
- package/dist/src/modules/module-loader.d.ts.map +0 -1
- package/dist/src/modules/module-loader.js +0 -10
- package/dist/src/scripts/db-init.d.ts +0 -2
- package/dist/src/scripts/db-init.d.ts.map +0 -1
- package/dist/src/scripts/db-init.js +0 -300
- package/dist/src/scripts/db-migrations-sync.d.ts +0 -2
- package/dist/src/scripts/db-migrations-sync.d.ts.map +0 -1
- package/dist/src/scripts/db-migrations-sync.js +0 -84
- package/dist/src/scripts/dev-sync.d.ts +0 -2
- package/dist/src/scripts/dev-sync.d.ts.map +0 -1
- package/dist/src/scripts/dev-sync.js +0 -194
- package/dist/src/scripts/init-app.d.ts +0 -12
- package/dist/src/scripts/init-app.d.ts.map +0 -1
- package/dist/src/scripts/init-app.js +0 -2175
- package/dist/src/scripts/module-add.d.ts +0 -2
- package/dist/src/scripts/module-add.d.ts.map +0 -1
- package/dist/src/scripts/module-add.js +0 -232
- package/dist/src/scripts/module-build.d.ts +0 -2
- package/dist/src/scripts/module-build.d.ts.map +0 -1
- package/dist/src/scripts/module-build.js +0 -1280
- package/dist/src/scripts/module-create.d.ts +0 -28
- package/dist/src/scripts/module-create.d.ts.map +0 -1
- package/dist/src/scripts/module-create.js +0 -1429
- package/dist/src/scripts/module-delete.d.ts +0 -6
- package/dist/src/scripts/module-delete.d.ts.map +0 -1
- package/dist/src/scripts/module-delete.js +0 -147
- package/dist/src/scripts/module-list.d.ts +0 -2
- package/dist/src/scripts/module-list.d.ts.map +0 -1
- package/dist/src/scripts/module-list.js +0 -61
- package/dist/src/scripts/module-remove.d.ts +0 -2
- package/dist/src/scripts/module-remove.d.ts.map +0 -1
- package/dist/src/scripts/module-remove.js +0 -311
- package/dist/src/scripts/readme-build.d.ts +0 -2
- package/dist/src/scripts/readme-build.d.ts.map +0 -1
- package/dist/src/scripts/readme-build.js +0 -39
- package/dist/src/scripts/script-runner.d.ts +0 -5
- package/dist/src/scripts/script-runner.d.ts.map +0 -1
- package/dist/src/scripts/script-runner.js +0 -25
- package/dist/src/templates/AuthGuidePage.d.ts +0 -2
- package/dist/src/templates/AuthGuidePage.d.ts.map +0 -1
- package/dist/src/templates/AuthGuidePage.js +0 -9
- package/dist/src/templates/DefaultDoc.d.ts +0 -2
- package/dist/src/templates/DefaultDoc.d.ts.map +0 -1
- package/dist/src/templates/DefaultDoc.js +0 -240
- package/dist/src/templates/DocPage.d.ts +0 -17
- package/dist/src/templates/DocPage.d.ts.map +0 -1
- package/dist/src/templates/DocPage.js +0 -193
- package/dist/src/templates/DocsPageWithModules.d.ts +0 -2
- package/dist/src/templates/DocsPageWithModules.d.ts.map +0 -1
- package/dist/src/templates/DocsPageWithModules.js +0 -8
- package/dist/src/templates/MigrationsGuidePage.d.ts +0 -2
- package/dist/src/templates/MigrationsGuidePage.d.ts.map +0 -1
- package/dist/src/templates/MigrationsGuidePage.js +0 -11
- package/dist/src/templates/ModuleGuidePage.d.ts +0 -2
- package/dist/src/templates/ModuleGuidePage.d.ts.map +0 -1
- package/dist/src/templates/ModuleGuidePage.js +0 -14
- package/dist/src/templates/SimpleDocPage.d.ts +0 -2
- package/dist/src/templates/SimpleDocPage.d.ts.map +0 -1
- package/dist/src/templates/SimpleDocPage.js +0 -28
- package/dist/src/templates/SimpleHomePage.d.ts +0 -6
- package/dist/src/templates/SimpleHomePage.d.ts.map +0 -1
- package/dist/src/templates/SimpleHomePage.js +0 -7
- package/dist/src/types/menu.d.ts +0 -23
- package/dist/src/types/menu.d.ts.map +0 -1
- package/dist/src/types/menu.js +0 -1
- package/dist/templates/HomePage.d.ts +0 -6
- package/dist/templates/HomePage.d.ts.map +0 -1
- package/dist/templates/HomePage.js +0 -6
- package/dist/templates/components/AppAside.d.ts +0 -6
- package/dist/templates/components/AppAside.d.ts.map +0 -1
- package/dist/templates/components/AppAside.js +0 -9
- package/dist/templates/layouts/admin-layout.d.ts +0 -4
- package/dist/templates/layouts/admin-layout.d.ts.map +0 -1
- package/dist/templates/layouts/admin-layout.js +0 -6
- package/dist/templates/layouts/auth-layout.d.ts +0 -4
- package/dist/templates/layouts/auth-layout.d.ts.map +0 -1
- package/dist/templates/layouts/auth-layout.js +0 -6
- package/dist/templates/migrations/20201010100000_init.sql +0 -123
|
@@ -10,6 +10,19 @@ const _monorepoRoot = projectRoot.includes("/apps/")
|
|
|
10
10
|
const appDirectory = path.join(projectRoot, "app");
|
|
11
11
|
// Mode debug activé via --debug
|
|
12
12
|
const isDebugMode = process.argv.includes("--debug");
|
|
13
|
+
// Helper pour écrire (générer ou mettre à jour) un fichier de scaffold
|
|
14
|
+
function ensureDirectory(dir) {
|
|
15
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
function writeScaffoldFile(targetPath, content, label) {
|
|
18
|
+
const existed = fs.existsSync(targetPath);
|
|
19
|
+
ensureDirectory(path.dirname(targetPath));
|
|
20
|
+
fs.writeFileSync(targetPath, content, "utf-8");
|
|
21
|
+
if (isDebugMode) {
|
|
22
|
+
const status = existed ? "♻️ Updated" : "✅ Generated";
|
|
23
|
+
console.log(`${status} ${label}: ${targetPath}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
13
26
|
// Créer un require dans le contexte de l'application pour résoudre les modules installés dans l'app
|
|
14
27
|
const projectRequire = createRequire(path.join(projectRoot, "package.json"));
|
|
15
28
|
// Charger les modules depuis modules.json
|
|
@@ -70,10 +83,10 @@ async function loadModuleConfigs() {
|
|
|
70
83
|
return moduleConfigs;
|
|
71
84
|
}
|
|
72
85
|
const sectionDirectoryMap = {
|
|
73
|
-
public: ["(public)"],
|
|
74
|
-
auth: ["auth"],
|
|
75
|
-
admin: ["admin"],
|
|
76
|
-
user: ["auth", "user"],
|
|
86
|
+
public: ["[lang]", "(public)"],
|
|
87
|
+
auth: ["[lang]", "auth"],
|
|
88
|
+
admin: ["[lang]", "admin"],
|
|
89
|
+
user: ["[lang]", "auth", "user"],
|
|
77
90
|
};
|
|
78
91
|
const sectionLayoutMap = {
|
|
79
92
|
auth: "AuthLayout",
|
|
@@ -87,9 +100,6 @@ const navigation = {
|
|
|
87
100
|
admin: [],
|
|
88
101
|
};
|
|
89
102
|
const userMenu = [];
|
|
90
|
-
function ensureDirectory(dir) {
|
|
91
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
92
|
-
}
|
|
93
103
|
function ensureSectionLayout(sectionPath) {
|
|
94
104
|
const sectionDir = path.join(appDirectory, ...sectionPath);
|
|
95
105
|
const sectionKey = sectionPath[0];
|
|
@@ -101,16 +111,13 @@ function ensureSectionLayout(sectionPath) {
|
|
|
101
111
|
const layoutName = sectionLayoutMap[sectionKey];
|
|
102
112
|
if (layoutName) {
|
|
103
113
|
const layoutPath = path.join(sectionDir, "layout.tsx");
|
|
104
|
-
|
|
105
|
-
|
|
114
|
+
const layoutContent = `import { ${layoutName} } from "@lastbrain/app";
|
|
115
|
+
import type React from "react";
|
|
106
116
|
|
|
107
117
|
export default function SectionLayout({ children }: { children: React.ReactNode }) {
|
|
108
118
|
return <${layoutName}>{children}</${layoutName}>;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
fs.writeFileSync(layoutPath, layoutContent);
|
|
112
|
-
console.log(`📐 Generated section layout: ${layoutPath}`);
|
|
113
|
-
}
|
|
119
|
+
}`;
|
|
120
|
+
writeScaffoldFile(layoutPath, layoutContent, `${sectionKey} layout`);
|
|
114
121
|
}
|
|
115
122
|
generatedSections.add(sectionKey);
|
|
116
123
|
}
|
|
@@ -165,7 +172,9 @@ function buildPage(moduleConfig, page) {
|
|
|
165
172
|
: "Root";
|
|
166
173
|
const wrapperName = `${page.componentExport}${wrapperSuffix}Route`;
|
|
167
174
|
// Vérifier si la route a des paramètres dynamiques (segments avec [])
|
|
168
|
-
|
|
175
|
+
// Inclure les segments du sectionPath (ex: [lang]) ET les segments du module
|
|
176
|
+
const allSegments = [...sectionPath, ...segments];
|
|
177
|
+
const hasDynamicParams = allSegments.some((seg) => seg.startsWith("[") && seg.endsWith("]"));
|
|
169
178
|
// Pour les pages publiques (signin, signup, etc.), utiliser dynamic import sans SSR
|
|
170
179
|
// pour éviter les erreurs d'hydratation avec les IDs HeroUI/React Aria
|
|
171
180
|
const isPublicAuthPage = page.section === "public" &&
|
|
@@ -193,7 +202,7 @@ interface UserPageProps { params: Promise<{ id: string }> }
|
|
|
193
202
|
async function getModuleUserTabs() {
|
|
194
203
|
try {
|
|
195
204
|
// Depuis /app/admin/auth/users/[id]/ vers /apps/test-01/config/user-tabs
|
|
196
|
-
const { moduleUserTabs } = await import("
|
|
205
|
+
const { moduleUserTabs } = await import("../../../../../../config/user-tabs");
|
|
197
206
|
return moduleUserTabs || [];
|
|
198
207
|
} catch (e) {
|
|
199
208
|
console.warn("[user-detail-wrapper] erreur chargement user-tabs", e);
|
|
@@ -240,11 +249,29 @@ export default function ${wrapperName}${hasDynamicParams ? "(props: Record<strin
|
|
|
240
249
|
const importPath = page.entryPoint
|
|
241
250
|
? `${moduleConfig.moduleName}/${page.entryPoint}`
|
|
242
251
|
: moduleConfig.moduleName;
|
|
252
|
+
// Extraire les noms des paramètres dynamiques pour le typage
|
|
253
|
+
// Inclure les segments du sectionPath (ex: [lang]) ET les segments du module
|
|
254
|
+
const allSegments = [...sectionPath, ...segments];
|
|
255
|
+
const dynamicParamNames = allSegments
|
|
256
|
+
.filter((seg) => seg.startsWith("[") && seg.endsWith("]"))
|
|
257
|
+
.map((seg) => seg.slice(1, -1)); // Enlève les []
|
|
258
|
+
// Générer le type des params si nécessaire
|
|
259
|
+
const paramsType = dynamicParamNames.length > 0
|
|
260
|
+
? `{ ${dynamicParamNames.map((name) => `${name}: string`).join("; ")} }`
|
|
261
|
+
: "";
|
|
262
|
+
const propsSignature = hasDynamicParams && paramsType
|
|
263
|
+
? `({\n params,\n}: {\n params: Promise<${paramsType}>;\n})`
|
|
264
|
+
: "()";
|
|
265
|
+
// Les composants utilisent useParams() en interne, on ne passe jamais params en props
|
|
266
|
+
// On fait juste l'unwrap pour Next.js 15 si des params existent
|
|
267
|
+
const awaitParams = hasDynamicParams
|
|
268
|
+
? "await params; // Unwrap params for Next.js 15\n "
|
|
269
|
+
: "";
|
|
243
270
|
content = `// GENERATED BY LASTBRAIN MODULE BUILD
|
|
244
271
|
import { ${page.componentExport} } from "${importPath}";
|
|
245
272
|
${page.metadataExport ? `\nexport { ${page.metadataExport} as generateMetadata } from "${importPath}";\n` : ""}
|
|
246
|
-
export default
|
|
247
|
-
return <${page.componentExport}
|
|
273
|
+
export default ${hasDynamicParams ? "async " : ""}function ${wrapperName}${propsSignature} {
|
|
274
|
+
${awaitParams}return <${page.componentExport} />;
|
|
248
275
|
}
|
|
249
276
|
`;
|
|
250
277
|
}
|
|
@@ -345,7 +372,7 @@ function generateMenuConfig(moduleConfigs) {
|
|
|
345
372
|
// Fonction pour préparer les menus avec les composants
|
|
346
373
|
const prepareMenusForExport = (menus) => {
|
|
347
374
|
return menus.map((menu) => {
|
|
348
|
-
const { moduleName, __componentRef, ...cleanMenu } = menu;
|
|
375
|
+
const { moduleName: _moduleName, __componentRef, ...cleanMenu } = menu;
|
|
349
376
|
if (__componentRef) {
|
|
350
377
|
// Retourner une référence au composant au lieu de la sérialiser
|
|
351
378
|
return `{ ...${JSON.stringify(cleanMenu)}, component: ${__componentRef} }`;
|
|
@@ -554,10 +581,12 @@ function buildGroupedApi(apis, routePath) {
|
|
|
554
581
|
const exportsBySource = new Map();
|
|
555
582
|
apis.forEach(({ moduleConfig, api }) => {
|
|
556
583
|
const handler = `${moduleConfig.moduleName}/${api.entryPoint}`;
|
|
557
|
-
|
|
558
|
-
|
|
584
|
+
const currentExports = exportsBySource.get(handler);
|
|
585
|
+
if (currentExports) {
|
|
586
|
+
currentExports.push(api.handlerExport);
|
|
587
|
+
return;
|
|
559
588
|
}
|
|
560
|
-
exportsBySource.
|
|
589
|
+
exportsBySource.set(handler, [api.handlerExport]);
|
|
561
590
|
});
|
|
562
591
|
// Générer les exports - un export statement par source
|
|
563
592
|
const exportStatements = [];
|
|
@@ -662,7 +691,7 @@ function cleanGeneratedFiles() {
|
|
|
662
691
|
}
|
|
663
692
|
};
|
|
664
693
|
// Nettoyer les dossiers de sections
|
|
665
|
-
const sectionsToClean = ["(public)", "auth", "admin", "api"];
|
|
694
|
+
const sectionsToClean = ["(public)", "auth", "admin", "api", "[lang]"];
|
|
666
695
|
sectionsToClean.forEach((section) => {
|
|
667
696
|
const sectionPath = path.join(appDirectory, section);
|
|
668
697
|
if (fs.existsSync(sectionPath)) {
|
|
@@ -684,15 +713,55 @@ function cleanGeneratedFiles() {
|
|
|
684
713
|
console.log("🧹 Cleanup completed");
|
|
685
714
|
}
|
|
686
715
|
}
|
|
716
|
+
/**
|
|
717
|
+
* Supprime les anciennes routes sans [lang] et les layouts générés
|
|
718
|
+
*/
|
|
719
|
+
function cleanOldRoutesWithoutLang() {
|
|
720
|
+
const generatedComment = "// GENERATED BY LASTBRAIN MODULE BUILD";
|
|
721
|
+
// Supprimer les anciens dossiers de sections sans [lang]
|
|
722
|
+
const oldSections = ["(public)", "auth", "admin"];
|
|
723
|
+
oldSections.forEach((section) => {
|
|
724
|
+
const sectionPath = path.join(appDirectory, section);
|
|
725
|
+
if (fs.existsSync(sectionPath)) {
|
|
726
|
+
try {
|
|
727
|
+
// Supprimer récursivement tout le dossier
|
|
728
|
+
fs.rmSync(sectionPath, { recursive: true, force: true });
|
|
729
|
+
if (isDebugMode) {
|
|
730
|
+
console.log(`🗑️ Removed old section without [lang]: ${section}`);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
catch (error) {
|
|
734
|
+
console.warn(`⚠️ Could not remove ${section}:`, error);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
});
|
|
738
|
+
// Supprimer les layouts générés dans [lang]
|
|
739
|
+
const langLayoutsToRemove = [
|
|
740
|
+
path.join(appDirectory, "[lang]", "layout.tsx"),
|
|
741
|
+
path.join(appDirectory, "[lang]", "auth", "layout.tsx"),
|
|
742
|
+
path.join(appDirectory, "[lang]", "admin", "layout.tsx"),
|
|
743
|
+
];
|
|
744
|
+
langLayoutsToRemove.forEach((layoutPath) => {
|
|
745
|
+
if (fs.existsSync(layoutPath)) {
|
|
746
|
+
try {
|
|
747
|
+
const content = fs.readFileSync(layoutPath, "utf-8");
|
|
748
|
+
// Supprimer si c'est un fichier généré
|
|
749
|
+
if (content.includes(generatedComment) ||
|
|
750
|
+
content.includes("AppProviders")) {
|
|
751
|
+
fs.unlinkSync(layoutPath);
|
|
752
|
+
if (isDebugMode) {
|
|
753
|
+
console.log(`🗑️ Removed generated layout: ${layoutPath}`);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
catch (error) {
|
|
758
|
+
console.warn(`⚠️ Could not remove layout ${layoutPath}:`, error);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
});
|
|
762
|
+
}
|
|
687
763
|
function generateAppAside() {
|
|
688
764
|
const targetPath = path.join(appDirectory, "components", "AppAside.tsx");
|
|
689
|
-
// Ne pas écraser si le fichier existe déjà
|
|
690
|
-
if (fs.existsSync(targetPath)) {
|
|
691
|
-
if (isDebugMode) {
|
|
692
|
-
console.log(`⏭️ AppAside already exists, skipping: ${targetPath}`);
|
|
693
|
-
}
|
|
694
|
-
return;
|
|
695
|
-
}
|
|
696
765
|
const templateContent = `"use client";
|
|
697
766
|
|
|
698
767
|
import { AppAside as UIAppAside } from "@lastbrain/app";
|
|
@@ -717,86 +786,236 @@ export function AppAside({ className = "", isVisible = true }: AppAsideProps) {
|
|
|
717
786
|
);
|
|
718
787
|
}`;
|
|
719
788
|
try {
|
|
720
|
-
|
|
721
|
-
fs.writeFileSync(targetPath, templateContent, "utf-8");
|
|
722
|
-
if (isDebugMode) {
|
|
723
|
-
console.log(`✅ Generated AppAside component: ${targetPath}`);
|
|
724
|
-
}
|
|
789
|
+
writeScaffoldFile(targetPath, templateContent, "AppAside component");
|
|
725
790
|
}
|
|
726
791
|
catch (error) {
|
|
727
792
|
console.error(`❌ Error generating AppAside component: ${error}`);
|
|
728
793
|
}
|
|
729
794
|
}
|
|
730
795
|
function generateLayouts() {
|
|
731
|
-
// Générer
|
|
732
|
-
const
|
|
733
|
-
|
|
734
|
-
|
|
796
|
+
// Générer ClientLayout wrapper client
|
|
797
|
+
const clientLayoutPath = path.join(appDirectory, "components", "ClientLayout.tsx");
|
|
798
|
+
const clientLayoutContent = `"use client";
|
|
799
|
+
|
|
800
|
+
import { HeroUIProvider } from "@heroui/system";
|
|
801
|
+
import { ThemeProvider } from "next-themes";
|
|
802
|
+
import { AppProviders } from "./AppProviders";
|
|
803
|
+
import { AppHeader } from "./AppHeader";
|
|
804
|
+
import type { ReactNode } from "react";
|
|
805
|
+
import { useLocalizedRouter, type Language } from "@lastbrain/core";
|
|
806
|
+
|
|
807
|
+
|
|
808
|
+
export function ClientLayout({
|
|
809
|
+
children,
|
|
810
|
+
lang = "fr",
|
|
811
|
+
translations = {},
|
|
812
|
+
}: {
|
|
813
|
+
children: ReactNode;
|
|
814
|
+
lang?: Language;
|
|
815
|
+
translations?: Record<string, string>;
|
|
816
|
+
}) {
|
|
817
|
+
const router = useLocalizedRouter();
|
|
818
|
+
|
|
819
|
+
return (
|
|
820
|
+
<HeroUIProvider navigate={router.push}>
|
|
821
|
+
<ThemeProvider
|
|
822
|
+
attribute="class"
|
|
823
|
+
defaultTheme="dark"
|
|
824
|
+
enableSystem={false}
|
|
825
|
+
storageKey="lastbrain-theme"
|
|
826
|
+
>
|
|
827
|
+
<AppProviders lang={lang} translations={translations}>
|
|
828
|
+
<AppHeader />
|
|
829
|
+
<div className="min-h-screen text-foreground bg-background">
|
|
830
|
+
{children}
|
|
831
|
+
</div>
|
|
832
|
+
</AppProviders>
|
|
833
|
+
</ThemeProvider>
|
|
834
|
+
</HeroUIProvider>
|
|
835
|
+
);
|
|
836
|
+
}`;
|
|
837
|
+
try {
|
|
838
|
+
writeScaffoldFile(clientLayoutPath, clientLayoutContent, "ClientLayout component");
|
|
839
|
+
}
|
|
840
|
+
catch (error) {
|
|
841
|
+
console.error(`❌ Error generating ClientLayout component: ${error}`);
|
|
842
|
+
}
|
|
843
|
+
// Générer AppProviders wrapper client
|
|
844
|
+
const appProvidersPath = path.join(appDirectory, "components", "AppProviders.tsx");
|
|
845
|
+
const appProvidersContent = `"use client";
|
|
846
|
+
|
|
847
|
+
import { AppProviders as BaseAppProviders } from "@lastbrain/app";
|
|
848
|
+
import { realtimeConfig } from "../../config/realtime";
|
|
849
|
+
import type { ReactNode } from "react";
|
|
850
|
+
import type { Language } from "@lastbrain/core";
|
|
851
|
+
|
|
852
|
+
export function AppProviders({
|
|
853
|
+
children,
|
|
854
|
+
lang = "fr",
|
|
855
|
+
translations = {},
|
|
856
|
+
}: {
|
|
857
|
+
children: ReactNode;
|
|
858
|
+
lang?: Language;
|
|
859
|
+
translations?: Record<string, string>;
|
|
860
|
+
}) {
|
|
861
|
+
return (
|
|
862
|
+
<BaseAppProviders
|
|
863
|
+
realtimeConfig={realtimeConfig}
|
|
864
|
+
lang={lang}
|
|
865
|
+
translations={translations}
|
|
866
|
+
>
|
|
867
|
+
{children}
|
|
868
|
+
</BaseAppProviders>
|
|
869
|
+
);
|
|
870
|
+
}`;
|
|
871
|
+
try {
|
|
872
|
+
writeScaffoldFile(appProvidersPath, appProvidersContent, "AppProviders component");
|
|
873
|
+
}
|
|
874
|
+
catch (error) {
|
|
875
|
+
console.error(`❌ Error generating AppProviders component: ${error}`);
|
|
876
|
+
}
|
|
877
|
+
// Générer AppHeader component
|
|
878
|
+
const appHeaderPath = path.join(appDirectory, "components", "AppHeader.tsx");
|
|
879
|
+
const appHeaderContent = `"use client";
|
|
880
|
+
|
|
881
|
+
import { Header } from "@lastbrain/ui";
|
|
882
|
+
import { LanguageSwitcher } from "@lastbrain/app";
|
|
735
883
|
import { menuConfig } from "../../config/menu";
|
|
736
884
|
|
|
737
|
-
export
|
|
885
|
+
export function AppHeader() {
|
|
886
|
+
return (
|
|
887
|
+
<Header
|
|
888
|
+
menuConfig={menuConfig}
|
|
889
|
+
languageSwitcher={<LanguageSwitcher variant="minimal" />}
|
|
890
|
+
/>
|
|
891
|
+
);
|
|
892
|
+
}`;
|
|
893
|
+
try {
|
|
894
|
+
writeScaffoldFile(appHeaderPath, appHeaderContent, "AppHeader component");
|
|
895
|
+
}
|
|
896
|
+
catch (error) {
|
|
897
|
+
console.error(`❌ Error generating AppHeader component: ${error}`);
|
|
898
|
+
}
|
|
899
|
+
// Générer layout [lang] pour la gestion i18n
|
|
900
|
+
const langLayoutPath = path.join(appDirectory, "[lang]", "layout.tsx");
|
|
901
|
+
if (!fs.existsSync(langLayoutPath)) {
|
|
902
|
+
const langLayoutContent = `import { loadTranslations } from "@lastbrain/app/i18n/server-lang";
|
|
903
|
+
import { ClientLayout } from "../../components/ClientLayout";
|
|
904
|
+
|
|
905
|
+
export default async function LangLayout({
|
|
738
906
|
children,
|
|
907
|
+
params,
|
|
739
908
|
}: {
|
|
740
909
|
children: React.ReactNode;
|
|
910
|
+
params: Promise<{ lang: string }>;
|
|
741
911
|
}) {
|
|
912
|
+
const { lang } = await params;
|
|
913
|
+
const validLang = lang === "en" || lang === "fr" ? lang : "fr";
|
|
914
|
+
|
|
915
|
+
// Charger les traductions pour cette langue
|
|
916
|
+
const translations = await loadTranslations(validLang);
|
|
917
|
+
|
|
742
918
|
return (
|
|
743
|
-
<
|
|
744
|
-
|
|
745
|
-
|
|
919
|
+
<ClientLayout lang={validLang} translations={translations}>
|
|
920
|
+
<div className="min-h-screen pt-16">
|
|
921
|
+
{children}
|
|
922
|
+
</div>
|
|
923
|
+
</ClientLayout>
|
|
746
924
|
);
|
|
747
925
|
}`;
|
|
748
926
|
try {
|
|
749
|
-
ensureDirectory(path.dirname(
|
|
750
|
-
fs.writeFileSync(
|
|
927
|
+
ensureDirectory(path.dirname(langLayoutPath));
|
|
928
|
+
fs.writeFileSync(langLayoutPath, langLayoutContent, "utf-8");
|
|
751
929
|
if (isDebugMode) {
|
|
752
|
-
console.log(`✅ Generated
|
|
930
|
+
console.log(`✅ Generated [lang] layout: ${langLayoutPath}`);
|
|
753
931
|
}
|
|
754
932
|
}
|
|
755
933
|
catch (error) {
|
|
756
|
-
console.error(`❌ Error generating
|
|
934
|
+
console.error(`❌ Error generating [lang] layout: ${error}`);
|
|
757
935
|
}
|
|
758
936
|
}
|
|
759
937
|
else if (isDebugMode) {
|
|
760
|
-
console.log(`⏭️
|
|
938
|
+
console.log(`⏭️ [lang] layout already exists, skipping: ${langLayoutPath}`);
|
|
939
|
+
}
|
|
940
|
+
// Générer layout auth avec sidebar
|
|
941
|
+
const authLayoutPath = path.join(appDirectory, "[lang]", "auth", "layout.tsx");
|
|
942
|
+
const authLayoutContent = `"use client";
|
|
943
|
+
|
|
944
|
+
import { AuthLayoutWithSidebar, langHref, useLanguage } from "@lastbrain/app";
|
|
945
|
+
import { menuConfig as fullMenuConfig } from "../../../config/menu";
|
|
946
|
+
|
|
947
|
+
export default function SectionLayout({
|
|
948
|
+
children,
|
|
949
|
+
}: {
|
|
950
|
+
children: React.ReactNode;
|
|
951
|
+
}) {
|
|
952
|
+
const { lang } = useLanguage();
|
|
953
|
+
|
|
954
|
+
// Transformer les paths du menu avec la langue
|
|
955
|
+
const menuConfig = {
|
|
956
|
+
...fullMenuConfig,
|
|
957
|
+
auth: (fullMenuConfig.auth || []).map(item => ({
|
|
958
|
+
...item,
|
|
959
|
+
path: item.path?.startsWith("/") && !item.path?.startsWith("/api/")
|
|
960
|
+
? langHref(item.path, lang)
|
|
961
|
+
: item.path
|
|
962
|
+
})),
|
|
963
|
+
};
|
|
964
|
+
|
|
965
|
+
return (
|
|
966
|
+
<AuthLayoutWithSidebar menuConfig={menuConfig}>
|
|
967
|
+
{children}
|
|
968
|
+
</AuthLayoutWithSidebar>
|
|
969
|
+
);
|
|
970
|
+
}`;
|
|
971
|
+
try {
|
|
972
|
+
writeScaffoldFile(authLayoutPath, authLayoutContent, "auth layout with sidebar");
|
|
973
|
+
}
|
|
974
|
+
catch (error) {
|
|
975
|
+
console.error(`❌ Error generating auth layout: ${error}`);
|
|
761
976
|
}
|
|
762
977
|
// Générer layout admin avec sidebar
|
|
763
|
-
const adminLayoutPath = path.join(appDirectory, "admin", "layout.tsx");
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
import {
|
|
978
|
+
const adminLayoutPath = path.join(appDirectory, "[lang]", "admin", "layout.tsx");
|
|
979
|
+
const adminLayoutContent = `"use client";
|
|
980
|
+
|
|
981
|
+
import { AdminLayoutWithSidebar, langHref, useLanguage } from "@lastbrain/app";
|
|
982
|
+
import { menuConfig as fullMenuConfig } from "../../../config/menu";
|
|
767
983
|
|
|
768
984
|
export default function AdminLayout({
|
|
769
985
|
children,
|
|
770
986
|
}: {
|
|
771
987
|
children: React.ReactNode;
|
|
772
988
|
}) {
|
|
989
|
+
const { lang } = useLanguage();
|
|
990
|
+
|
|
991
|
+
// Transformer les paths du menu avec la langue
|
|
992
|
+
const menuConfig = {
|
|
993
|
+
...fullMenuConfig,
|
|
994
|
+
admin: (fullMenuConfig.admin || []).map(item => ({
|
|
995
|
+
...item,
|
|
996
|
+
path: item.path?.startsWith("/") && !item.path?.startsWith("/api/")
|
|
997
|
+
? langHref(item.path, lang)
|
|
998
|
+
: item.path
|
|
999
|
+
})),
|
|
1000
|
+
};
|
|
1001
|
+
|
|
773
1002
|
return (
|
|
774
1003
|
<AdminLayoutWithSidebar menuConfig={menuConfig}>
|
|
775
1004
|
{children}
|
|
776
1005
|
</AdminLayoutWithSidebar>
|
|
777
1006
|
);
|
|
778
1007
|
}`;
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
fs.writeFileSync(adminLayoutPath, adminLayoutContent, "utf-8");
|
|
782
|
-
if (isDebugMode) {
|
|
783
|
-
console.log(`✅ Generated admin layout with sidebar: ${adminLayoutPath}`);
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
|
-
catch (error) {
|
|
787
|
-
console.error(`❌ Error generating admin layout: ${error}`);
|
|
788
|
-
}
|
|
1008
|
+
try {
|
|
1009
|
+
writeScaffoldFile(adminLayoutPath, adminLayoutContent, "admin layout with sidebar");
|
|
789
1010
|
}
|
|
790
|
-
|
|
791
|
-
console.
|
|
1011
|
+
catch (error) {
|
|
1012
|
+
console.error(`❌ Error generating admin layout: ${error}`);
|
|
792
1013
|
}
|
|
793
1014
|
}
|
|
794
1015
|
async function generateRealtimeConfig(moduleConfigs) {
|
|
795
1016
|
try {
|
|
796
1017
|
// Extraire les configurations realtime des modules
|
|
797
|
-
const realtimeConfigs = moduleConfigs
|
|
798
|
-
.filter((config) => config.realtime)
|
|
799
|
-
.map((config) => config.realtime);
|
|
1018
|
+
const realtimeConfigs = moduleConfigs.flatMap((config) => (config.realtime ? [config.realtime] : []));
|
|
800
1019
|
if (realtimeConfigs.length === 0) {
|
|
801
1020
|
console.log("⏭️ No realtime configuration found in modules");
|
|
802
1021
|
return;
|
|
@@ -846,8 +1065,7 @@ async function generateUserTabsConfig(moduleConfigs) {
|
|
|
846
1065
|
try {
|
|
847
1066
|
// Extraire les configurations user tabs des modules
|
|
848
1067
|
const userTabsConfigs = moduleConfigs
|
|
849
|
-
.
|
|
850
|
-
.flatMap((config) => config.userTabs.map((tab) => ({
|
|
1068
|
+
.flatMap((config) => (config.userTabs ?? []).map((tab) => ({
|
|
851
1069
|
...tab,
|
|
852
1070
|
moduleName: config.moduleName,
|
|
853
1071
|
})))
|
|
@@ -902,9 +1120,7 @@ async function generateUserTabsConfig(moduleConfigs) {
|
|
|
902
1120
|
async function generateBucketsConfig(moduleConfigs) {
|
|
903
1121
|
try {
|
|
904
1122
|
// Extraire les configurations storage des modules
|
|
905
|
-
const allBuckets = moduleConfigs
|
|
906
|
-
.filter((config) => config.storage?.buckets && config.storage.buckets.length > 0)
|
|
907
|
-
.flatMap((config) => config.storage.buckets);
|
|
1123
|
+
const allBuckets = moduleConfigs.flatMap((config) => config.storage?.buckets ?? []);
|
|
908
1124
|
if (allBuckets.length === 0) {
|
|
909
1125
|
console.log("⏭️ No storage buckets configuration found in modules");
|
|
910
1126
|
return;
|
|
@@ -1027,9 +1243,7 @@ export function isValidFileSize(bucketName: string, fileSize: number): boolean {
|
|
|
1027
1243
|
async function generateStorageProxyApi(moduleConfigs) {
|
|
1028
1244
|
try {
|
|
1029
1245
|
// Extraire les configurations storage des modules
|
|
1030
|
-
const allBuckets = moduleConfigs
|
|
1031
|
-
.filter((config) => config.storage?.buckets && config.storage.buckets.length > 0)
|
|
1032
|
-
.flatMap((config) => config.storage.buckets);
|
|
1246
|
+
const allBuckets = moduleConfigs.flatMap((config) => config.storage?.buckets ?? []);
|
|
1033
1247
|
if (allBuckets.length === 0) {
|
|
1034
1248
|
console.log("⏭️ No storage buckets found, skipping proxy API generation");
|
|
1035
1249
|
return;
|
|
@@ -1159,9 +1373,7 @@ export async function GET(
|
|
|
1159
1373
|
async function generateFooterConfig(moduleConfigs) {
|
|
1160
1374
|
try {
|
|
1161
1375
|
// Extraire tous les liens footer des modules
|
|
1162
|
-
const allFooterLinks = moduleConfigs
|
|
1163
|
-
.filter((config) => config.footer && config.footer.length > 0)
|
|
1164
|
-
.flatMap((config) => config.footer);
|
|
1376
|
+
const allFooterLinks = moduleConfigs.flatMap((config) => config.footer ?? []);
|
|
1165
1377
|
if (allFooterLinks.length === 0) {
|
|
1166
1378
|
console.log("⏭️ No footer links found, skipping footer config generation");
|
|
1167
1379
|
return;
|
|
@@ -1203,6 +1415,85 @@ export const footerConfig: FooterConfig = {
|
|
|
1203
1415
|
console.error("❌ Error generating footer config:", error);
|
|
1204
1416
|
}
|
|
1205
1417
|
}
|
|
1418
|
+
/**
|
|
1419
|
+
* Génère les fichiers i18n en concaténant les traductions des modules
|
|
1420
|
+
*/
|
|
1421
|
+
async function generateI18nFiles() {
|
|
1422
|
+
const appI18nDir = path.join(projectRoot, "i18n");
|
|
1423
|
+
const packagesDir = path.join(_monorepoRoot, "packages");
|
|
1424
|
+
const translations = {
|
|
1425
|
+
fr: {},
|
|
1426
|
+
en: {},
|
|
1427
|
+
};
|
|
1428
|
+
try {
|
|
1429
|
+
// Importer glob dynamiquement
|
|
1430
|
+
const { glob } = await import("glob");
|
|
1431
|
+
// Rechercher tous les fichiers i18n dans packages/**/src/i18n/*.json
|
|
1432
|
+
const pattern = path.join(packagesDir, "**/src/i18n/*.json");
|
|
1433
|
+
const files = await glob(pattern, {
|
|
1434
|
+
ignore: ["**/node_modules/**", "**/dist/**"],
|
|
1435
|
+
});
|
|
1436
|
+
if (isDebugMode) {
|
|
1437
|
+
console.log(`\n🔍 Found ${files.length} i18n files\n`);
|
|
1438
|
+
}
|
|
1439
|
+
for (const file of files) {
|
|
1440
|
+
const fileName = path.basename(file, ".json");
|
|
1441
|
+
const lang = fileName; // fr.json -> fr, en.json -> en
|
|
1442
|
+
if (!translations[lang]) {
|
|
1443
|
+
translations[lang] = {};
|
|
1444
|
+
}
|
|
1445
|
+
try {
|
|
1446
|
+
const content = JSON.parse(fs.readFileSync(file, "utf-8"));
|
|
1447
|
+
const moduleName = extractModuleNameFromPath(file);
|
|
1448
|
+
if (isDebugMode) {
|
|
1449
|
+
console.log(` ✓ ${moduleName} (${lang})`);
|
|
1450
|
+
}
|
|
1451
|
+
// Préfixer uniquement si la clé n'est pas déjà namespacée (avec ou sans suffixe -pro)
|
|
1452
|
+
const moduleNamespace = moduleName.replace(/-pro$/, "");
|
|
1453
|
+
for (const [key, value] of Object.entries(content)) {
|
|
1454
|
+
const keyRoot = key.split(".")[0];
|
|
1455
|
+
const isGenericNamespaced = keyRoot.startsWith("module-");
|
|
1456
|
+
const isAlreadyNamespaced = isGenericNamespaced ||
|
|
1457
|
+
key.startsWith(`${moduleName}.`) ||
|
|
1458
|
+
key.startsWith(`${moduleNamespace}.`);
|
|
1459
|
+
const normalizedKey = isAlreadyNamespaced
|
|
1460
|
+
? key
|
|
1461
|
+
: `${moduleNamespace}.${key}`;
|
|
1462
|
+
translations[lang][normalizedKey] = value;
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
catch (error) {
|
|
1466
|
+
console.warn(` ⚠️ Error reading ${file}:`, error);
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
// Créer le dossier i18n s'il n'existe pas
|
|
1470
|
+
ensureDirectory(appI18nDir);
|
|
1471
|
+
// Écrire les fichiers de traduction
|
|
1472
|
+
for (const [lang, content] of Object.entries(translations)) {
|
|
1473
|
+
const filePath = path.join(appI18nDir, `${lang}.json`);
|
|
1474
|
+
fs.writeFileSync(filePath, JSON.stringify(content, null, 2), "utf-8");
|
|
1475
|
+
const keyCount = Object.keys(content).length;
|
|
1476
|
+
if (isDebugMode) {
|
|
1477
|
+
console.log(`✅ Generated ${filePath} (${keyCount} keys)`);
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
catch (error) {
|
|
1482
|
+
console.error("❌ Error generating i18n files:", error);
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
/**
|
|
1486
|
+
* Extrait le nom du module depuis le chemin du fichier
|
|
1487
|
+
*/
|
|
1488
|
+
function extractModuleNameFromPath(filePath) {
|
|
1489
|
+
// packages/module-auth/src/i18n/fr.json -> module-auth
|
|
1490
|
+
const parts = filePath.split(path.sep);
|
|
1491
|
+
const packagesIndex = parts.indexOf("packages");
|
|
1492
|
+
if (packagesIndex !== -1 && packagesIndex < parts.length - 1) {
|
|
1493
|
+
return parts[packagesIndex + 1];
|
|
1494
|
+
}
|
|
1495
|
+
return "unknown";
|
|
1496
|
+
}
|
|
1206
1497
|
export async function runModuleBuild() {
|
|
1207
1498
|
ensureDirectory(appDirectory);
|
|
1208
1499
|
// Nettoyer les fichiers générés précédemment
|
|
@@ -1210,6 +1501,11 @@ export async function runModuleBuild() {
|
|
|
1210
1501
|
console.log("🧹 Cleaning previously generated files...");
|
|
1211
1502
|
}
|
|
1212
1503
|
cleanGeneratedFiles();
|
|
1504
|
+
// Supprimer les anciennes routes sans [lang]
|
|
1505
|
+
if (isDebugMode) {
|
|
1506
|
+
console.log("🗑️ Removing old routes without [lang]...");
|
|
1507
|
+
}
|
|
1508
|
+
cleanOldRoutesWithoutLang();
|
|
1213
1509
|
const moduleConfigs = await loadModuleConfigs();
|
|
1214
1510
|
if (isDebugMode) {
|
|
1215
1511
|
console.log(`🔍 Loaded ${moduleConfigs.length} module configurations`);
|
|
@@ -1231,10 +1527,12 @@ export async function runModuleBuild() {
|
|
|
1231
1527
|
const apisByPath = new Map();
|
|
1232
1528
|
moduleConfigs.forEach((moduleConfig) => {
|
|
1233
1529
|
moduleConfig.apis.forEach((api) => {
|
|
1234
|
-
|
|
1235
|
-
|
|
1530
|
+
const apisForPath = apisByPath.get(api.path);
|
|
1531
|
+
if (apisForPath) {
|
|
1532
|
+
apisForPath.push({ moduleConfig, api });
|
|
1533
|
+
return;
|
|
1236
1534
|
}
|
|
1237
|
-
apisByPath.
|
|
1535
|
+
apisByPath.set(api.path, [{ moduleConfig, api }]);
|
|
1238
1536
|
});
|
|
1239
1537
|
});
|
|
1240
1538
|
// Générer les fichiers de route groupés
|
|
@@ -1272,6 +1570,11 @@ export async function runModuleBuild() {
|
|
|
1272
1570
|
console.log("🦶 Generating footer configuration...");
|
|
1273
1571
|
}
|
|
1274
1572
|
await generateFooterConfig(moduleConfigs);
|
|
1573
|
+
// Générer les fichiers i18n
|
|
1574
|
+
if (isDebugMode) {
|
|
1575
|
+
console.log("🌍 Building i18n files...");
|
|
1576
|
+
}
|
|
1577
|
+
await generateI18nFiles();
|
|
1275
1578
|
// Message de succès final
|
|
1276
1579
|
if (!isDebugMode) {
|
|
1277
1580
|
console.log("\n✅ Module build completed successfully!");
|