diff --git a/.env b/.env new file mode 100644 index 0000000..e69de29 diff --git a/.env.production b/.env.production new file mode 100644 index 0000000..e69de29 diff --git a/.env.staging b/.env.staging new file mode 100644 index 0000000..e69de29 diff --git a/.gitea/workflows/deploy-vps.yaml b/.gitea/workflows/deploy-vps.yaml index 96bf489..b67fe69 100644 --- a/.gitea/workflows/deploy-vps.yaml +++ b/.gitea/workflows/deploy-vps.yaml @@ -65,7 +65,7 @@ jobs: run: pnpm install --frozen-lockfile - name: Build - run: pnpm run build + run: pnpm run build:staging - name: Deploy dist to VPS dist run: | diff --git a/i18next.config.ts b/i18next.config.ts new file mode 100644 index 0000000..97415e5 --- /dev/null +++ b/i18next.config.ts @@ -0,0 +1,21 @@ +import { readdirSync } from "fs"; +import { join } from "path"; + +export const LOCALES_PATH = join("locales"); +export const LOCAL_LOCALES_PATH = join("public", LOCALES_PATH); +export const DEFAULT_LANGUAGE = "en"; + +export default { + locales: readdirSync(LOCAL_LOCALES_PATH) + .filter((file) => file.endsWith(".json")) + .map((locale) => locale.replace(".json", "")), + defaultLocale: DEFAULT_LANGUAGE, + fallbackLng: DEFAULT_LANGUAGE, + react: { + useSuspense: false, + }, + extract: { + input: "src/**/*.{js,jsx,ts,tsx}", + output: join(LOCAL_LOCALES_PATH, "{{language}}.json"), + }, +}; diff --git a/package.json b/package.json index 61415e8..4a7a909 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "scripts": { "dev": "vite", "build": "tsc -b && vite build", + "build:staging": "tsc -b && vite build --mode staging", "lint": "oxlint", "lint:fix": "oxlint --fix", "fmt": "oxfmt", @@ -21,12 +22,16 @@ "@tanstack/react-router": "^1.166.3", "@tanstack/react-router-devtools": "^1.166.3", "arktype": "^2.2.0", + "i18next": "^25.8.17", + "i18next-http-backend": "^3.0.2", "motion": "^12.35.1", "react": "^19.2.4", "react-dom": "^19.2.4", + "react-i18next": "^16.5.6", "tailwindcss": "^4.2.1" }, "devDependencies": { + "@i18next-selector/vite-plugin": "^0.0.18", "@tanstack/router-plugin": "^1.166.3", "@types/node": "^24.10.1", "@types/react": "^19.2.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6eb3bcb..ec30225 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -32,6 +32,12 @@ importers: arktype: specifier: ^2.2.0 version: 2.2.0 + i18next: + specifier: ^25.8.17 + version: 25.8.17(typescript@5.9.3) + i18next-http-backend: + specifier: ^3.0.2 + version: 3.0.2 motion: specifier: ^12.35.1 version: 12.35.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -41,10 +47,16 @@ importers: react-dom: specifier: ^19.2.4 version: 19.2.4(react@19.2.4) + react-i18next: + specifier: ^16.5.6 + version: 16.5.6(i18next@25.8.17(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) tailwindcss: specifier: ^4.2.1 version: 4.2.1 devDependencies: + '@i18next-selector/vite-plugin': + specifier: ^0.0.18 + version: 0.0.18(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2)) '@tanstack/router-plugin': specifier: ^1.166.3 version: 1.166.3(@tanstack/react-router@1.166.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2)) @@ -161,6 +173,10 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/runtime@7.28.6': + resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} + engines: {node: '>=6.9.0'} + '@babel/template@7.28.6': resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} @@ -332,6 +348,11 @@ packages: cpu: [x64] os: [win32] + '@i18next-selector/vite-plugin@0.0.18': + resolution: {integrity: sha512-jCdVJdaYDqa3dE8LCscCa7OzCN7UvUP+FDgSuc3L3mkPRlmhiXwNpCSWNUpSgGfubGBcpIE9vexHaLcS2KU0Bg==} + peerDependencies: + vite: 6 - 7 + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -1159,6 +1180,18 @@ packages: resolution: {integrity: sha512-42WoRePf8v690qG8yGRe/YOh+oHni9vUaUUfoqlS91U2scd3a5rkLtVsc6b7z60w3RogH0I00vdrC5AaeiZ18w==} engines: {node: '>=20.19'} + '@traversable/json@0.0.26': + resolution: {integrity: sha512-oXKX0eNxbbHGLjLV27nTuV0uyR6uSoWi0BF+FYJu4jXRcSsWqCHOqNjIb2x/0usKd70rnKLGyHxurlTBTpQVOw==} + peerDependencies: + '@traversable/registry': ^0.0.25 + fast-check: ^3 + peerDependenciesMeta: + fast-check: + optional: true + + '@traversable/registry@0.0.25': + resolution: {integrity: sha512-idu2DhzoHOeqO+FZSpnDTgrFQWZL+poyxO9KozHeW7KdVqecrtYwR10vCVB/dItVdMBVZbavbNWO6PgUYN1KLg==} + '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} @@ -1204,6 +1237,9 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + arkregex@0.0.5: resolution: {integrity: sha512-ncYjBdLlh5/QnVsAA8De16Tc9EqmYM7y/WU9j+236KcyYNUXogpz3sC4ATIZYzzLxwI+0sEOaQLEmLmRleaEXw==} @@ -1278,6 +1314,9 @@ packages: cookie-es@2.0.0: resolution: {integrity: sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==} + cross-fetch@4.0.0: + resolution: {integrity: sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==} + csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} @@ -1395,11 +1434,25 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + html-parse-stringify@3.0.1: + resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==} + husky@9.1.7: resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} engines: {node: '>=18'} hasBin: true + i18next-http-backend@3.0.2: + resolution: {integrity: sha512-PdlvPnvIp4E1sYi46Ik4tBYh/v/NbYfFFgTjkwFl0is8A18s7/bx9aXqsrOax9WUbeNS6mD2oix7Z0yGGf6m5g==} + + i18next@25.8.17: + resolution: {integrity: sha512-vWtCttyn5bpOK4hWbRAe1ZXkA+Yzcn2OcACT+WJavtfGMcxzkfvXTLMeOU8MUhRmAySKjU4VVuKlo0sSGeBokA==} + peerDependencies: + typescript: ^5 + peerDependenciesMeta: + typescript: + optional: true + immutable@5.1.5: resolution: {integrity: sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==} @@ -1434,6 +1487,10 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -1579,6 +1636,15 @@ packages: node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + node-releases@2.0.36: resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} @@ -1633,6 +1699,22 @@ packages: peerDependencies: react: ^19.2.4 + react-i18next@16.5.6: + resolution: {integrity: sha512-Ua7V2/efA88ido7KyK51fb8Ki8M/sRfW8LR/rZ/9ZKr2luhuTI7kwYZN5agT1rWG7aYm5G0RYE/6JR8KJoCMDw==} + peerDependencies: + i18next: '>= 25.6.2' + react: '>= 16.8.0' + react-dom: '*' + react-native: '*' + typescript: ^5 + peerDependenciesMeta: + react-dom: + optional: true + react-native: + optional: true + typescript: + optional: true + react@19.2.4: resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} engines: {node: '>=0.10.0'} @@ -1894,6 +1976,9 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -1968,9 +2053,19 @@ packages: yaml: optional: true + void-elements@3.1.0: + resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} + engines: {node: '>=0.10.0'} + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + webpack-virtual-modules@0.6.2: resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + wrap-ansi@9.0.2: resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} engines: {node: '>=18'} @@ -2095,6 +2190,8 @@ snapshots: '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 + '@babel/runtime@7.28.6': {} + '@babel/template@7.28.6': dependencies: '@babel/code-frame': 7.29.0 @@ -2199,6 +2296,15 @@ snapshots: '@esbuild/win32-x64@0.27.3': optional: true + '@i18next-selector/vite-plugin@0.0.18(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2))': + dependencies: + '@traversable/json': 0.0.26(@traversable/registry@0.0.25) + '@traversable/registry': 0.0.25 + js-yaml: 4.1.1 + vite: 7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(sass-embedded@1.97.3)(sass@1.97.3)(tsx@4.21.0)(yaml@2.8.2) + transitivePeerDependencies: + - fast-check + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -2810,6 +2916,12 @@ snapshots: '@tanstack/virtual-file-routes@1.161.4': {} + '@traversable/json@0.0.26(@traversable/registry@0.0.25)': + dependencies: + '@traversable/registry': 0.0.25 + + '@traversable/registry@0.0.25': {} + '@types/estree@1.0.8': {} '@types/node@24.12.0': @@ -2849,6 +2961,8 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 + argparse@2.0.1: {} + arkregex@0.0.5: dependencies: '@ark/util': 0.56.0 @@ -2931,6 +3045,12 @@ snapshots: cookie-es@2.0.0: {} + cross-fetch@4.0.0: + dependencies: + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + csstype@3.2.3: {} dayjs@1.11.19: {} @@ -3032,8 +3152,24 @@ snapshots: has-flag@4.0.0: optional: true + html-parse-stringify@3.0.1: + dependencies: + void-elements: 3.1.0 + husky@9.1.7: {} + i18next-http-backend@3.0.2: + dependencies: + cross-fetch: 4.0.0 + transitivePeerDependencies: + - encoding + + i18next@25.8.17(typescript@5.9.3): + dependencies: + '@babel/runtime': 7.28.6 + optionalDependencies: + typescript: 5.9.3 + immutable@5.1.5: optional: true @@ -3059,6 +3195,10 @@ snapshots: js-tokens@4.0.0: {} + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + jsesc@3.1.0: {} json5@2.2.3: {} @@ -3179,6 +3319,10 @@ snapshots: node-addon-api@7.1.1: optional: true + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + node-releases@2.0.36: {} normalize-path@3.0.0: {} @@ -3254,6 +3398,17 @@ snapshots: react: 19.2.4 scheduler: 0.27.0 + react-i18next@16.5.6(i18next@25.8.17(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3): + dependencies: + '@babel/runtime': 7.28.6 + html-parse-stringify: 3.0.1 + i18next: 25.8.17(typescript@5.9.3) + react: 19.2.4 + use-sync-external-store: 1.6.0(react@19.2.4) + optionalDependencies: + react-dom: 19.2.4(react@19.2.4) + typescript: 5.9.3 + react@19.2.4: {} readdirp@3.6.0: @@ -3500,6 +3655,8 @@ snapshots: dependencies: is-number: 7.0.0 + tr46@0.0.3: {} + tslib@2.8.1: {} tsx@4.21.0: @@ -3551,8 +3708,17 @@ snapshots: tsx: 4.21.0 yaml: 2.8.2 + void-elements@3.1.0: {} + + webidl-conversions@3.0.1: {} + webpack-virtual-modules@0.6.2: {} + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + wrap-ansi@9.0.2: dependencies: ansi-styles: 6.2.3 diff --git a/public/locales/en.d.ts b/public/locales/en.d.ts new file mode 100644 index 0000000..36d140b --- /dev/null +++ b/public/locales/en.d.ts @@ -0,0 +1 @@ +export declare const resources: { hello: "Hello World!" }; diff --git a/public/locales/en.json b/public/locales/en.json new file mode 100644 index 0000000..5de8883 --- /dev/null +++ b/public/locales/en.json @@ -0,0 +1,3 @@ +{ + "hello": "Hello World!" +} diff --git a/public/locales/ru.d.ts b/public/locales/ru.d.ts new file mode 100644 index 0000000..d039f6d --- /dev/null +++ b/public/locales/ru.d.ts @@ -0,0 +1 @@ +export declare const resources: { hello: "Привет мир" }; diff --git a/public/locales/ru.json b/public/locales/ru.json new file mode 100644 index 0000000..31b3150 --- /dev/null +++ b/public/locales/ru.json @@ -0,0 +1,3 @@ +{ + "hello": "Привет мир" +} diff --git a/src/i18next.d.ts b/src/i18next.d.ts new file mode 100644 index 0000000..69e850c --- /dev/null +++ b/src/i18next.d.ts @@ -0,0 +1,9 @@ +import "i18next"; + +import type { resources } from "../public/locales/en.d.ts"; + +declare module "i18next" { + interface CustomTypeOptions { + resources: { translation: typeof resources }; + } +} diff --git a/src/i18next.ts b/src/i18next.ts new file mode 100644 index 0000000..7a74619 --- /dev/null +++ b/src/i18next.ts @@ -0,0 +1,27 @@ +import i18next from "i18next"; +import Backend, { type HttpBackendOptions } from "i18next-http-backend"; +import { initReactI18next } from "react-i18next"; + +declare const __LANGS__: string[]; +declare const __LOCALES_PATH__: string; +declare const __DEFAULT_LANG__: string; + +export const languages = __LANGS__.map((key) => ({ + key, + label: key.toUpperCase(), +})); + +i18next + .use(Backend) + .use(initReactI18next) + .init({ + backend: { + loadPath: `/${__LOCALES_PATH__}/{{lng}}.json`, + }, + fallbackLng: __DEFAULT_LANG__, + supportedLngs: __LANGS__, + debug: import.meta.env.DEV, + interpolation: { + escapeValue: false, + }, + }); diff --git a/src/main.tsx b/src/main.tsx index f5856df..422fb85 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,10 +1,11 @@ import { StrictMode } from "react"; import ReactDOM from "react-dom/client"; import { RouterProvider, createRouter } from "@tanstack/react-router"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import "./index.css"; import { routeTree } from "./routeTree.gen"; -import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import "./i18next"; const router = createRouter({ routeTree }); diff --git a/src/routes/__root.tsx b/src/routes/__root.tsx index 76c4b3b..0521b63 100644 --- a/src/routes/__root.tsx +++ b/src/routes/__root.tsx @@ -17,6 +17,12 @@ export const Route = createRootRoute({
{ + const { t, i18n } = useTranslation(); + + const [langIdx, setLangIdx] = useState(0); + useEffect(() => { + i18n.changeLanguage(languages[langIdx].key); + }, [langIdx, i18n]); + return (
-

Welcome Home!

+

+ {t("hello")} + +

); }, diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 0000000..6e551a2 --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1,11 @@ +interface ViteTypeOptions { + strictImportMetaEnv: unknown; +} + +interface ImportMetaEnv { + MODE: "development" | "production" | "staging"; +} + +interface ImportMeta { + readonly env: ImportMetaEnv; +} diff --git a/tsconfig.json b/tsconfig.json index d32ff68..6d2d36b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,4 +1,7 @@ { "files": [], - "references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }] + "references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }], + "compilerOptions": { + "resolveJsonModule": true + } } diff --git a/vite.config.ts b/vite.config.ts index 5d93ad9..8f74407 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -3,9 +3,18 @@ import react from "@vitejs/plugin-react-swc"; import tailwindcss from "@tailwindcss/vite"; import tanstackRouter from "@tanstack/router-plugin/vite"; import { devtools as tanstackDevtools } from "@tanstack/devtools-vite"; +import { i18nextVitePlugin } from "@i18next-selector/vite-plugin"; +import i18nextConfig, { + DEFAULT_LANGUAGE, + LOCALES_PATH, + LOCAL_LOCALES_PATH, +} from "./i18next.config"; export default defineConfig({ plugins: [ + i18nextVitePlugin({ + sourceDir: LOCAL_LOCALES_PATH, + }), tanstackDevtools({ removeDevtoolsOnBuild: true, logging: true, @@ -32,4 +41,9 @@ export default defineConfig({ react(), tailwindcss(), ], + define: { + __LANGS__: JSON.stringify(i18nextConfig.locales), + __LOCALES_PATH__: JSON.stringify(LOCALES_PATH), + __DEFAULT_LANG__: JSON.stringify(DEFAULT_LANGUAGE), + }, });