From 9ddf055abaff8a1f824076330ad2262f506fb266 Mon Sep 17 00:00:00 2001 From: ariari04 Date: Wed, 14 Aug 2024 09:51:28 +0600 Subject: [PATCH] Add next-intl --- messages/en.json | 62 ++++++++++ messages/kg.json | 62 ++++++++++ messages/ru.json | 62 ++++++++++ next.config.mjs | 18 ++- package-lock.json | 104 ++++++++++++++++ package.json | 11 +- src/app/[locale]/globals.css | 3 + src/app/[locale]/layout.tsx | 31 +++++ src/app/[locale]/page.tsx | 5 + src/app/favicon.ico | Bin 25931 -> 0 bytes src/app/globals.css | 33 ----- src/app/layout.tsx | 23 +--- src/app/not-found.tsx | 15 +++ src/app/page.tsx | 116 +----------------- src/app/shared/config/navigation.ts | 7 ++ src/app/shared/variables/links_footer.ts | 17 +++ src/app/widgets/Footer/Footer.tsx | 89 ++++++++++++++ .../widgets/Footer/assets/app-store-btn.svg | 31 +++++ src/app/widgets/Footer/assets/facebook.svg | 14 +++ src/app/widgets/Footer/assets/instagram.svg | 16 +++ .../widgets/Footer/assets/play-market-btn.svg | 15 +++ src/app/widgets/Footer/assets/youtube.svg | 14 +++ src/app/widgets/NotFound/NotFound.tsx | 30 +++++ src/app/widgets/NotFound/assets/not-found.svg | 16 +++ src/i18n.ts | 12 ++ src/middleware.ts | 13 ++ tailwind.config.ts | 5 + 27 files changed, 654 insertions(+), 170 deletions(-) create mode 100644 messages/en.json create mode 100644 messages/kg.json create mode 100644 messages/ru.json create mode 100644 src/app/[locale]/globals.css create mode 100644 src/app/[locale]/layout.tsx create mode 100644 src/app/[locale]/page.tsx delete mode 100644 src/app/favicon.ico delete mode 100644 src/app/globals.css create mode 100644 src/app/not-found.tsx create mode 100644 src/app/shared/config/navigation.ts create mode 100644 src/app/shared/variables/links_footer.ts create mode 100644 src/app/widgets/Footer/Footer.tsx create mode 100644 src/app/widgets/Footer/assets/app-store-btn.svg create mode 100644 src/app/widgets/Footer/assets/facebook.svg create mode 100644 src/app/widgets/Footer/assets/instagram.svg create mode 100644 src/app/widgets/Footer/assets/play-market-btn.svg create mode 100644 src/app/widgets/Footer/assets/youtube.svg create mode 100644 src/app/widgets/NotFound/NotFound.tsx create mode 100644 src/app/widgets/NotFound/assets/not-found.svg create mode 100644 src/i18n.ts create mode 100644 src/middleware.ts diff --git a/messages/en.json b/messages/en.json new file mode 100644 index 0000000..c13fd53 --- /dev/null +++ b/messages/en.json @@ -0,0 +1,62 @@ +{ + "general": { + "date": "Date", + "address": "Address", + "status": "Status", + "description": "Description", + "reviews": "Reviews", + "rating": "Rating", + "review": "Review", + "write_comment": "Write Comment", + "search": "Search", + "search_for": "Search For", + "city": "City", + "added_roads": "Added Roads", + "broken_roads": "Broken Roads", + "accident_hotspots": "Accident Hotspots", + "local_defects": "Local Defects", + "repair_plans": "Repair Plans", + "repaired": "Repaired", + "fixed_local_defects": "Fixed Local Defects", + "news": "News", + "details": "Details", + "navigation": "Navigation", + "contacts": "Contacts", + "download_our_app": "Download our app", + "back": "Back", + "save": "Save", + "saving": "Saving", + "cancel": "Cancel", + "cancellation": "Cancellation", + "save_changes": "Save Changes", + "send": "Send", + "receive": "Receive", + "delete": "Delete", + "show_on_map": "Show on Map", + "author_of_appeal": "Author of Appeal", + "enter_city": "Enter City", + "page_not_found": "Page Not Found (404)", + "incorrect_address_or_nonexistent_page": "Incorrect Address or Nonexistent Page.", + "home": "Home", + "first_name": "First Name", + "last_name": "Last Name", + "email": "Email" + }, + "disclaimer": { + "text": "This website is funded by the European Union. Its contents are the sole responsibility of Transparency International Kyrgyzstan and do not necessarily reflect the views of the European Union." + }, + "navigation": { + "home": "Home", + "about_us": "About Us", + "privacy": "Privacy Policy", + "support": "Support", + "statistics": "Statistics", + "news": "News", + "volunteers": "Volunteers", + "profile": "Profile", + "login": "Login" + }, + "rights": { + "text": "All rights reserved" + } +} diff --git a/messages/kg.json b/messages/kg.json new file mode 100644 index 0000000..b499500 --- /dev/null +++ b/messages/kg.json @@ -0,0 +1,62 @@ +{ + "general": { + "date": "Күн", + "address": "Дарек", + "status": "Статус", + "description": "Көйгөй", + "reviews": "Комментарийлер", + "rating": "Рейтинг", + "review": "Комментарий", + "write_comment": "Комментарий жазуу", + "search": "Издөө", + "search_for": "Издөө", + "city": "Шаар", + "added_roads": "Белгилөөлөр", + "broken_roads": "Бузулган жолдор", + "accident_hotspots": "Авариялык абалда", + "local_defects": "Жергиликтүү кемчиликтер", + "repair_plans": "Ремонттоо планында", + "repaired": "Ремонттолгон", + "fixed_local_defects": "Жергиликтүү оңдолгон жолдор", + "news": "Жаңылыктар", + "details": "Кененирээк маалымат", + "navigation": "Навигация", + "contacts": "Байланыш", + "download_our_app": "Биздин колдонмону жүктөңүз", + "back": "Артка", + "save": "Сактоо", + "saving": "Сакталат", + "cancel": "Жокко чыгаруу", + "cancellation": "Жокко чыгаруу", + "save_changes": "Өзгөртүүлөрдү сактоо", + "send": "Жиберүү", + "receive": "Алуу", + "delete": "Жок кылуу", + "show_on_map": "Картада көрсөтүү", + "author_of_appeal": "Өтүнүчтүн автору", + "enter_city": "Жерликти киргизиңиз", + "page_not_found": "Барак табылган жок (404)", + "incorrect_address_or_nonexistent_page": "Дарек туура эмес же баракча жок", + "home": "Башкы бет", + "first_name": "Аты-жөнү", + "last_name": "Фамилия", + "email": "Электрондук почта" + }, + "navigation": { + "home": "Башкы бет", + "about_us": "Биз жөнүндө", + "privacy": "Купуялык саясаты", + "support": "Колдоо", + "statistics": "Статистика", + "news": "Жаңылыктар", + "volunteers": "Ыктыярчылар", + "profile": "Профиль", + "login": "Кирүү" + }, + "disclaimer": { + "text": "Бул веб-сайт Европа Биримдиги тарабынан каржыланат. Анын мазмуну үчүн Трансперенси Интернешнл Кыргызстан гана жоопкерчиликтүү жана ал Европа Биримдигинин көз карашын сөзсүз түрдө чагылдырбайт." + }, + "rights": { + "text": "Бардык укуктар корголгон" + } +} diff --git a/messages/ru.json b/messages/ru.json new file mode 100644 index 0000000..ee97ef0 --- /dev/null +++ b/messages/ru.json @@ -0,0 +1,62 @@ +{ + "general": { + "date": "Дата", + "address": "Адрес", + "status": "Статус", + "description": "Описание", + "reviews": "Комментарии", + "rating": "Рейтинг", + "review": "Комментарий", + "write_comment": "Написать комментарий", + "search": "Поиск", + "search_for": "Искать", + "city": "Город", + "added_roads": "Добавлено дорог", + "broken_roads": "Разбитых дорог", + "accident_hotspots": "Очагов аварийности", + "local_defects": "Локальных дефектов", + "repair_plans": "В планах ремонта", + "repaired": "Отремонтировано", + "fixed_local_defects": "Локальных дефектов исправлено", + "news": "Новости", + "details": "Подробнее", + "navigation": "Навигация", + "contacts": "Контакты", + "download_our_app": "Скачивай наше приложение", + "back": "Назад", + "save": "Сохранить", + "saving": "Сохранение", + "cancel": "Отменить", + "cancellation": "Отмена", + "save_changes": "Сохранить изменения", + "send": "Отправить", + "receive": "Получить", + "delete": "Удалить", + "show_on_map": "Показать на карте", + "author_of_appeal": "Автор обращения", + "enter_city": "Введите населенный пункт", + "page_not_found": "Страница не найдена (404)", + "incorrect_address_or_nonexistent_page": "Неправильно набран адрес или такой страницы не существует.", + "home": "На главную", + "first_name": "Имя", + "last_name": "Фамилия", + "email": "Электронная почта" + }, + "navigation": { + "home": "Главная", + "about_us": "О нас", + "privacy": "Политика конфиденциальности", + "support": "Поддержка", + "statistics": "Статистика", + "news": "Новости", + "volunteers": "Волонтеры", + "profile": "Профиль", + "login": "Войти" + }, + "disclaimer": { + "text": "Этот веб-сайт финансируется Европейским Союзом. Ответственность за его содержание лежит исключительно на Трансперенси Интернешнл Кыргызстан и не обязательно отражает точку зрения Европейского Союза." + }, + "rights": { + "text": "Все права защищены" + } +} diff --git a/next.config.mjs b/next.config.mjs index 4678774..9e682c8 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,4 +1,16 @@ -/** @type {import('next').NextConfig} */ -const nextConfig = {}; +import createNextIntlPlugin from "next-intl/plugin"; +const withNextIntl = createNextIntlPlugin(); -export default nextConfig; +/** @type {import('next').NextConfig} */ +const nextConfig = { + images: { + remotePatterns: [ + { + protocol: "https", + hostname: "**", + }, + ], + }, +}; + +export default withNextIntl(nextConfig); diff --git a/package-lock.json b/package-lock.json index b1b5890..4251bf6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.1.0", "dependencies": { "next": "14.2.5", + "next-intl": "^3.17.2", "react": "^18", "react-dom": "^18" }, @@ -91,6 +92,58 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@formatjs/ecma402-abstract": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.0.0.tgz", + "integrity": "sha512-rRqXOqdFmk7RYvj4khklyqzcfQl9vEL/usogncBHRZfZBDOwMGuSRNFl02fu5KGHXdbinju+YXyuR+Nk8xlr/g==", + "dependencies": { + "@formatjs/intl-localematcher": "0.5.4", + "tslib": "^2.4.0" + } + }, + "node_modules/@formatjs/ecma402-abstract/node_modules/@formatjs/intl-localematcher": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.4.tgz", + "integrity": "sha512-zTwEpWOzZ2CiKcB93BLngUX59hQkuZjT2+SAQEscSm52peDW/getsawMcWF1rGRpMCX6D7nSJA3CzJ8gn13N/g==", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@formatjs/fast-memoize": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.0.tgz", + "integrity": "sha512-hnk/nY8FyrL5YxwP9e4r9dqeM6cAbo8PeU9UjyXojZMNvVad2Z06FAVHyR3Ecw6fza+0GH7vdJgiKIVXTMbSBA==", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@formatjs/icu-messageformat-parser": { + "version": "2.7.8", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.7.8.tgz", + "integrity": "sha512-nBZJYmhpcSX0WeJ5SDYUkZ42AgR3xiyhNCsQweFx3cz/ULJjym8bHAzWKvG5e2+1XO98dBYC0fWeeAECAVSwLA==", + "dependencies": { + "@formatjs/ecma402-abstract": "2.0.0", + "@formatjs/icu-skeleton-parser": "1.8.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@formatjs/icu-skeleton-parser": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.2.tgz", + "integrity": "sha512-k4ERKgw7aKGWJZgTarIcNEmvyTVD9FYh0mTrrBMHZ1b8hUu6iOJ4SzsZlo3UNAvHYa+PnvntIwRPt1/vy4nA9Q==", + "dependencies": { + "@formatjs/ecma402-abstract": "2.0.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@formatjs/intl-localematcher": { + "version": "0.2.32", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.32.tgz", + "integrity": "sha512-k/MEBstff4sttohyEpXxCmC3MqbUn9VvHGlZ8fauLzkbwXmVrEeyzS+4uhrvAk9DWU9/7otYWxyDox4nT/KVLQ==", + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -2464,6 +2517,17 @@ "node": ">= 0.4" } }, + "node_modules/intl-messageformat": { + "version": "10.5.14", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.5.14.tgz", + "integrity": "sha512-IjC6sI0X7YRjjyVH9aUgdftcmZK7WXdHeil4KwbjDnRWjnVitKpAx3rr6t6di1joFp5188VqKcobOPA6mCLG/w==", + "dependencies": { + "@formatjs/ecma402-abstract": "2.0.0", + "@formatjs/fast-memoize": "2.2.0", + "@formatjs/icu-messageformat-parser": "2.7.8", + "tslib": "^2.4.0" + } + }, "node_modules/is-arguments": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", @@ -3149,6 +3213,14 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/next": { "version": "14.2.5", "resolved": "https://registry.npmjs.org/next/-/next-14.2.5.tgz", @@ -3198,6 +3270,26 @@ } } }, + "node_modules/next-intl": { + "version": "3.17.2", + "resolved": "https://registry.npmjs.org/next-intl/-/next-intl-3.17.2.tgz", + "integrity": "sha512-X2ly23e1lC5vdWHaJFBDZi/0iornEdFQQtqJmmPOb7WD+LDssm9vAnx+hJshYGjddaP3rUmyWaPgePCQqaxm1g==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/amannn" + } + ], + "dependencies": { + "@formatjs/intl-localematcher": "^0.2.32", + "negotiator": "^0.6.3", + "use-intl": "^3.17.2" + }, + "peerDependencies": { + "next": "^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/next/node_modules/postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", @@ -4647,6 +4739,18 @@ "punycode": "^2.1.0" } }, + "node_modules/use-intl": { + "version": "3.17.2", + "resolved": "https://registry.npmjs.org/use-intl/-/use-intl-3.17.2.tgz", + "integrity": "sha512-9lPgt41nS8x4AYCLfIC9VKCmamnVxzPM2nze7lpp/I1uaSSQvIz5MQpYUFikv08cMUsCwAWahU0e+arHInpdcw==", + "dependencies": { + "@formatjs/fast-memoize": "^2.2.0", + "intl-messageformat": "^10.5.14" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index 552b534..2542221 100644 --- a/package.json +++ b/package.json @@ -9,18 +9,19 @@ "lint": "next lint" }, "dependencies": { + "next": "14.2.5", + "next-intl": "^3.17.2", "react": "^18", - "react-dom": "^18", - "next": "14.2.5" + "react-dom": "^18" }, "devDependencies": { - "typescript": "^5", "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", + "eslint": "^8", + "eslint-config-next": "14.2.5", "postcss": "^8", "tailwindcss": "^3.4.1", - "eslint": "^8", - "eslint-config-next": "14.2.5" + "typescript": "^5" } } diff --git a/src/app/[locale]/globals.css b/src/app/[locale]/globals.css new file mode 100644 index 0000000..b5c61c9 --- /dev/null +++ b/src/app/[locale]/globals.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/src/app/[locale]/layout.tsx b/src/app/[locale]/layout.tsx new file mode 100644 index 0000000..e1848a9 --- /dev/null +++ b/src/app/[locale]/layout.tsx @@ -0,0 +1,31 @@ +import type { Metadata } from "next"; +import { Inter } from "next/font/google"; +import "./globals.css"; +import { NextIntlClientProvider, useMessages } from "next-intl"; +import Footer from "../widgets/Footer/Footer"; + +const inter = Inter({ subsets: ["latin"] }); + +export const metadata: Metadata = { + title: "Create Next App", + description: "Generated by create next app", +}; + +export default function RootLayout({ + children, + params, +}: Readonly<{ + children: React.ReactNode; + params: { locale: string }; +}>) { + const messages = useMessages(); + + return ( + + + {children} +