@lastbrain/app 2.0.15 → 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/PublicLayout.d.ts.map +1 -1
- package/dist/layouts/PublicLayout.js +1 -1
- 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 +390 -83
- 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/PublicLayout.tsx +3 -1
- package/src/layouts/RootLayout.tsx +13 -6
- package/src/scripts/i18n-build.ts +122 -0
- package/src/scripts/init-app.ts +12 -12
- package/src/scripts/module-build.ts +483 -96
- 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);
|
|
@@ -236,11 +245,33 @@ export default function ${wrapperName}${hasDynamicParams ? "(props: Record<strin
|
|
|
236
245
|
`;
|
|
237
246
|
}
|
|
238
247
|
else {
|
|
248
|
+
// Déterminer le chemin d'import
|
|
249
|
+
const importPath = page.entryPoint
|
|
250
|
+
? `${moduleConfig.moduleName}/${page.entryPoint}`
|
|
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
|
+
: "";
|
|
239
270
|
content = `// GENERATED BY LASTBRAIN MODULE BUILD
|
|
240
|
-
import { ${page.componentExport} } from "${
|
|
241
|
-
|
|
242
|
-
export default
|
|
243
|
-
return <${page.componentExport}
|
|
271
|
+
import { ${page.componentExport} } from "${importPath}";
|
|
272
|
+
${page.metadataExport ? `\nexport { ${page.metadataExport} as generateMetadata } from "${importPath}";\n` : ""}
|
|
273
|
+
export default ${hasDynamicParams ? "async " : ""}function ${wrapperName}${propsSignature} {
|
|
274
|
+
${awaitParams}return <${page.componentExport} />;
|
|
244
275
|
}
|
|
245
276
|
`;
|
|
246
277
|
}
|
|
@@ -341,7 +372,7 @@ function generateMenuConfig(moduleConfigs) {
|
|
|
341
372
|
// Fonction pour préparer les menus avec les composants
|
|
342
373
|
const prepareMenusForExport = (menus) => {
|
|
343
374
|
return menus.map((menu) => {
|
|
344
|
-
const { moduleName, __componentRef, ...cleanMenu } = menu;
|
|
375
|
+
const { moduleName: _moduleName, __componentRef, ...cleanMenu } = menu;
|
|
345
376
|
if (__componentRef) {
|
|
346
377
|
// Retourner une référence au composant au lieu de la sérialiser
|
|
347
378
|
return `{ ...${JSON.stringify(cleanMenu)}, component: ${__componentRef} }`;
|
|
@@ -550,10 +581,12 @@ function buildGroupedApi(apis, routePath) {
|
|
|
550
581
|
const exportsBySource = new Map();
|
|
551
582
|
apis.forEach(({ moduleConfig, api }) => {
|
|
552
583
|
const handler = `${moduleConfig.moduleName}/${api.entryPoint}`;
|
|
553
|
-
|
|
554
|
-
|
|
584
|
+
const currentExports = exportsBySource.get(handler);
|
|
585
|
+
if (currentExports) {
|
|
586
|
+
currentExports.push(api.handlerExport);
|
|
587
|
+
return;
|
|
555
588
|
}
|
|
556
|
-
exportsBySource.
|
|
589
|
+
exportsBySource.set(handler, [api.handlerExport]);
|
|
557
590
|
});
|
|
558
591
|
// Générer les exports - un export statement par source
|
|
559
592
|
const exportStatements = [];
|
|
@@ -658,7 +691,7 @@ function cleanGeneratedFiles() {
|
|
|
658
691
|
}
|
|
659
692
|
};
|
|
660
693
|
// Nettoyer les dossiers de sections
|
|
661
|
-
const sectionsToClean = ["(public)", "auth", "admin", "api"];
|
|
694
|
+
const sectionsToClean = ["(public)", "auth", "admin", "api", "[lang]"];
|
|
662
695
|
sectionsToClean.forEach((section) => {
|
|
663
696
|
const sectionPath = path.join(appDirectory, section);
|
|
664
697
|
if (fs.existsSync(sectionPath)) {
|
|
@@ -680,15 +713,55 @@ function cleanGeneratedFiles() {
|
|
|
680
713
|
console.log("🧹 Cleanup completed");
|
|
681
714
|
}
|
|
682
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
|
+
}
|
|
683
763
|
function generateAppAside() {
|
|
684
764
|
const targetPath = path.join(appDirectory, "components", "AppAside.tsx");
|
|
685
|
-
// Ne pas écraser si le fichier existe déjà
|
|
686
|
-
if (fs.existsSync(targetPath)) {
|
|
687
|
-
if (isDebugMode) {
|
|
688
|
-
console.log(`⏭️ AppAside already exists, skipping: ${targetPath}`);
|
|
689
|
-
}
|
|
690
|
-
return;
|
|
691
|
-
}
|
|
692
765
|
const templateContent = `"use client";
|
|
693
766
|
|
|
694
767
|
import { AppAside as UIAppAside } from "@lastbrain/app";
|
|
@@ -713,86 +786,236 @@ export function AppAside({ className = "", isVisible = true }: AppAsideProps) {
|
|
|
713
786
|
);
|
|
714
787
|
}`;
|
|
715
788
|
try {
|
|
716
|
-
|
|
717
|
-
fs.writeFileSync(targetPath, templateContent, "utf-8");
|
|
718
|
-
if (isDebugMode) {
|
|
719
|
-
console.log(`✅ Generated AppAside component: ${targetPath}`);
|
|
720
|
-
}
|
|
789
|
+
writeScaffoldFile(targetPath, templateContent, "AppAside component");
|
|
721
790
|
}
|
|
722
791
|
catch (error) {
|
|
723
792
|
console.error(`❌ Error generating AppAside component: ${error}`);
|
|
724
793
|
}
|
|
725
794
|
}
|
|
726
795
|
function generateLayouts() {
|
|
727
|
-
// Générer
|
|
728
|
-
const
|
|
729
|
-
|
|
730
|
-
|
|
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";
|
|
731
883
|
import { menuConfig } from "../../config/menu";
|
|
732
884
|
|
|
733
|
-
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({
|
|
734
906
|
children,
|
|
907
|
+
params,
|
|
735
908
|
}: {
|
|
736
909
|
children: React.ReactNode;
|
|
910
|
+
params: Promise<{ lang: string }>;
|
|
737
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
|
+
|
|
738
918
|
return (
|
|
739
|
-
<
|
|
740
|
-
|
|
741
|
-
|
|
919
|
+
<ClientLayout lang={validLang} translations={translations}>
|
|
920
|
+
<div className="min-h-screen pt-16">
|
|
921
|
+
{children}
|
|
922
|
+
</div>
|
|
923
|
+
</ClientLayout>
|
|
742
924
|
);
|
|
743
925
|
}`;
|
|
744
926
|
try {
|
|
745
|
-
ensureDirectory(path.dirname(
|
|
746
|
-
fs.writeFileSync(
|
|
927
|
+
ensureDirectory(path.dirname(langLayoutPath));
|
|
928
|
+
fs.writeFileSync(langLayoutPath, langLayoutContent, "utf-8");
|
|
747
929
|
if (isDebugMode) {
|
|
748
|
-
console.log(`✅ Generated
|
|
930
|
+
console.log(`✅ Generated [lang] layout: ${langLayoutPath}`);
|
|
749
931
|
}
|
|
750
932
|
}
|
|
751
933
|
catch (error) {
|
|
752
|
-
console.error(`❌ Error generating
|
|
934
|
+
console.error(`❌ Error generating [lang] layout: ${error}`);
|
|
753
935
|
}
|
|
754
936
|
}
|
|
755
937
|
else if (isDebugMode) {
|
|
756
|
-
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}`);
|
|
757
976
|
}
|
|
758
977
|
// Générer layout admin avec sidebar
|
|
759
|
-
const adminLayoutPath = path.join(appDirectory, "admin", "layout.tsx");
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
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";
|
|
763
983
|
|
|
764
984
|
export default function AdminLayout({
|
|
765
985
|
children,
|
|
766
986
|
}: {
|
|
767
987
|
children: React.ReactNode;
|
|
768
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
|
+
|
|
769
1002
|
return (
|
|
770
1003
|
<AdminLayoutWithSidebar menuConfig={menuConfig}>
|
|
771
1004
|
{children}
|
|
772
1005
|
</AdminLayoutWithSidebar>
|
|
773
1006
|
);
|
|
774
1007
|
}`;
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
fs.writeFileSync(adminLayoutPath, adminLayoutContent, "utf-8");
|
|
778
|
-
if (isDebugMode) {
|
|
779
|
-
console.log(`✅ Generated admin layout with sidebar: ${adminLayoutPath}`);
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
catch (error) {
|
|
783
|
-
console.error(`❌ Error generating admin layout: ${error}`);
|
|
784
|
-
}
|
|
1008
|
+
try {
|
|
1009
|
+
writeScaffoldFile(adminLayoutPath, adminLayoutContent, "admin layout with sidebar");
|
|
785
1010
|
}
|
|
786
|
-
|
|
787
|
-
console.
|
|
1011
|
+
catch (error) {
|
|
1012
|
+
console.error(`❌ Error generating admin layout: ${error}`);
|
|
788
1013
|
}
|
|
789
1014
|
}
|
|
790
1015
|
async function generateRealtimeConfig(moduleConfigs) {
|
|
791
1016
|
try {
|
|
792
1017
|
// Extraire les configurations realtime des modules
|
|
793
|
-
const realtimeConfigs = moduleConfigs
|
|
794
|
-
.filter((config) => config.realtime)
|
|
795
|
-
.map((config) => config.realtime);
|
|
1018
|
+
const realtimeConfigs = moduleConfigs.flatMap((config) => (config.realtime ? [config.realtime] : []));
|
|
796
1019
|
if (realtimeConfigs.length === 0) {
|
|
797
1020
|
console.log("⏭️ No realtime configuration found in modules");
|
|
798
1021
|
return;
|
|
@@ -842,8 +1065,7 @@ async function generateUserTabsConfig(moduleConfigs) {
|
|
|
842
1065
|
try {
|
|
843
1066
|
// Extraire les configurations user tabs des modules
|
|
844
1067
|
const userTabsConfigs = moduleConfigs
|
|
845
|
-
.
|
|
846
|
-
.flatMap((config) => config.userTabs.map((tab) => ({
|
|
1068
|
+
.flatMap((config) => (config.userTabs ?? []).map((tab) => ({
|
|
847
1069
|
...tab,
|
|
848
1070
|
moduleName: config.moduleName,
|
|
849
1071
|
})))
|
|
@@ -898,9 +1120,7 @@ async function generateUserTabsConfig(moduleConfigs) {
|
|
|
898
1120
|
async function generateBucketsConfig(moduleConfigs) {
|
|
899
1121
|
try {
|
|
900
1122
|
// Extraire les configurations storage des modules
|
|
901
|
-
const allBuckets = moduleConfigs
|
|
902
|
-
.filter((config) => config.storage?.buckets && config.storage.buckets.length > 0)
|
|
903
|
-
.flatMap((config) => config.storage.buckets);
|
|
1123
|
+
const allBuckets = moduleConfigs.flatMap((config) => config.storage?.buckets ?? []);
|
|
904
1124
|
if (allBuckets.length === 0) {
|
|
905
1125
|
console.log("⏭️ No storage buckets configuration found in modules");
|
|
906
1126
|
return;
|
|
@@ -1023,9 +1243,7 @@ export function isValidFileSize(bucketName: string, fileSize: number): boolean {
|
|
|
1023
1243
|
async function generateStorageProxyApi(moduleConfigs) {
|
|
1024
1244
|
try {
|
|
1025
1245
|
// Extraire les configurations storage des modules
|
|
1026
|
-
const allBuckets = moduleConfigs
|
|
1027
|
-
.filter((config) => config.storage?.buckets && config.storage.buckets.length > 0)
|
|
1028
|
-
.flatMap((config) => config.storage.buckets);
|
|
1246
|
+
const allBuckets = moduleConfigs.flatMap((config) => config.storage?.buckets ?? []);
|
|
1029
1247
|
if (allBuckets.length === 0) {
|
|
1030
1248
|
console.log("⏭️ No storage buckets found, skipping proxy API generation");
|
|
1031
1249
|
return;
|
|
@@ -1155,9 +1373,7 @@ export async function GET(
|
|
|
1155
1373
|
async function generateFooterConfig(moduleConfigs) {
|
|
1156
1374
|
try {
|
|
1157
1375
|
// Extraire tous les liens footer des modules
|
|
1158
|
-
const allFooterLinks = moduleConfigs
|
|
1159
|
-
.filter((config) => config.footer && config.footer.length > 0)
|
|
1160
|
-
.flatMap((config) => config.footer);
|
|
1376
|
+
const allFooterLinks = moduleConfigs.flatMap((config) => config.footer ?? []);
|
|
1161
1377
|
if (allFooterLinks.length === 0) {
|
|
1162
1378
|
console.log("⏭️ No footer links found, skipping footer config generation");
|
|
1163
1379
|
return;
|
|
@@ -1199,6 +1415,85 @@ export const footerConfig: FooterConfig = {
|
|
|
1199
1415
|
console.error("❌ Error generating footer config:", error);
|
|
1200
1416
|
}
|
|
1201
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
|
+
}
|
|
1202
1497
|
export async function runModuleBuild() {
|
|
1203
1498
|
ensureDirectory(appDirectory);
|
|
1204
1499
|
// Nettoyer les fichiers générés précédemment
|
|
@@ -1206,6 +1501,11 @@ export async function runModuleBuild() {
|
|
|
1206
1501
|
console.log("🧹 Cleaning previously generated files...");
|
|
1207
1502
|
}
|
|
1208
1503
|
cleanGeneratedFiles();
|
|
1504
|
+
// Supprimer les anciennes routes sans [lang]
|
|
1505
|
+
if (isDebugMode) {
|
|
1506
|
+
console.log("🗑️ Removing old routes without [lang]...");
|
|
1507
|
+
}
|
|
1508
|
+
cleanOldRoutesWithoutLang();
|
|
1209
1509
|
const moduleConfigs = await loadModuleConfigs();
|
|
1210
1510
|
if (isDebugMode) {
|
|
1211
1511
|
console.log(`🔍 Loaded ${moduleConfigs.length} module configurations`);
|
|
@@ -1227,10 +1527,12 @@ export async function runModuleBuild() {
|
|
|
1227
1527
|
const apisByPath = new Map();
|
|
1228
1528
|
moduleConfigs.forEach((moduleConfig) => {
|
|
1229
1529
|
moduleConfig.apis.forEach((api) => {
|
|
1230
|
-
|
|
1231
|
-
|
|
1530
|
+
const apisForPath = apisByPath.get(api.path);
|
|
1531
|
+
if (apisForPath) {
|
|
1532
|
+
apisForPath.push({ moduleConfig, api });
|
|
1533
|
+
return;
|
|
1232
1534
|
}
|
|
1233
|
-
apisByPath.
|
|
1535
|
+
apisByPath.set(api.path, [{ moduleConfig, api }]);
|
|
1234
1536
|
});
|
|
1235
1537
|
});
|
|
1236
1538
|
// Générer les fichiers de route groupés
|
|
@@ -1268,6 +1570,11 @@ export async function runModuleBuild() {
|
|
|
1268
1570
|
console.log("🦶 Generating footer configuration...");
|
|
1269
1571
|
}
|
|
1270
1572
|
await generateFooterConfig(moduleConfigs);
|
|
1573
|
+
// Générer les fichiers i18n
|
|
1574
|
+
if (isDebugMode) {
|
|
1575
|
+
console.log("🌍 Building i18n files...");
|
|
1576
|
+
}
|
|
1577
|
+
await generateI18nFiles();
|
|
1271
1578
|
// Message de succès final
|
|
1272
1579
|
if (!isDebugMode) {
|
|
1273
1580
|
console.log("\n✅ Module build completed successfully!");
|