diff --git a/next.config.js b/next.config.js index 50f8420..d6be20a 100644 --- a/next.config.js +++ b/next.config.js @@ -4,6 +4,10 @@ const nextConfig = { images: { unoptimized: true, }, + i18n: { + locales: ["ru", "en"], + defaultLocale: "ru", + }, }; module.exports = nextConfig; diff --git a/package.json b/package.json index 2db5031..8c63ca0 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "eslint": "8.36.0", "eslint-config-next": "13.2.4", "next": "13.2.4", + "next-intl": "^2.12.0", "postcss": "^8.4.21", "postcss-nesting": "^11.2.1", "react": "^18.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9587057..7078666 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,6 +10,7 @@ specifiers: eslint: 8.36.0 eslint-config-next: 13.2.4 next: 13.2.4 + next-intl: ^2.12.0 postcss: ^8.4.21 postcss-nesting: ^11.2.1 react: ^18.2.0 @@ -26,6 +27,7 @@ dependencies: eslint: 8.36.0 eslint-config-next: 13.2.4_j4766f7ecgqbon3u7zlxn5zszu next: 13.2.4_biqbaboplfbrettd7655fr4n2y + next-intl: 2.12.0_next@13.2.4+react@18.2.0 postcss: 8.4.21 postcss-nesting: 11.2.1_postcss@8.4.21 react: 18.2.0 @@ -290,6 +292,53 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: false + /@formatjs/ecma402-abstract/1.11.4: + resolution: {integrity: sha512-EBikYFp2JCdIfGEb5G9dyCkTGDmC57KSHhRQOC3aYxoPWVZvfWCDjZwkGYHN7Lis/fmuWl906bnNTJifDQ3sXw==} + dependencies: + '@formatjs/intl-localematcher': 0.2.25 + tslib: 2.5.0 + dev: false + + /@formatjs/ecma402-abstract/1.14.3: + resolution: {integrity: sha512-SlsbRC/RX+/zg4AApWIFNDdkLtFbkq3LNoZWXZCE/nHVKqoIJyaoQyge/I0Y38vLxowUn9KTtXgusLD91+orbg==} + dependencies: + '@formatjs/intl-localematcher': 0.2.32 + tslib: 2.5.0 + dev: false + + /@formatjs/fast-memoize/1.2.1: + resolution: {integrity: sha512-Rg0e76nomkz3vF9IPlKeV+Qynok0r7YZjL6syLz4/urSg0IbjPZCB/iYUMNsYA643gh4mgrX3T7KEIFIxJBQeg==} + dependencies: + tslib: 2.5.0 + dev: false + + /@formatjs/icu-messageformat-parser/2.1.0: + resolution: {integrity: sha512-Qxv/lmCN6hKpBSss2uQ8IROVnta2r9jd3ymUEIjm2UyIkUCHVcbUVRGL/KS/wv7876edvsPe+hjHVJ4z8YuVaw==} + dependencies: + '@formatjs/ecma402-abstract': 1.11.4 + '@formatjs/icu-skeleton-parser': 1.3.6 + tslib: 2.5.0 + dev: false + + /@formatjs/icu-skeleton-parser/1.3.6: + resolution: {integrity: sha512-I96mOxvml/YLrwU2Txnd4klA7V8fRhb6JG/4hm3VMNmeJo1F03IpV2L3wWt7EweqNLES59SZ4d6hVOPCSf80Bg==} + dependencies: + '@formatjs/ecma402-abstract': 1.11.4 + tslib: 2.5.0 + dev: false + + /@formatjs/intl-localematcher/0.2.25: + resolution: {integrity: sha512-YmLcX70BxoSopLFdLr1Ds99NdlTI2oWoLbaUW2M406lxOIPzE1KQhRz2fPUkq34xVZQaihCoU29h0KK7An3bhA==} + dependencies: + tslib: 2.5.0 + dev: false + + /@formatjs/intl-localematcher/0.2.32: + resolution: {integrity: sha512-k/MEBstff4sttohyEpXxCmC3MqbUn9VvHGlZ8fauLzkbwXmVrEeyzS+4uhrvAk9DWU9/7otYWxyDox4nT/KVLQ==} + dependencies: + tslib: 2.5.0 + dev: false + /@humanwhocodes/config-array/0.11.8: resolution: {integrity: sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==} engines: {node: '>=10.10.0'} @@ -757,6 +806,10 @@ packages: eslint-visitor-keys: 3.3.0 dev: false + /accept-language-parser/1.5.0: + resolution: {integrity: sha512-QhyTbMLYo0BBGg1aWbeMG4ekWtds/31BrEU+DONOg/7ax23vxpL03Pb7/zBmha2v7vdD3AyzZVWBVGEZxKOXWw==} + dev: false + /acorn-jsx/5.3.2_acorn@8.8.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -1853,6 +1906,15 @@ packages: side-channel: 1.0.4 dev: false + /intl-messageformat/9.13.0: + resolution: {integrity: sha512-7sGC7QnSQGa5LZP7bXLDhVDtQOeKGeBFGHF2Y8LVBwYZoQZCgWeKoPGTa5GMG8g/TzDgeXuYJQis7Ggiw2xTOw==} + dependencies: + '@formatjs/ecma402-abstract': 1.11.4 + '@formatjs/fast-memoize': 1.2.1 + '@formatjs/icu-messageformat-parser': 2.1.0 + tslib: 2.5.0 + dev: false + /is-arguments/1.1.1: resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} engines: {node: '>= 0.4'} @@ -2172,6 +2234,19 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: false + /next-intl/2.12.0_next@13.2.4+react@18.2.0: + resolution: {integrity: sha512-UWKLA3BIsezFo/OJelGYmJL3BsztApo2mgvmwHMDbTsuBJx0x4SaIIPapnPHPzMhUbppZIbY70xNIULHwn++hg==} + engines: {node: '>=10'} + peerDependencies: + next: ^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + accept-language-parser: 1.5.0 + next: 13.2.4_biqbaboplfbrettd7655fr4n2y + react: 18.2.0 + use-intl: 2.12.0_react@18.2.0 + dev: false + /next/13.2.4_biqbaboplfbrettd7655fr4n2y: resolution: {integrity: sha512-g1I30317cThkEpvzfXujf0O4wtaQHtDCLhlivwlTJ885Ld+eOgcz7r3TGQzeU+cSRoNHtD8tsJgzxVdYojFssw==} engines: {node: '>=14.6.0'} @@ -2855,6 +2930,17 @@ packages: tslib: 2.5.0 dev: false + /use-intl/2.12.0_react@18.2.0: + resolution: {integrity: sha512-LcmAqn78o6Ii9wsLERKAXI9QfiSVBzY3u+mSh6YCLUKhDhr7WHqTBfhEV1gZvdwy7mydhwWQUyQ9Zy5XHuUOAQ==} + engines: {node: '>=10'} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + '@formatjs/ecma402-abstract': 1.14.3 + intl-messageformat: 9.13.0 + react: 18.2.0 + dev: false + /use-sidecar/1.1.2_pmekkgnqduwlme35zpnqhenc34: resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==} engines: {node: '>=10'} diff --git a/src/components/header/Header.js b/src/components/header/Header.js index 29e7fb0..a29689a 100644 --- a/src/components/header/Header.js +++ b/src/components/header/Header.js @@ -1,9 +1,12 @@ import { useEffect } from "react"; +import { useTranslations } from "next-intl"; import cn from "classnames"; import styles from "./Header.module.css"; import { initSmoothScroll } from "./smooth-scroll"; export function Header() { + const t = useTranslations("Dev"); + useEffect(() => { initSmoothScroll(); }, []); @@ -11,19 +14,16 @@ export function Header() { return (
-

- Это Код Екатеринбурга — команда, которая сделает - невозможное. Невыполнимое, сложное и безумное. Сделает то, - что никто не сможет. Это тот проект, о котором - вы мечтали. Это — проект судьбы. -

+

- Узнать, что мы будем делать - + dangerouslySetInnerHTML={{ __html: t.raw("learnMore") }} + />
); diff --git a/src/locales/en.json b/src/locales/en.json new file mode 100644 index 0000000..7c71829 --- /dev/null +++ b/src/locales/en.json @@ -0,0 +1,7 @@ +{ + "Dev": { + "title": "Ekaterinburg code", + "header": "This is the Yekaterinburg Code - a team that will achieve the impossible. The unattainable, complex, and insane. They will do what no one else can. This is the project you've dreamed of. It is the project of destiny.", + "learnMore": "Find out what we will be doing" + } +} diff --git a/src/locales/ru.json b/src/locales/ru.json new file mode 100644 index 0000000..42ea290 --- /dev/null +++ b/src/locales/ru.json @@ -0,0 +1,7 @@ +{ + "Dev": { + "title": "Код Екатеринбурга", + "header": "Это Код Екатеринбурга — команда, которая сделает невозможное. Невыполнимое, сложное и безумное. Сделает то, что никто не сможет. Это тот проект, о котором вы мечтали. Это — проект судьбы.", + "learnMore": "Узнать, что мы будем делать" + } +} diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 52cf446..fc20b58 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -1,8 +1,13 @@ +import { NextIntlProvider } from "next-intl"; +import type { AppProps } from "next/app"; import "@/styles/globals.css"; import "../../public/fonts/index.css"; import "../../public/font-jetbrains-mono/index.css"; -import type { AppProps } from "next/app"; export default function App({ Component, pageProps }: AppProps) { - return ; + return ( + + + + ); } diff --git a/src/pages/index.tsx b/src/pages/index.tsx index e047c21..5a10349 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,5 +1,6 @@ /* eslint-disable @next/next/no-img-element */ import Head from "next/head"; +import { useTranslations } from "next-intl"; import cn from "classnames"; import styles from "@/components/page/Page.module.css"; import { Preview } from "@/components/preview/Preview"; @@ -9,12 +10,15 @@ import { Road } from "@/components/road/Road"; import { Iframe } from "@/components/iframe/Iframe"; import { Team } from "@/components/team/Team"; import { MainAction } from "@/components/action/MainAction"; +import { GetStaticProps } from "next"; export default function Home() { + const t = useTranslations("Dev"); + return ( <> - Код Екатеринбурга + {t("title")}
@@ -146,3 +150,11 @@ export default function Home() { ); } + +export const getStaticProps: GetStaticProps = async (context) => { + return { + props: { + messages: (await import(`../locales/${context.locale}.json`)).default, + }, + }; +};