@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
|
@@ -34,7 +34,7 @@ export function DefaultDocumentation() {
|
|
|
34
34
|
avec système de modules, authentification et base de données.
|
|
35
35
|
</p>
|
|
36
36
|
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
37
|
-
<strong>
|
|
37
|
+
<strong>Requirements</strong>
|
|
38
38
|
</p>
|
|
39
39
|
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
40
40
|
!
|
|
@@ -2024,6 +2024,516 @@ export function DocUsageCustom() {
|
|
|
2024
2024
|
</div>
|
|
2025
2025
|
</CardBody>
|
|
2026
2026
|
</Card>
|
|
2027
|
+
|
|
2028
|
+
<Card id="section-i18n" className="scroll-mt-32">
|
|
2029
|
+
<CardHeader>
|
|
2030
|
+
<h2 className="text-2xl font-semibold flex items-center gap-2">
|
|
2031
|
+
<FileText size={24} />
|
|
2032
|
+
Système de traduction i18n
|
|
2033
|
+
</h2>
|
|
2034
|
+
</CardHeader>
|
|
2035
|
+
<CardBody className="space-y-4">
|
|
2036
|
+
<h3 className="text-lg font-semibold mb-2">Vue d'ensemble</h3>
|
|
2037
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2038
|
+
LastBrain intègre un système de traduction automatique qui :
|
|
2039
|
+
</p>
|
|
2040
|
+
<div className="space-y-2">
|
|
2041
|
+
<div className="flex items-start gap-2">
|
|
2042
|
+
<span className="text-green-600">✅</span>
|
|
2043
|
+
<span>Collecte les traductions de tous les modules</span>
|
|
2044
|
+
</div>
|
|
2045
|
+
<div className="flex items-start gap-2">
|
|
2046
|
+
<span className="text-green-600">✅</span>
|
|
2047
|
+
<span>Les concatène dans l'application</span>
|
|
2048
|
+
</div>
|
|
2049
|
+
<div className="flex items-start gap-2">
|
|
2050
|
+
<span className="text-green-600">✅</span>
|
|
2051
|
+
<span>Permet l'accès aux traductions côté client et serveur</span>
|
|
2052
|
+
</div>
|
|
2053
|
+
<div className="flex items-start gap-2">
|
|
2054
|
+
<span className="text-green-600">✅</span>
|
|
2055
|
+
<span>Gère le changement de langue via cookies</span>
|
|
2056
|
+
</div>
|
|
2057
|
+
</div>
|
|
2058
|
+
<h3 className="text-lg font-semibold mb-2">Structure</h3>
|
|
2059
|
+
<h4 className="font-medium mb-2">Dans les modules</h4>
|
|
2060
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2061
|
+
Chaque module peut définir ses traductions dans{" "}
|
|
2062
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2063
|
+
src/i18n/
|
|
2064
|
+
</code>{" "}
|
|
2065
|
+
:
|
|
2066
|
+
</p>
|
|
2067
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2068
|
+
packages/module-auth/
|
|
2069
|
+
</p>
|
|
2070
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2071
|
+
src/
|
|
2072
|
+
</p>
|
|
2073
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2074
|
+
i18n/
|
|
2075
|
+
</p>
|
|
2076
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2077
|
+
fr.json
|
|
2078
|
+
</p>
|
|
2079
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2080
|
+
en.json
|
|
2081
|
+
</p>
|
|
2082
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2083
|
+
<strong>Exemple fr.json</strong> :
|
|
2084
|
+
</p>
|
|
2085
|
+
<Alert hideIcon color="primary" className="p-4 mb-4">
|
|
2086
|
+
<pre className="whitespace-pre-wrap">{`{
|
|
2087
|
+
"welcome": "Bienvenue",
|
|
2088
|
+
"signin": "Se connecter",
|
|
2089
|
+
"signout": "Se déconnecter"
|
|
2090
|
+
}`}</pre>
|
|
2091
|
+
</Alert>
|
|
2092
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2093
|
+
<strong>Exemple en.json</strong> :
|
|
2094
|
+
</p>
|
|
2095
|
+
<Alert hideIcon color="primary" className="p-4 mb-4">
|
|
2096
|
+
<pre className="whitespace-pre-wrap">{`{
|
|
2097
|
+
"welcome": "Welcome",
|
|
2098
|
+
"signin": "Sign in",
|
|
2099
|
+
"signout": "Sign out"
|
|
2100
|
+
}`}</pre>
|
|
2101
|
+
</Alert>
|
|
2102
|
+
<h4 className="font-medium mb-2">Génération automatique</h4>
|
|
2103
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2104
|
+
Lors du{" "}
|
|
2105
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2106
|
+
pnpm build:modules
|
|
2107
|
+
</code>
|
|
2108
|
+
, le système :
|
|
2109
|
+
</p>
|
|
2110
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2111
|
+
1. Collecte tous les fichiers{" "}
|
|
2112
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2113
|
+
packages/**/src/i18n/*.json
|
|
2114
|
+
</code>
|
|
2115
|
+
</p>
|
|
2116
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2117
|
+
2. Préfixe les clés avec le nom du module (ex:{" "}
|
|
2118
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2119
|
+
module-auth.welcome
|
|
2120
|
+
</code>
|
|
2121
|
+
)
|
|
2122
|
+
</p>
|
|
2123
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2124
|
+
3. Concatène les traductions par langue
|
|
2125
|
+
</p>
|
|
2126
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2127
|
+
4. Génère{" "}
|
|
2128
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2129
|
+
apps/{'{'app{'}'/i18n/fr.json
|
|
2130
|
+
</code>{" "}
|
|
2131
|
+
et{" "}
|
|
2132
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2133
|
+
apps/{'{'app{'}'/i18n/en.json
|
|
2134
|
+
</code>
|
|
2135
|
+
</p>
|
|
2136
|
+
<h4 className="font-medium mb-2">Routes générées</h4>
|
|
2137
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2138
|
+
Toutes les routes sont générées avec le paramètre{" "}
|
|
2139
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2140
|
+
[lang]
|
|
2141
|
+
</code>{" "}
|
|
2142
|
+
:
|
|
2143
|
+
</p>
|
|
2144
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2145
|
+
app/
|
|
2146
|
+
</p>
|
|
2147
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2148
|
+
[lang]/
|
|
2149
|
+
</p>
|
|
2150
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2151
|
+
layout.tsx # Layout racine qui charge les traductions
|
|
2152
|
+
</p>
|
|
2153
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2154
|
+
(public)/
|
|
2155
|
+
</p>
|
|
2156
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2157
|
+
page.tsx
|
|
2158
|
+
</p>
|
|
2159
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2160
|
+
auth/
|
|
2161
|
+
</p>
|
|
2162
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2163
|
+
layout.tsx
|
|
2164
|
+
</p>
|
|
2165
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2166
|
+
signin/
|
|
2167
|
+
</p>
|
|
2168
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2169
|
+
page.tsx
|
|
2170
|
+
</p>
|
|
2171
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2172
|
+
admin/
|
|
2173
|
+
</p>
|
|
2174
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2175
|
+
layout.tsx
|
|
2176
|
+
</p>
|
|
2177
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2178
|
+
users/
|
|
2179
|
+
</p>
|
|
2180
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2181
|
+
page.tsx
|
|
2182
|
+
</p>
|
|
2183
|
+
<h3 className="text-lg font-semibold mb-2">Utilisation</h3>
|
|
2184
|
+
<h4 className="font-medium mb-2">
|
|
2185
|
+
⚠️ Important : Imports côté serveur
|
|
2186
|
+
</h4>
|
|
2187
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2188
|
+
Les fonctions server-only (
|
|
2189
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2190
|
+
getServerLanguage
|
|
2191
|
+
</code>
|
|
2192
|
+
,{" "}
|
|
2193
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2194
|
+
loadTranslations
|
|
2195
|
+
</code>
|
|
2196
|
+
,{" "}
|
|
2197
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2198
|
+
createServerTranslator
|
|
2199
|
+
</code>
|
|
2200
|
+
,{" "}
|
|
2201
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2202
|
+
createNamespacedTranslator
|
|
2203
|
+
</code>
|
|
2204
|
+
) doivent être importées depuis :
|
|
2205
|
+
</p>
|
|
2206
|
+
<Alert hideIcon color="primary" className="p-4 mb-4">
|
|
2207
|
+
<pre className="whitespace-pre-wrap">{`import { ... } from "@lastbrain/app/i18n/server-lang";`}</pre>
|
|
2208
|
+
</Alert>
|
|
2209
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2210
|
+
<strong>PAS</strong> depuis{" "}
|
|
2211
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2212
|
+
"@lastbrain/app"
|
|
2213
|
+
</code>{" "}
|
|
2214
|
+
car cela causerait des erreurs côté client.
|
|
2215
|
+
</p>
|
|
2216
|
+
<h4 className="font-medium mb-2">Côté serveur (Server Components)</h4>
|
|
2217
|
+
<Alert hideIcon color="primary" className="p-4 mb-4">
|
|
2218
|
+
<pre className="whitespace-pre-wrap">{`import { getServerLanguage, loadTranslations } from "@lastbrain/app/i18n/server-lang";
|
|
2219
|
+
|
|
2220
|
+
export default async function MyPage({
|
|
2221
|
+
params,
|
|
2222
|
+
}: {
|
|
2223
|
+
params: Promise<{ lang: string }>;
|
|
2224
|
+
}) {
|
|
2225
|
+
const { lang } = await params;
|
|
2226
|
+
const translations = await loadTranslations(lang as "fr" | "en");
|
|
2227
|
+
|
|
2228
|
+
return (
|
|
2229
|
+
<div>
|
|
2230
|
+
<h1>{translations["module-auth.welcome"]}</h1>
|
|
2231
|
+
</div>
|
|
2232
|
+
);
|
|
2233
|
+
}`}</pre>
|
|
2234
|
+
</Alert>
|
|
2235
|
+
<Alert hideIcon color="primary" className="p-4 mb-4">
|
|
2236
|
+
<pre className="whitespace-pre-wrap">{`"use client";
|
|
2237
|
+
|
|
2238
|
+
import { useLanguage } from "@lastbrain/app";
|
|
2239
|
+
|
|
2240
|
+
export function MyComponent() {
|
|
2241
|
+
const { lang, setLang, t } = useLanguage();
|
|
2242
|
+
|
|
2243
|
+
return (
|
|
2244
|
+
<div>
|
|
2245
|
+
<h1>{t("module-auth.welcome")}</h1>
|
|
2246
|
+
<button onClick={() => setLang("en")}>EN</button>
|
|
2247
|
+
<button onClick={() => setLang("fr")}>FR</button>
|
|
2248
|
+
</div>
|
|
2249
|
+
);
|
|
2250
|
+
}`}</pre>
|
|
2251
|
+
</Alert>
|
|
2252
|
+
<h4 className="font-medium mb-2">Hook useLanguage</h4>
|
|
2253
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2254
|
+
Le hook{" "}
|
|
2255
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2256
|
+
useLanguage()
|
|
2257
|
+
</code>{" "}
|
|
2258
|
+
fournit :
|
|
2259
|
+
</p>
|
|
2260
|
+
<div className="space-y-2">
|
|
2261
|
+
<div className="flex items-start gap-2">
|
|
2262
|
+
<span className="text-green-600">✅</span>
|
|
2263
|
+
<span>
|
|
2264
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2265
|
+
lang
|
|
2266
|
+
</code>
|
|
2267
|
+
: La langue actuelle (
|
|
2268
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2269
|
+
"fr"
|
|
2270
|
+
</code>{" "}
|
|
2271
|
+
|{" "}
|
|
2272
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2273
|
+
"en"
|
|
2274
|
+
</code>
|
|
2275
|
+
)
|
|
2276
|
+
</span>
|
|
2277
|
+
</div>
|
|
2278
|
+
<div className="flex items-start gap-2">
|
|
2279
|
+
<span className="text-green-600">✅</span>
|
|
2280
|
+
<span>
|
|
2281
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2282
|
+
setLang(lang)
|
|
2283
|
+
</code>
|
|
2284
|
+
: Fonction pour changer de langue (sauvegarde dans cookies et
|
|
2285
|
+
redirige)
|
|
2286
|
+
</span>
|
|
2287
|
+
</div>
|
|
2288
|
+
<div className="flex items-start gap-2">
|
|
2289
|
+
<span className="text-green-600">✅</span>
|
|
2290
|
+
<span>
|
|
2291
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2292
|
+
t(key)
|
|
2293
|
+
</code>
|
|
2294
|
+
: Fonction de traduction
|
|
2295
|
+
</span>
|
|
2296
|
+
</div>
|
|
2297
|
+
</div>
|
|
2298
|
+
<h3 className="text-lg font-semibold mb-2">Gestion des cookies</h3>
|
|
2299
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2300
|
+
Le système utilise le cookie{" "}
|
|
2301
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2302
|
+
NEXT_LOCALE
|
|
2303
|
+
</code>{" "}
|
|
2304
|
+
pour :
|
|
2305
|
+
</p>
|
|
2306
|
+
<div className="space-y-2">
|
|
2307
|
+
<div className="flex items-start gap-2">
|
|
2308
|
+
<span className="text-green-600">✅</span>
|
|
2309
|
+
<span>Stocker la préférence de langue de l'utilisateur</span>
|
|
2310
|
+
</div>
|
|
2311
|
+
<div className="flex items-start gap-2">
|
|
2312
|
+
<span className="text-green-600">✅</span>
|
|
2313
|
+
<span>
|
|
2314
|
+
Permettre l'accès côté serveur via{" "}
|
|
2315
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2316
|
+
getServerLanguage()
|
|
2317
|
+
</code>
|
|
2318
|
+
</span>
|
|
2319
|
+
</div>
|
|
2320
|
+
<div className="flex items-start gap-2">
|
|
2321
|
+
<span className="text-green-600">✅</span>
|
|
2322
|
+
<span>Persister la langue entre les sessions</span>
|
|
2323
|
+
</div>
|
|
2324
|
+
</div>
|
|
2325
|
+
<h3 className="text-lg font-semibold mb-2">Bonnes pratiques</h3>
|
|
2326
|
+
<h4 className="font-medium mb-2">1. Préfixage des clés</h4>
|
|
2327
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2328
|
+
Les clés sont automatiquement préfixées par le nom du module, donc :
|
|
2329
|
+
</p>
|
|
2330
|
+
<div className="space-y-2">
|
|
2331
|
+
<div className="flex items-start gap-2">
|
|
2332
|
+
<span className="text-green-600">✅</span>
|
|
2333
|
+
<span>
|
|
2334
|
+
Dans{" "}
|
|
2335
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2336
|
+
module-auth/src/i18n/fr.json
|
|
2337
|
+
</code>{" "}
|
|
2338
|
+
:{" "}
|
|
2339
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2340
|
+
"welcome": "Bienvenue"
|
|
2341
|
+
</code>
|
|
2342
|
+
</span>
|
|
2343
|
+
</div>
|
|
2344
|
+
<div className="flex items-start gap-2">
|
|
2345
|
+
<span className="text-green-600">✅</span>
|
|
2346
|
+
<span>
|
|
2347
|
+
Devient dans l'app :{" "}
|
|
2348
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2349
|
+
"module-auth.welcome": "Bienvenue"
|
|
2350
|
+
</code>
|
|
2351
|
+
</span>
|
|
2352
|
+
</div>
|
|
2353
|
+
</div>
|
|
2354
|
+
<h4 className="font-medium mb-2">2. Organisation des traductions</h4>
|
|
2355
|
+
<Alert hideIcon color="primary" className="p-4 mb-4">
|
|
2356
|
+
<pre className="whitespace-pre-wrap">{`{
|
|
2357
|
+
"common": {
|
|
2358
|
+
"save": "Enregistrer",
|
|
2359
|
+
"cancel": "Annuler"
|
|
2360
|
+
},
|
|
2361
|
+
"errors": {
|
|
2362
|
+
"required": "Ce champ est requis",
|
|
2363
|
+
"invalid_email": "Email invalide"
|
|
2364
|
+
},
|
|
2365
|
+
"pages": {
|
|
2366
|
+
"home": {
|
|
2367
|
+
"title": "Accueil",
|
|
2368
|
+
"subtitle": "Bienvenue sur LastBrain"
|
|
2369
|
+
}
|
|
2370
|
+
}
|
|
2371
|
+
}`}</pre>
|
|
2372
|
+
</Alert>
|
|
2373
|
+
<h4 className="font-medium mb-2">3. Utilisation dans les vues</h4>
|
|
2374
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2375
|
+
<strong>À FAIRE</strong> ✅ :
|
|
2376
|
+
</p>
|
|
2377
|
+
<Alert hideIcon color="primary" className="p-4 mb-4">
|
|
2378
|
+
<pre className="whitespace-pre-wrap">{`"use client";
|
|
2379
|
+
import { useLanguage } from "@lastbrain/app";
|
|
2380
|
+
|
|
2381
|
+
export function MyView() {
|
|
2382
|
+
const { t } = useLanguage();
|
|
2383
|
+
return <h1>{t("module-auth.welcome")}</h1>;
|
|
2384
|
+
}`}</pre>
|
|
2385
|
+
</Alert>
|
|
2386
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2387
|
+
<strong>À NE PAS FAIRE</strong> ❌ :
|
|
2388
|
+
</p>
|
|
2389
|
+
<Alert hideIcon color="primary" className="p-4 mb-4">
|
|
2390
|
+
<pre className="whitespace-pre-wrap">{`// Ne pas faire de requêtes Supabase directes dans les vues
|
|
2391
|
+
// Utiliser les API routes à la place`}</pre>
|
|
2392
|
+
</Alert>
|
|
2393
|
+
<h3 className="text-lg font-semibold mb-2">Langues supportées</h3>
|
|
2394
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2395
|
+
Par défaut :{" "}
|
|
2396
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2397
|
+
fr
|
|
2398
|
+
</code>{" "}
|
|
2399
|
+
et{" "}
|
|
2400
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2401
|
+
en
|
|
2402
|
+
</code>
|
|
2403
|
+
</p>
|
|
2404
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2405
|
+
Pour ajouter une langue :
|
|
2406
|
+
</p>
|
|
2407
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2408
|
+
1. Créer les fichiers{" "}
|
|
2409
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2410
|
+
{'{'lang{'}'.json
|
|
2411
|
+
</code>{" "}
|
|
2412
|
+
dans les modules
|
|
2413
|
+
</p>
|
|
2414
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2415
|
+
2. Le système détectera automatiquement la nouvelle langue
|
|
2416
|
+
</p>
|
|
2417
|
+
<h3 className="text-lg font-semibold mb-2">
|
|
2418
|
+
Middleware de langue (optionnel)
|
|
2419
|
+
</h3>
|
|
2420
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2421
|
+
Si vous souhaitez rediriger automatiquement vers{" "}
|
|
2422
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2423
|
+
/fr
|
|
2424
|
+
</code>{" "}
|
|
2425
|
+
ou{" "}
|
|
2426
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2427
|
+
/en
|
|
2428
|
+
</code>{" "}
|
|
2429
|
+
selon la préférence navigateur :
|
|
2430
|
+
</p>
|
|
2431
|
+
<Alert hideIcon color="primary" className="p-4 mb-4">
|
|
2432
|
+
<pre className="whitespace-pre-wrap">{`// middleware.ts
|
|
2433
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
2434
|
+
|
|
2435
|
+
export function middleware(request: NextRequest) {
|
|
2436
|
+
const { pathname } = request.nextUrl;
|
|
2437
|
+
|
|
2438
|
+
// Si pas de langue dans l'URL
|
|
2439
|
+
if (!pathname.match(/^\\/(fr|en)\\//)) {
|
|
2440
|
+
const locale = request.cookies.get("NEXT_LOCALE")?.value || "fr";
|
|
2441
|
+
return NextResponse.redirect(new URL(\`/\${locale}\${pathname}\`, request.url));
|
|
2442
|
+
}
|
|
2443
|
+
|
|
2444
|
+
return NextResponse.next();
|
|
2445
|
+
}
|
|
2446
|
+
|
|
2447
|
+
export const config = {
|
|
2448
|
+
matcher: ["/((?!api|_next|.*\\\\..*).*)"],
|
|
2449
|
+
};`}</pre>
|
|
2450
|
+
</Alert>
|
|
2451
|
+
<h3 className="text-lg font-semibold mb-2">Debugging</h3>
|
|
2452
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2453
|
+
Pour voir les traductions générées :
|
|
2454
|
+
</p>
|
|
2455
|
+
<Snippet symbol="" hideSymbol className="text-sm mb-2">
|
|
2456
|
+
{`pnpm build:modules --debug`}
|
|
2457
|
+
</Snippet>
|
|
2458
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2459
|
+
Cela affichera :
|
|
2460
|
+
</p>
|
|
2461
|
+
<div className="space-y-2">
|
|
2462
|
+
<div className="flex items-start gap-2">
|
|
2463
|
+
<span className="text-green-600">✅</span>
|
|
2464
|
+
<span>Les fichiers i18n trouvés</span>
|
|
2465
|
+
</div>
|
|
2466
|
+
<div className="flex items-start gap-2">
|
|
2467
|
+
<span className="text-green-600">✅</span>
|
|
2468
|
+
<span>Les modules traités</span>
|
|
2469
|
+
</div>
|
|
2470
|
+
<div className="flex items-start gap-2">
|
|
2471
|
+
<span className="text-green-600">✅</span>
|
|
2472
|
+
<span>Les clés générées</span>
|
|
2473
|
+
</div>
|
|
2474
|
+
<div className="flex items-start gap-2">
|
|
2475
|
+
<span className="text-green-600">✅</span>
|
|
2476
|
+
<span>Le chemin des fichiers de sortie</span>
|
|
2477
|
+
</div>
|
|
2478
|
+
</div>
|
|
2479
|
+
<h3 className="text-lg font-semibold mb-2">Exemple complet</h3>
|
|
2480
|
+
<h4 className="font-medium mb-2">
|
|
2481
|
+
1. Créer les traductions dans un module
|
|
2482
|
+
</h4>
|
|
2483
|
+
<Alert hideIcon color="primary" className="p-4 mb-4">
|
|
2484
|
+
<pre className="whitespace-pre-wrap">{`// packages/module-shop-pro/src/i18n/fr.json
|
|
2485
|
+
{
|
|
2486
|
+
"products": "Produits",
|
|
2487
|
+
"add_to_cart": "Ajouter au panier",
|
|
2488
|
+
"checkout": "Passer commande"
|
|
2489
|
+
}`}</pre>
|
|
2490
|
+
</Alert>
|
|
2491
|
+
<h4 className="font-medium mb-2">2. Lancer le build</h4>
|
|
2492
|
+
<Snippet symbol="" hideSymbol className="text-sm mb-2">
|
|
2493
|
+
{`cd apps/recipe`}
|
|
2494
|
+
</Snippet>
|
|
2495
|
+
<Snippet symbol="" hideSymbol className="text-sm mb-2">
|
|
2496
|
+
{`pnpm build:modules`}
|
|
2497
|
+
</Snippet>
|
|
2498
|
+
<h4 className="font-medium mb-2">3. Utiliser dans une vue</h4>
|
|
2499
|
+
<Alert hideIcon color="primary" className="p-4 mb-4">
|
|
2500
|
+
<pre className="whitespace-pre-wrap">{`"use client";
|
|
2501
|
+
import { useLanguage } from "@lastbrain/app";
|
|
2502
|
+
|
|
2503
|
+
export function ProductCard() {
|
|
2504
|
+
const { t } = useLanguage();
|
|
2505
|
+
|
|
2506
|
+
return <button>{t("module-shop-pro.add_to_cart")}</button>;
|
|
2507
|
+
}`}</pre>
|
|
2508
|
+
</Alert>
|
|
2509
|
+
<h3 className="text-lg font-semibold mb-2">
|
|
2510
|
+
Migration des applications existantes
|
|
2511
|
+
</h3>
|
|
2512
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2513
|
+
Si vous avez une app existante sans i18n :
|
|
2514
|
+
</p>
|
|
2515
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2516
|
+
1. Les routes actuelles ne casseront pas
|
|
2517
|
+
</p>
|
|
2518
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2519
|
+
2. Exécutez{" "}
|
|
2520
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2521
|
+
pnpm build:modules
|
|
2522
|
+
</code>{" "}
|
|
2523
|
+
pour générer les nouvelles routes avec{" "}
|
|
2524
|
+
<code className="text-sm bg-slate-100 dark:bg-slate-800 px-2 py-1 rounded">
|
|
2525
|
+
[lang]
|
|
2526
|
+
</code>
|
|
2527
|
+
</p>
|
|
2528
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2529
|
+
3. Ajoutez progressivement les traductions dans vos modules
|
|
2530
|
+
</p>
|
|
2531
|
+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-2">
|
|
2532
|
+
4. Les vues peuvent continuer à utiliser du texte en dur pendant la
|
|
2533
|
+
transition
|
|
2534
|
+
</p>
|
|
2535
|
+
</CardBody>
|
|
2536
|
+
</Card>
|
|
2027
2537
|
</div>
|
|
2028
2538
|
);
|
|
2029
2539
|
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Middleware optionnel pour la gestion automatique de la langue
|
|
3
|
+
*
|
|
4
|
+
* À placer dans apps/<votre-app>/middleware.ts
|
|
5
|
+
*
|
|
6
|
+
* Ce middleware :
|
|
7
|
+
* - Détecte si l'URL contient /fr ou /en
|
|
8
|
+
* - Si non, redirige vers la langue par défaut (cookie ou navigateur)
|
|
9
|
+
* - Sauvegarde la préférence dans un cookie
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
13
|
+
|
|
14
|
+
// Langues supportées
|
|
15
|
+
const locales = ["fr", "en"];
|
|
16
|
+
const defaultLocale = "fr";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Extrait la langue préférée depuis le header Accept-Language
|
|
20
|
+
*/
|
|
21
|
+
function getPreferredLocale(request: NextRequest): string {
|
|
22
|
+
const acceptLanguage = request.headers.get("accept-language");
|
|
23
|
+
if (!acceptLanguage) return defaultLocale;
|
|
24
|
+
|
|
25
|
+
// Parse "fr-FR,fr;q=0.9,en;q=0.8" -> ["fr-FR", "fr", "en"]
|
|
26
|
+
const languages = acceptLanguage.split(",").map((lang) => {
|
|
27
|
+
const [code] = lang.split(";");
|
|
28
|
+
return code.trim().split("-")[0];
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Trouver la première langue supportée
|
|
32
|
+
for (const lang of languages) {
|
|
33
|
+
if (locales.includes(lang)) {
|
|
34
|
+
return lang;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return defaultLocale;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Vérifie si l'URL contient déjà une langue
|
|
43
|
+
*/
|
|
44
|
+
function hasLocale(pathname: string): boolean {
|
|
45
|
+
return locales.some(
|
|
46
|
+
(locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function middleware(request: NextRequest) {
|
|
51
|
+
const { pathname } = request.nextUrl;
|
|
52
|
+
|
|
53
|
+
// Ignorer les fichiers statiques et API
|
|
54
|
+
if (
|
|
55
|
+
pathname.startsWith("/_next") ||
|
|
56
|
+
pathname.startsWith("/api") ||
|
|
57
|
+
pathname.includes(".")
|
|
58
|
+
) {
|
|
59
|
+
return NextResponse.next();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Si l'URL contient déjà une langue, continuer
|
|
63
|
+
if (hasLocale(pathname)) {
|
|
64
|
+
return NextResponse.next();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Déterminer la langue à utiliser
|
|
68
|
+
const cookieLocale = request.cookies.get("NEXT_LOCALE")?.value;
|
|
69
|
+
const locale =
|
|
70
|
+
cookieLocale && locales.includes(cookieLocale)
|
|
71
|
+
? cookieLocale
|
|
72
|
+
: getPreferredLocale(request);
|
|
73
|
+
|
|
74
|
+
// Rediriger vers l'URL avec la langue
|
|
75
|
+
const url = request.nextUrl.clone();
|
|
76
|
+
url.pathname = `/${locale}${pathname}`;
|
|
77
|
+
|
|
78
|
+
const response = NextResponse.redirect(url);
|
|
79
|
+
|
|
80
|
+
// Sauvegarder la préférence dans un cookie
|
|
81
|
+
response.cookies.set("NEXT_LOCALE", locale, {
|
|
82
|
+
path: "/",
|
|
83
|
+
maxAge: 365 * 24 * 60 * 60, // 1 an
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
return response;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export const config = {
|
|
90
|
+
// Matcher pour toutes les routes sauf les fichiers statiques
|
|
91
|
+
matcher: ["/((?!_next|api|.*\\..*).*)"],
|
|
92
|
+
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../src/app-shell/(admin)/dashboard/page.tsx"],"names":[],"mappings":"AAEA,MAAM,CAAC,OAAO,UAAU,kBAAkB,4CAOzC"}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
export default function AdminDashboardPage() {
|
|
4
|
-
return (_jsxs("div", { className: "mx-auto max-w-4xl space-y-3 px-4 py-16", children: [_jsx("h1", { className: "text-3xl font-bold", children: "Administration" }), _jsx("p", { className: "text-slate-600", children: "Gestion des modules et des utilisateurs." })] }));
|
|
5
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../src/app-shell/(admin)/page.tsx"],"names":[],"mappings":"AAEA,MAAM,CAAC,OAAO,UAAU,kBAAkB,4CAOzC"}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
export default function AdminDashboardPage() {
|
|
4
|
-
return (_jsxs("div", { className: "mx-auto max-w-4xl space-y-3 px-4 py-16", children: [_jsx("h1", { className: "text-3xl font-bold", children: "Administration" }), _jsx("p", { className: "text-slate-600", children: "Gestion des modules et des utilisateurs." })] }));
|
|
5
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../src/app-shell/(auth)/dashboard/page.tsx"],"names":[],"mappings":"AAEA,MAAM,CAAC,OAAO,UAAU,iBAAiB,4CAOxC"}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
export default function AuthDashboardPage() {
|
|
4
|
-
return (_jsxs("div", { className: "mx-auto max-w-4xl space-y-3 px-4 py-16", children: [_jsx("h1", { className: "text-3xl font-bold", children: "Tableau de bord" }), _jsx("p", { className: "text-slate-600", children: "Bienvenue utilisateur \u2014 votre session est active." })] }));
|
|
5
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../src/app-shell/(auth)/page.tsx"],"names":[],"mappings":"AAEA,MAAM,CAAC,OAAO,UAAU,iBAAiB,4CAOxC"}
|