diff --git a/package-lock.json b/package-lock.json index 80cf4ea..22a557c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,9 +8,13 @@ "name": "pasargad_bricks", "version": "0.1.0", "dependencies": { + "i18next": "^25.2.1", + "i18next-browser-languagedetector": "^8.1.0", + "i18next-http-backend": "^3.0.2", "next": "15.3.3", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "react-i18next": "^15.5.2" }, "devDependencies": { "@eslint/eslintrc": "^3", @@ -53,6 +57,14 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/runtime": { + "version": "7.27.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.4.tgz", + "integrity": "sha512-t3yaEOuGu9NlIZ+hIeGbBjFtZT7j2cb2tg0fuaJKeGotchRjjLfrBA9Kwf8quhpP1EUuxModQg04q/mBwyg8uA==", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@emnapi/core": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.3.tgz", @@ -2202,6 +2214,14 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -3410,6 +3430,60 @@ "node": ">= 0.4" } }, + "node_modules/html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "dependencies": { + "void-elements": "3.1.0" + } + }, + "node_modules/i18next": { + "version": "25.2.1", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.2.1.tgz", + "integrity": "sha512-+UoXK5wh+VlE1Zy5p6MjcvctHXAhRwQKCxiJD8noKZzIXmnAX8gdHX5fLPA3MEVxEN4vbZkQFy8N0LyD9tUqPw==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "dependencies": { + "@babel/runtime": "^7.27.1" + }, + "peerDependencies": { + "typescript": "^5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/i18next-browser-languagedetector": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.1.0.tgz", + "integrity": "sha512-mHZxNx1Lq09xt5kCauZ/4bsXOEA2pfpwSoU11/QTJB+pD94iONFwp+ohqi///PwiFvjFOxe1akYCdHyFo1ng5Q==", + "dependencies": { + "@babel/runtime": "^7.23.2" + } + }, + "node_modules/i18next-http-backend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-3.0.2.tgz", + "integrity": "sha512-PdlvPnvIp4E1sYi46Ik4tBYh/v/NbYfFFgTjkwFl0is8A18s7/bx9aXqsrOax9WUbeNS6mD2oix7Z0yGGf6m5g==", + "dependencies": { + "cross-fetch": "4.0.0" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -4462,6 +4536,25 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -4826,6 +4919,31 @@ "react": "^19.1.0" } }, + "node_modules/react-i18next": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.5.2.tgz", + "integrity": "sha512-ePODyXgmZQAOYTbZXQn5rRsSBu3Gszo69jxW6aKmlSgxKAI1fOhDwSu6bT4EKHciWPKQ7v7lPrjeiadR6Gi+1A==", + "dependencies": { + "@babel/runtime": "^7.25.0", + "html-parse-stringify": "^3.0.1" + }, + "peerDependencies": { + "i18next": ">= 23.2.3", + "react": ">= 16.8.0", + "typescript": "^5" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -5513,6 +5631,11 @@ "node": ">=8.0" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "node_modules/ts-api-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", @@ -5632,7 +5755,7 @@ "version": "5.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", - "dev": true, + "devOptional": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -5706,6 +5829,28 @@ "punycode": "^2.1.0" } }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 502a45c..e3e0dec 100644 --- a/package.json +++ b/package.json @@ -9,9 +9,13 @@ "lint": "next lint" }, "dependencies": { + "i18next": "^25.2.1", + "i18next-browser-languagedetector": "^8.1.0", + "i18next-http-backend": "^3.0.2", "next": "15.3.3", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "react-i18next": "^15.5.2" }, "devDependencies": { "@eslint/eslintrc": "^3", diff --git a/public/locales/en/routes.json b/public/locales/en/routes.json new file mode 100644 index 0000000..8fce860 --- /dev/null +++ b/public/locales/en/routes.json @@ -0,0 +1,4 @@ +{ + "home": "Home", + "about": "About" +} diff --git a/public/locales/fa/routes.json b/public/locales/fa/routes.json new file mode 100644 index 0000000..05778de --- /dev/null +++ b/public/locales/fa/routes.json @@ -0,0 +1,4 @@ +{ + "home": "صفحه‌ی اصلی", + "about": "درباره‌ی ما" +} diff --git a/src/app/aaa/page.tsx b/src/app/aaa/page.tsx new file mode 100644 index 0000000..bfcfb19 --- /dev/null +++ b/src/app/aaa/page.tsx @@ -0,0 +1,17 @@ +// ... existing imports ... + +async function getData() { + // Simulate a delay to show server-side data fetching + await new Promise((resolve) => setTimeout(resolve, 1000)); + return { message: 'This data was fetched on the server!' }; +} + +export default async function Home() { + const data = await getData(); + + return ( +
+ ssss +
+ ); +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 8da647e..6e86abd 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,16 +1,8 @@ import type { Metadata } from 'next'; import { Geist, Geist_Mono } from 'next/font/google'; import './globals.css'; - -const geistSans = Geist({ - variable: '--font-geist-sans', - subsets: ['latin'], -}); - -const geistMono = Geist_Mono({ - variable: '--font-geist-mono', - subsets: ['latin'], -}); +import { I18nextProvider } from 'react-i18next'; +import i18n from '../config/i18n'; export const metadata: Metadata = { title: 'Create Next App', @@ -19,16 +11,14 @@ export const metadata: Metadata = { export default function RootLayout({ children, -}: Readonly<{ +}: { children: React.ReactNode; -}>) { +}) { return ( - - {children} - + + {children} + ); } diff --git a/src/app/page.tsx b/src/app/page.tsx index ffefd17..bfcfb19 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,5 +1,4 @@ // ... existing imports ... -import Button from '../components/Button'; // Adjust the import path if necessary async function getData() { // Simulate a delay to show server-side data fetching @@ -12,44 +11,7 @@ export default async function Home() { return (
-
-

- {data.message} -

-
- -
- - - - -
- -
-

Standard Buttons:

-
- - - - -
- -

Sized Buttons:

-
- - - -
- -

Icon Buttons:

-
-
-
+ ssss
); } diff --git a/src/app/page/a.tsx b/src/app/page/a.tsx new file mode 100644 index 0000000..bfcfb19 --- /dev/null +++ b/src/app/page/a.tsx @@ -0,0 +1,17 @@ +// ... existing imports ... + +async function getData() { + // Simulate a delay to show server-side data fetching + await new Promise((resolve) => setTimeout(resolve, 1000)); + return { message: 'This data was fetched on the server!' }; +} + +export default async function Home() { + const data = await getData(); + + return ( +
+ ssss +
+ ); +} diff --git a/src/app/page/page.tsx b/src/app/page/page.tsx new file mode 100644 index 0000000..bfcfb19 --- /dev/null +++ b/src/app/page/page.tsx @@ -0,0 +1,17 @@ +// ... existing imports ... + +async function getData() { + // Simulate a delay to show server-side data fetching + await new Promise((resolve) => setTimeout(resolve, 1000)); + return { message: 'This data was fetched on the server!' }; +} + +export default async function Home() { + const data = await getData(); + + return ( +
+ ssss +
+ ); +} diff --git a/src/assets/constants/footerMenu/index.ts b/src/assets/constants/footerMenu/index.ts new file mode 100644 index 0000000..7de98b2 --- /dev/null +++ b/src/assets/constants/footerMenu/index.ts @@ -0,0 +1,5 @@ +import { quickLinks } from './quickLinks.const'; + +export const footerMenu = { + quickLinks, +}; diff --git a/src/assets/constants/footerMenu/quickLinks.const.ts b/src/assets/constants/footerMenu/quickLinks.const.ts new file mode 100644 index 0000000..3e28824 --- /dev/null +++ b/src/assets/constants/footerMenu/quickLinks.const.ts @@ -0,0 +1,7 @@ +import { appConstants } from '..'; + +export const quickLinks = [ + { + title: appConstants.routeFactory.home.title, + }, +] as any[]; diff --git a/src/assets/constants/index.ts b/src/assets/constants/index.ts new file mode 100644 index 0000000..a714da0 --- /dev/null +++ b/src/assets/constants/index.ts @@ -0,0 +1,7 @@ +import { footerMenu } from './footerMenu'; +import routeFactory from './routeFactory'; + +export const appConstants = { + routeFactory, + footerMenu, +}; diff --git a/src/assets/constants/routeFactory/index.ts b/src/assets/constants/routeFactory/index.ts new file mode 100644 index 0000000..9c0c981 --- /dev/null +++ b/src/assets/constants/routeFactory/index.ts @@ -0,0 +1,13 @@ +import { useTranslation } from 'react-i18next'; +const { t } = useTranslation('routes'); + +export default { + home: { + title: t('home'), + route: () => '/', + }, + about: { + title: t('about'), + route: () => '/about', + }, +}; diff --git a/src/components/layout/footer/Footer.tsx b/src/components/layout/footer/Footer.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/config/i18n.ts b/src/config/i18n.ts new file mode 100644 index 0000000..25d9662 --- /dev/null +++ b/src/config/i18n.ts @@ -0,0 +1,19 @@ +import i18n from 'i18next'; +import { initReactI18next } from 'react-i18next'; +import Backend from 'i18next-http-backend'; + +i18n + .use(Backend) + .use(initReactI18next) + .init({ + fallbackLng: 'en', + debug: false, + interpolation: { + escapeValue: false, + }, + backend: { + loadPath: '/locales/{{lng}}/{{ns}}.json', + } + }); + +export default i18n; \ No newline at end of file