diff --git a/src/routes/(app)/(auth)/account/index.tsx b/src/routes/(app)/(auth)/account/index.tsx
new file mode 100644
index 0000000..d88cfb5
--- /dev/null
+++ b/src/routes/(app)/(auth)/account/index.tsx
@@ -0,0 +1,9 @@
+import { createFileRoute } from '@tanstack/react-router';
+
+export const Route = createFileRoute('/(app)/(auth)/account/')({
+ component: RouteComponent,
+});
+
+function RouteComponent() {
+ return
;
+}
diff --git a/src/routes/(app)/(auth)/profile.tsx b/src/routes/(app)/(auth)/account/profile.tsx
similarity index 60%
rename from src/routes/(app)/(auth)/profile.tsx
rename to src/routes/(app)/(auth)/account/profile.tsx
index 4b71bd6..4e5c3ca 100644
--- a/src/routes/(app)/(auth)/profile.tsx
+++ b/src/routes/(app)/(auth)/account/profile.tsx
@@ -1,16 +1,16 @@
import ProfileForm from '@/components/form/profile-form';
-import i18n from '@/lib/i18n';
+import { m } from '@/paraglide/messages';
import { createFileRoute } from '@tanstack/react-router';
-export const Route = createFileRoute('/(app)/(auth)/profile')({
+export const Route = createFileRoute('/(app)/(auth)/account/profile')({
component: RouteComponent,
- staticData: { breadcrumb: i18n.t('nav.profile') },
+ staticData: { breadcrumb: () => m.nav_profile() },
});
function RouteComponent() {
return (
-
diff --git a/src/routes/(app)/(auth)/account/route.tsx b/src/routes/(app)/(auth)/account/route.tsx
new file mode 100644
index 0000000..19cc9af
--- /dev/null
+++ b/src/routes/(app)/(auth)/account/route.tsx
@@ -0,0 +1,6 @@
+import { m } from '@/paraglide/messages';
+import { createFileRoute } from '@tanstack/react-router';
+
+export const Route = createFileRoute('/(app)/(auth)/account')({
+ staticData: { breadcrumb: () => m.nav_account() },
+});
diff --git a/src/routes/(app)/(auth)/account/settings.tsx b/src/routes/(app)/(auth)/account/settings.tsx
new file mode 100644
index 0000000..1a66679
--- /dev/null
+++ b/src/routes/(app)/(auth)/account/settings.tsx
@@ -0,0 +1,11 @@
+import { m } from '@/paraglide/messages';
+import { createFileRoute } from '@tanstack/react-router';
+
+export const Route = createFileRoute('/(app)/(auth)/account/settings')({
+ component: RouteComponent,
+ staticData: { breadcrumb: () => m.nav_settings() },
+});
+
+function RouteComponent() {
+ return
Hello "account/settings"!
;
+}
diff --git a/src/routes/(app)/(auth)/dashboard.tsx b/src/routes/(app)/(auth)/dashboard.tsx
index c9e947b..d72116c 100644
--- a/src/routes/(app)/(auth)/dashboard.tsx
+++ b/src/routes/(app)/(auth)/dashboard.tsx
@@ -1,9 +1,11 @@
+import { m } from '@/paraglide/messages';
import { createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/(app)/(auth)/dashboard')({
component: RouteComponent,
+ staticData: { breadcrumb: () => m.nav_dashboard() },
});
function RouteComponent() {
- return
Hello "/(app)/dashboard"!
;
+ return
Hello "dashboard"!
;
}
diff --git a/src/routes/(app)/(auth)/settings.tsx b/src/routes/(app)/(auth)/settings.tsx
index 2a2ba29..82685c9 100644
--- a/src/routes/(app)/(auth)/settings.tsx
+++ b/src/routes/(app)/(auth)/settings.tsx
@@ -1,16 +1,16 @@
import SettingsForm from '@/components/form/settings-form';
-import i18n from '@/lib/i18n';
+import { m } from '@/paraglide/messages';
import { createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/(app)/(auth)/settings')({
component: RouteComponent,
- staticData: { breadcrumb: i18n.t('nav.settings') },
+ staticData: { breadcrumb: () => m.nav_settings() },
});
function RouteComponent() {
return (
-
diff --git a/src/routes/(app)/index.tsx b/src/routes/(app)/index.tsx
index e931720..8cf6c65 100644
--- a/src/routes/(app)/index.tsx
+++ b/src/routes/(app)/index.tsx
@@ -1,11 +1,11 @@
-import i18n from '@/lib/i18n'
-import { createFileRoute } from '@tanstack/react-router'
+import { m } from '@/paraglide/messages';
+import { createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/(app)/')({
component: App,
- staticData: { breadcrumb: i18n.t('nav.home') },
-})
+ staticData: { breadcrumb: () => m.nav_home() },
+});
function App() {
- return
Home
+ return
Home
;
}
diff --git a/src/routes/(app)/route.tsx b/src/routes/(app)/route.tsx
index dbfc50e..9d5a3ce 100644
--- a/src/routes/(app)/route.tsx
+++ b/src/routes/(app)/route.tsx
@@ -1,3 +1,4 @@
+import { AuthProvider } from '@/components/auth/auth-provider';
import Header from '@/components/Header';
import AppSidebar from '@/components/sidebar/app-sidebar';
import { SidebarInset, SidebarProvider } from '@/components/ui/sidebar';
@@ -9,12 +10,14 @@ export const Route = createFileRoute('/(app)')({
function RouteComponent() {
return (
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
);
}
diff --git a/src/routes/__root.tsx b/src/routes/__root.tsx
index f188707..12bb13a 100644
--- a/src/routes/__root.tsx
+++ b/src/routes/__root.tsx
@@ -1,6 +1,6 @@
import NotFound from '@/components/NotFound';
import { Toaster } from '@/components/ui/sonner';
-import { setSSRLanguage } from '@/lib/i18n';
+import { getLocale } from '@/paraglide/runtime';
import { sessionQueries } from '@/service/queries';
import {
CheckIcon,
@@ -11,13 +11,12 @@ import {
import { TanStackDevtools } from '@tanstack/react-devtools';
import type { QueryClient } from '@tanstack/react-query';
import {
+ createRootRouteWithContext,
HeadContent,
Scripts,
- createRootRouteWithContext,
} from '@tanstack/react-router';
import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools';
import React from 'react';
-import { useTranslation } from 'react-i18next';
import TanStackQueryDevtools from '../integrations/tanstack-query/devtools';
import appCss from '../styles.css?url';
@@ -30,7 +29,6 @@ export const Route = createRootRouteWithContext
()({
const userSession = await context.queryClient.fetchQuery(
sessionQueries.user(),
);
- await setSSRLanguage();
return { userSession };
},
head: () => ({
@@ -61,29 +59,19 @@ export const Route = createRootRouteWithContext()({
});
function RootDocument({ children }: { children: React.ReactNode }) {
- const { i18n } = useTranslation();
-
return (
-
+
{children}
,
error: ,
diff --git a/src/server.ts b/src/server.ts
new file mode 100644
index 0000000..fc56df3
--- /dev/null
+++ b/src/server.ts
@@ -0,0 +1,8 @@
+import handler from '@tanstack/react-start/server-entry';
+import { paraglideMiddleware } from './paraglide/server.js';
+
+export default {
+ fetch(req: Request): Promise {
+ return paraglideMiddleware(req.clone(), () => handler.fetch(req));
+ },
+};
diff --git a/src/service/profile.schema.ts b/src/service/profile.schema.ts
index 46e6312..99d49c1 100644
--- a/src/service/profile.schema.ts
+++ b/src/service/profile.schema.ts
@@ -1,10 +1,10 @@
-import i18n from '@/lib/i18n';
+import { m } from '@/paraglide/messages';
import z from 'zod';
export const profileUpdateSchema = z.object({
name: z.string().nonempty(
- i18n.t('profile.messages.is_required', {
- field: i18n.t('profile.form.name'),
+ m.common_is_required({
+ field: m.profile_form_name('profile.form.name'),
}),
),
image: z.instanceof(File).optional(),
diff --git a/src/service/setting.api.ts b/src/service/setting.api.ts
index 39591a1..54155e5 100644
--- a/src/service/setting.api.ts
+++ b/src/service/setting.api.ts
@@ -1,7 +1,7 @@
import { prisma } from '@/db';
import { Setting } from '@/generated/prisma/client';
import { authMiddleware } from '@/lib/middleware';
-import { createServerFn } from '@tanstack/react-start';
+import { createIsomorphicFn, createServerFn } from '@tanstack/react-start';
import { settingSchema } from './setting.schema';
// import { settingSchema } from './setting.schema';
@@ -9,10 +9,24 @@ export type SettingReturn = {
[key: string]: Setting;
};
+export const getLanguage = createIsomorphicFn().server(async () => {
+ const language = await prisma.setting.findUnique({
+ where: {
+ key: 'site_language',
+ },
+ });
+
+ return language?.value;
+});
+
export const getSettings = createServerFn({ method: 'GET' })
.middleware([authMiddleware])
.handler(async () => {
- const settings = await prisma.setting.findMany();
+ const settings = await prisma.setting.findMany({
+ where: {
+ relation: 'admin',
+ },
+ });
const results: SettingReturn = {};
diff --git a/src/service/setting.schema.ts b/src/service/setting.schema.ts
index 42cbbe5..c1e71dc 100644
--- a/src/service/setting.schema.ts
+++ b/src/service/setting.schema.ts
@@ -1,25 +1,20 @@
-import i18n from '@/lib/i18n';
+import { m } from '@/paraglide/messages';
import z from 'zod';
export const settingSchema = z.object({
site_name: z.string().nonempty(
- i18n.t('settings.messages.is_required', {
- field: i18n.t('settings.form.name'),
+ m.common_is_required({
+ field: m.settings_form_name(),
}),
),
site_description: z.string().nonempty(
- i18n.t('settings.messages.is_required', {
- field: i18n.t('settings.form.description'),
+ m.common_is_required({
+ field: m.settings_form_description(),
}),
),
site_keywords: z.string().nonempty(
- i18n.t('settings.messages.is_required', {
- field: i18n.t('settings.form.keywords'),
- }),
- ),
- site_language: z.string().nonempty(
- i18n.t('settings.messages.is_required', {
- field: i18n.t('settings.form.language'),
+ m.common_is_required({
+ field: m.settings_form_keywords(),
}),
),
});
diff --git a/src/type/i18next.d.ts b/src/type/i18next.d.ts
deleted file mode 100644
index 5ae82d8..0000000
--- a/src/type/i18next.d.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import 'i18next'
-import translation from '../locales/vi.json'
-import { defaultNS } from './i18n'
-
-declare module 'i18next' {
- interface CustomTypeOptions {
- defaultNS: typeof defaultNS
- resources: {
- translation: typeof translation
- }
- }
-}
diff --git a/tsconfig.json b/tsconfig.json
index 0b0985e..4c8436b 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,12 +1,19 @@
{
- "include": ["**/*.ts", "**/*.tsx", "eslint.config.js", "prettier.config.js", "vite.config.js"],
-
+ "include": [
+ "**/*.ts",
+ "**/*.tsx",
+ "eslint.config.js",
+ "prettier.config.js",
+ "vite.config.js"
+ ],
+
"compilerOptions": {
"target": "ES2022",
"jsx": "react-jsx",
"module": "ESNext",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"types": ["vite/client"],
+ "allowJs": true,
/* Bundler mode */
"moduleResolution": "bundler",
@@ -23,7 +30,8 @@
"noUncheckedSideEffectImports": true,
"baseUrl": ".",
"paths": {
- "@/*": ["./src/*"]
+ "@/*": ["./src/*"],
+ "@root/*": ["./*"]
}
}
}
diff --git a/vite.config.ts b/vite.config.ts
index 863f49c..0c08616 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,3 +1,4 @@
+import { paraglideVitePlugin } from '@inlang/paraglide-js';
import tailwindcss from '@tailwindcss/vite';
import { devtools } from '@tanstack/devtools-vite';
import { tanstackStart } from '@tanstack/react-start/plugin/vite';
@@ -7,6 +8,13 @@ import viteTsConfigPaths from 'vite-tsconfig-paths';
const config = defineConfig({
plugins: [
+ paraglideVitePlugin({
+ project: './project.inlang',
+ outdir: './src/paraglide',
+ outputStructure: 'message-modules',
+ cookieName: 'PARAGLIDE_LOCALE',
+ strategy: ['cookie', 'baseLocale'],
+ }),
devtools(),
// this is the plugin that enables path aliases
viteTsConfigPaths({