diff --git a/next-i18next.config.js b/next-i18next.config.js
new file mode 100644
index 0000000..cff8bdd
--- /dev/null
+++ b/next-i18next.config.js
@@ -0,0 +1,6 @@
+module.exports = {
+ i18n: {
+ defaultLocale: "ru",
+ locales: ["ru", "en"],
+ },
+};
diff --git a/next.config.mjs b/next.config.mjs
index 7d73012..1f84d8d 100644
--- a/next.config.mjs
+++ b/next.config.mjs
@@ -21,6 +21,18 @@ const nextConfig = {
compiler: {
styledComponents: true,
},
+ i18n: {
+ defaultLocale: "ru",
+ locales: ["ru", "en"],
+ localeDetection: false, // отключить автоопределение по Accept-Language
+ localeCookie: {
+ name: "django_language",
+ httpOnly: false,
+ sameSite: false, // Django uses None, Next.js uses false for None
+ path: "/",
+ secure: false, // same as Django DEBUG mode
+ },
+ },
productionBrowserSourceMaps: true,
reactStrictMode: true,
diff --git a/package.json b/package.json
index a787dde..ce401bb 100644
--- a/package.json
+++ b/package.json
@@ -32,19 +32,22 @@
"@fortawesome/free-brands-svg-icons": "^6.0.0",
"@fortawesome/free-solid-svg-icons": "^6.0.0",
"@fortawesome/react-fontawesome": "^0.1.17",
- "@prisma/client": "^3.9.2",
+ "@prisma/client": "latest",
"@sentry/nextjs": "^6.17.9",
"date-fns": "^2.28.0",
"dayjs": "^1.10.7",
"gravatar-url": "^4.0.1",
+ "i18next": "^25.3.2",
"lru-cache": "^7.4.0",
"mobx": "^6.4.0",
"mobx-devtools-mst": "^0.9.30",
"mobx-react": "^7.3.0",
"mobx-state-tree": "^5.1.3",
"next": "^12.1.0",
+ "next-i18next": "^15.4.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
+ "react-i18next": "^15.6.1",
"react-linkify": "^1.0.0-alpha",
"react-redux": "^7.2.6",
"react-tooltip": "^4.2.21",
@@ -78,7 +81,7 @@
"prettier-plugin-packagejson": "^2.2.15",
"prettier-plugin-prisma": "^3.9.0",
"prettier-plugin-sh": "^0.8.1",
- "prisma": "^3.9.2",
+ "prisma": "latest",
"suppress-exit-code": "^1.0.0",
"typescript": "^4.5.5"
},
diff --git a/public/locales/en/common.json b/public/locales/en/common.json
new file mode 100644
index 0000000..0c87a24
--- /dev/null
+++ b/public/locales/en/common.json
@@ -0,0 +1,7 @@
+{
+ "welcome": "Welcome",
+ "dataPeriod": "Data Period",
+ "forPeriod": "For period:",
+ "filters": "Filters",
+ "hide": "Hide"
+}
diff --git a/public/locales/ru/common.json b/public/locales/ru/common.json
new file mode 100644
index 0000000..6566cfd
--- /dev/null
+++ b/public/locales/ru/common.json
@@ -0,0 +1,7 @@
+{
+ "welcome": "Добро пожаловать",
+ "dataPeriod": "Период данных",
+ "forPeriod": "За период:",
+ "filters": "Фильтры",
+ "hide": "Скрыть"
+}
diff --git a/src/components/inherited-map/components/filter-panel/filter-panel-normal.js b/src/components/inherited-map/components/filter-panel/filter-panel-normal.js
index 4c08434..62c1971 100644
--- a/src/components/inherited-map/components/filter-panel/filter-panel-normal.js
+++ b/src/components/inherited-map/components/filter-panel/filter-panel-normal.js
@@ -1,4 +1,5 @@
import { observer } from "mobx-react";
+import { useTranslation } from "next-i18next";
import * as React from "react";
import { useStore } from "../../models/root-store";
@@ -65,6 +66,7 @@ const CategoryTag = observer(({ filter }) => {
export const FilterPanelNormal = observer(() => {
const { filterStore } = useStore();
const { filters } = filterStore;
+ const { t } = useTranslation("common");
const mainFilters = filters.filter(
(currentFilter) => currentFilter.name !== "category",
@@ -83,7 +85,7 @@ export const FilterPanelNormal = observer(() => {
))}
-
Фильтры
+
{t("filters")}
{categoryFilters.map((currentFilter) => (
@@ -100,7 +102,7 @@ export const FilterPanelNormal = observer(() => {
- Скрыть
+ {t("hide")}
);
diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx
index 5c20887..bb14aac 100644
--- a/src/pages/_app.tsx
+++ b/src/pages/_app.tsx
@@ -2,6 +2,7 @@ import "../styles/inherited-scss/style.scss";
import { UserProvider } from "@auth0/nextjs-auth0";
import { AppProps } from "next/app";
+import { appWithTranslation } from "next-i18next";
import * as React from "react";
import { ThemeProvider } from "styled-components";
@@ -24,4 +25,4 @@ const App: React.VoidFunctionComponent
= ({
);
};
-export default App;
+export default appWithTranslation(App);
diff --git a/src/pages/iframes/map.tsx b/src/pages/iframes/map.tsx
index 5752195..9bb989a 100644
--- a/src/pages/iframes/map.tsx
+++ b/src/pages/iframes/map.tsx
@@ -1,6 +1,8 @@
import { NextPage } from "next";
import dynamic from "next/dynamic";
import Script from "next/script";
+import { useTranslation } from "next-i18next";
+import { serverSideTranslations } from "next-i18next/serverSideTranslations";
import * as React from "react";
import { usePostLocationSearchChangesToIframeParent } from "../../shared/django-helpers";
@@ -13,6 +15,7 @@ const InheritedMap = dynamic(
const MapIframePage: NextPage = () => {
usePostLocationSearchChangesToIframeParent();
+ const { t } = useTranslation("common");
return (
<>
@@ -29,4 +32,12 @@ const MapIframePage: NextPage = () => {
);
};
+export async function getServerSideProps({ locale }: { locale: string }) {
+ return {
+ props: {
+ ...(await serverSideTranslations(locale ?? "ru", ["common"])),
+ },
+ };
+}
+
export default MapIframePage;
diff --git a/yarn.lock b/yarn.lock
index 86421de..8368aea 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -147,6 +147,13 @@ __metadata:
languageName: node
linkType: hard
+"@babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.27.6":
+ version: 7.28.2
+ resolution: "@babel/runtime@npm:7.28.2"
+ checksum: 8673eb2311752929f5b0167f42cff4cc1d5fadddd0394baca27d06c1618680ffcf95e9f01061f5c4dc3f6a32b6bbf500e7762c02dc22bcd273c2947b9774ddad
+ languageName: node
+ linkType: hard
+
"@babel/template@npm:^7.16.7":
version: 7.16.7
resolution: "@babel/template@npm:7.16.7"
@@ -568,31 +575,73 @@ __metadata:
languageName: node
linkType: hard
-"@prisma/client@npm:^3.9.2":
- version: 3.9.2
- resolution: "@prisma/client@npm:3.9.2"
- dependencies:
- "@prisma/engines-version": 3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009
+"@prisma/client@npm:latest":
+ version: 6.12.0
+ resolution: "@prisma/client@npm:6.12.0"
peerDependencies:
prisma: "*"
+ typescript: ">=5.1.0"
peerDependenciesMeta:
prisma:
optional: true
- checksum: 5b4b8f252624250f609d57ed3939f3dbecb174c297691476050f48d6c24dd41ca2f70f9e5a52729a4e875527e56a2d564a116c0ada8f5fc935c558f09d2759e3
+ typescript:
+ optional: true
+ checksum: 3d6d9354b57872b58b97c01e3e90d1359d9dc47fd081f0db8ce81af0b3a1f5277678424c5a5a2f6a801ec0c87db3612da1e8be18913ee62ec54e6b4428eb6c96
languageName: node
linkType: hard
-"@prisma/engines-version@npm:3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009":
- version: 3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009
- resolution: "@prisma/engines-version@npm:3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009"
- checksum: 413d478fc1980604de1f46a0d53ae6c752965283a7d8c51d8fb3881c371b4a71ab4aa10002dba411d961286caf1141871c3c85d209a316421cdf1e1fdac71b4e
+"@prisma/config@npm:6.12.0":
+ version: 6.12.0
+ resolution: "@prisma/config@npm:6.12.0"
+ dependencies:
+ jiti: 2.4.2
+ checksum: b06b8fb9f8f07e44dcba250e059551d0439c82b5c2957385d5132e9040e7e40e5bc7bc3620cc671092b880552ad6f7247ae76d8288851ab06c8d01bfba6c7dfc
languageName: node
linkType: hard
-"@prisma/engines@npm:3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009":
- version: 3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009
- resolution: "@prisma/engines@npm:3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009"
- checksum: f934a02f0d12b67a8b878da5b854a2df0b1d5adbedb9d6df552dddcb4f58af9401268c2066180a337daa0fd22d9005eae2197bf8a4cc7b9e1a20764fe93f1244
+"@prisma/debug@npm:6.12.0":
+ version: 6.12.0
+ resolution: "@prisma/debug@npm:6.12.0"
+ checksum: eebf9aed967964f8187cc7b3df0205e25f99a2874163b09031a7283748f038d841a076809b1c593a01dc198d1736f562f11b06e66be01edbf1642a3a2f357174
+ languageName: node
+ linkType: hard
+
+"@prisma/engines-version@npm:6.12.0-15.8047c96bbd92db98a2abc7c9323ce77c02c89dbc":
+ version: 6.12.0-15.8047c96bbd92db98a2abc7c9323ce77c02c89dbc
+ resolution: "@prisma/engines-version@npm:6.12.0-15.8047c96bbd92db98a2abc7c9323ce77c02c89dbc"
+ checksum: 108e213a2cc3f85cf11c74c8b17f16f89b36cfc1a2146f918c935da0b9f9f3b0b1c59cdb4edf30c81767182ab9de5730330105af25d8b9cb6eacf400be4f7dfd
+ languageName: node
+ linkType: hard
+
+"@prisma/engines@npm:6.12.0":
+ version: 6.12.0
+ resolution: "@prisma/engines@npm:6.12.0"
+ dependencies:
+ "@prisma/debug": 6.12.0
+ "@prisma/engines-version": 6.12.0-15.8047c96bbd92db98a2abc7c9323ce77c02c89dbc
+ "@prisma/fetch-engine": 6.12.0
+ "@prisma/get-platform": 6.12.0
+ checksum: ab52544ce07ca375f4dbda448952a9ae7a920f9aa0385a7a02a082a12392c20fa2a0e450951dd4255a9918ec92ef4acc87290993c3bb9fa2cd55c4600b6c8919
+ languageName: node
+ linkType: hard
+
+"@prisma/fetch-engine@npm:6.12.0":
+ version: 6.12.0
+ resolution: "@prisma/fetch-engine@npm:6.12.0"
+ dependencies:
+ "@prisma/debug": 6.12.0
+ "@prisma/engines-version": 6.12.0-15.8047c96bbd92db98a2abc7c9323ce77c02c89dbc
+ "@prisma/get-platform": 6.12.0
+ checksum: 16ebe12e4d9ae03defcc08fee43cc8f4cd29edf57032df1c88070576fb23dd99de3dbc10a6dea702c8e5ff24e57e99efc050a7c65821b1c1a4575eac64a19540
+ languageName: node
+ linkType: hard
+
+"@prisma/get-platform@npm:6.12.0":
+ version: 6.12.0
+ resolution: "@prisma/get-platform@npm:6.12.0"
+ dependencies:
+ "@prisma/debug": 6.12.0
+ checksum: 64a9594088eb840fa10f3e42e3ef6428a136cb5736cb133824ce220216b5179352254e37e296568bf2afaa0db3eb8a600f120d9e91e08a1b18fb515474140112
languageName: node
linkType: hard
@@ -851,6 +900,17 @@ __metadata:
languageName: node
linkType: hard
+"@types/hoist-non-react-statics@npm:^3.3.6":
+ version: 3.3.7
+ resolution: "@types/hoist-non-react-statics@npm:3.3.7"
+ dependencies:
+ hoist-non-react-statics: ^3.3.0
+ peerDependencies:
+ "@types/react": "*"
+ checksum: 13f610572c073970b3f43cc446396974fed786fee6eac2d6fd4b0ca5c985f13e79d4a0de58af4e5b4c68470d808567c3a14108d98edb7d526d4d46c8ec851ed1
+ languageName: node
+ linkType: hard
+
"@types/http-cache-semantics@npm:*":
version: 4.0.1
resolution: "@types/http-cache-semantics@npm:4.0.1"
@@ -1805,6 +1865,13 @@ __metadata:
languageName: node
linkType: hard
+"core-js@npm:^3":
+ version: 3.44.0
+ resolution: "core-js@npm:3.44.0"
+ checksum: 1a9fca319aaeb8ae58764f9566a92d5fe7f609749dd1e5e0af4e1a0e4c6f0402d51b5ad379decb6ee722df0a65f0897a1ed1da397888e53437a52d3c105724a5
+ languageName: node
+ linkType: hard
+
"core-util-is@npm:~1.0.0":
version: 1.0.3
resolution: "core-util-is@npm:1.0.3"
@@ -3061,6 +3128,15 @@ __metadata:
languageName: node
linkType: hard
+"html-parse-stringify@npm:^3.0.1":
+ version: 3.0.1
+ resolution: "html-parse-stringify@npm:3.0.1"
+ dependencies:
+ void-elements: 3.1.0
+ checksum: 334fdebd4b5c355dba8e95284cead6f62bf865a2359da2759b039db58c805646350016d2017875718bc3c4b9bf81a0d11be5ee0cf4774a3a5a7b97cde21cfd67
+ languageName: node
+ linkType: hard
+
"http-cache-semantics@npm:^4.0.0, http-cache-semantics@npm:^4.1.0":
version: 4.1.0
resolution: "http-cache-semantics@npm:4.1.0"
@@ -3151,6 +3227,27 @@ __metadata:
languageName: node
linkType: hard
+"i18next-fs-backend@npm:^2.6.0":
+ version: 2.6.0
+ resolution: "i18next-fs-backend@npm:2.6.0"
+ checksum: 2a34a6f0563f7cc5c98de93e66fff66696eaf19b295d073fb1fef426db75783ecfab10b0251272957c307cbb3ffb4e9b5073c17ddb10be2e352d9b6e6ee71a5a
+ languageName: node
+ linkType: hard
+
+"i18next@npm:^25.3.2":
+ version: 25.3.2
+ resolution: "i18next@npm:25.3.2"
+ dependencies:
+ "@babel/runtime": ^7.27.6
+ peerDependencies:
+ typescript: ^5
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: e0ee33b6d7f1e8ce3aa2a6a139e673686a5651903fdfeec47d10b32737342045be6607da73020f94b07edcee9173d940fe4e8062d1e2183bbf482141624bda3e
+ languageName: node
+ linkType: hard
+
"iconv-lite@npm:^0.6.2":
version: 0.6.3
resolution: "iconv-lite@npm:0.6.3"
@@ -3606,6 +3703,15 @@ __metadata:
languageName: node
linkType: hard
+"jiti@npm:2.4.2":
+ version: 2.4.2
+ resolution: "jiti@npm:2.4.2"
+ bin:
+ jiti: lib/jiti-cli.mjs
+ checksum: c6c30c7b6b293e9f26addfb332b63d964a9f143cdd2cf5e946dbe5143db89f7c1b50ad9223b77fb1f6ddb0b9c5ecef995fea024ecf7d2861d285d779cde66e1e
+ languageName: node
+ linkType: hard
+
"joi@npm:^17.5.0":
version: 17.6.0
resolution: "joi@npm:17.6.0"
@@ -4418,6 +4524,24 @@ __metadata:
languageName: node
linkType: hard
+"next-i18next@npm:^15.4.2":
+ version: 15.4.2
+ resolution: "next-i18next@npm:15.4.2"
+ dependencies:
+ "@babel/runtime": ^7.23.2
+ "@types/hoist-non-react-statics": ^3.3.6
+ core-js: ^3
+ hoist-non-react-statics: ^3.3.2
+ i18next-fs-backend: ^2.6.0
+ peerDependencies:
+ i18next: ">= 23.7.13"
+ next: ">= 12.0.0"
+ react: ">= 17.0.2"
+ react-i18next: ">= 13.5.0"
+ checksum: d5c3d675b66ae4c65f96c040a031df0c81c23d2562c398f560c3e629e47fb67061053c0bb58cce41b9e45106a0c9cf7db05ef464991a6908ed5bb8fd85f50634
+ languageName: node
+ linkType: hard
+
"next@npm:^12.0.10, next@npm:^12.1.0":
version: 12.1.0
resolution: "next@npm:12.1.0"
@@ -5205,15 +5329,20 @@ __metadata:
languageName: node
linkType: hard
-"prisma@npm:^3.9.2":
- version: 3.9.2
- resolution: "prisma@npm:3.9.2"
+"prisma@npm:latest":
+ version: 6.12.0
+ resolution: "prisma@npm:6.12.0"
dependencies:
- "@prisma/engines": 3.9.0-58.bcc2ff906db47790ee902e7bbc76d7ffb1893009
+ "@prisma/config": 6.12.0
+ "@prisma/engines": 6.12.0
+ peerDependencies:
+ typescript: ">=5.1.0"
+ peerDependenciesMeta:
+ typescript:
+ optional: true
bin:
prisma: build/index.js
- prisma2: build/index.js
- checksum: 4070b61b09f45229680e1beeb14a95716353493032abaac9f6664bc60eba8279e165d446e8a12457a6d6a0e80d100c09228d00e7e1986e504fc8ceb9a16316f2
+ checksum: a8f18bfe55514048ceb2263467472032a0d0b8f2ac95510bc493c903efa57cf06dfa32bf5fdd16da360e11e86e207f1e24b258215a01efbcace4c45b39dd958c
languageName: node
linkType: hard
@@ -5333,6 +5462,27 @@ __metadata:
languageName: node
linkType: hard
+"react-i18next@npm:^15.6.1":
+ version: 15.6.1
+ resolution: "react-i18next@npm:15.6.1"
+ dependencies:
+ "@babel/runtime": ^7.27.6
+ 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
+ checksum: f4342cc8ad6c4f2b5e4e8ac663da8848ad6402c3713ca542f4ad3a84b21ca10678c443ff9ca8250fa512e6e5c0000fc83b68797ae734d7d15b7ff09d5c5e9004
+ languageName: node
+ linkType: hard
+
"react-is@npm:^16.13.1, react-is@npm:^16.7.0":
version: 16.13.1
resolution: "react-is@npm:16.13.1"
@@ -5672,7 +5822,7 @@ __metadata:
"@kachkaev/markdownlint-config": ^0.3.0
"@netlify/plugin-nextjs": ^4.2.7
"@next/eslint-plugin-next": ^12.1.0
- "@prisma/client": ^3.9.2
+ "@prisma/client": latest
"@sentry/nextjs": ^6.17.9
"@types/lru-cache": ^5.1.1
"@types/node": ^17.0.18
@@ -5688,6 +5838,7 @@ __metadata:
execa: ^6.1.0
gravatar-url: ^4.0.1
husky: ^7.0.4
+ i18next: ^25.3.2
lint-staged: ^12.3.4
lru-cache: ^7.4.0
markdownlint-cli: ^0.31.1
@@ -5696,14 +5847,16 @@ __metadata:
mobx-react: ^7.3.0
mobx-state-tree: ^5.1.3
next: ^12.1.0
+ next-i18next: ^15.4.2
npm-run-all: ^4.1.5
prettier: ^2.5.1
prettier-plugin-packagejson: ^2.2.15
prettier-plugin-prisma: ^3.9.0
prettier-plugin-sh: ^0.8.1
- prisma: ^3.9.2
+ prisma: latest
react: ^17.0.2
react-dom: ^17.0.2
+ react-i18next: ^15.6.1
react-linkify: ^1.0.0-alpha
react-redux: ^7.2.6
react-tooltip: ^4.2.21
@@ -6761,6 +6914,13 @@ __metadata:
languageName: node
linkType: hard
+"void-elements@npm:3.1.0":
+ version: 3.1.0
+ resolution: "void-elements@npm:3.1.0"
+ checksum: 0390f818107fa8fce55bb0a5c3f661056001c1d5a2a48c28d582d4d847347c2ab5b7f8272314cac58acf62345126b6b09bea623a185935f6b1c3bbce0dfd7f7f
+ languageName: node
+ linkType: hard
+
"vscode-json-languageservice@npm:^4.1.6":
version: 4.2.0
resolution: "vscode-json-languageservice@npm:4.2.0"