diff --git a/app/layout.tsx b/app/layout.tsx index 8a018d7..792ff83 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,3 +1,5 @@ +// RootLayout.tsx +"use client"; import { fontSans } from "@/config/fonts"; import { siteConfig } from "@/config/site"; import "@/styles/globals.css"; @@ -5,29 +7,55 @@ import clsx from "clsx"; import { Metadata } from "next"; import { Providers } from "./providers"; import LoadScript from "@/utils/global"; +import { NextIntlClientProvider } from "next-intl"; +import { useEffect, useState, type ReactNode } from "react"; +import storedLanguage from "@/store/language-store"; -export const metadata: Metadata = { - title: { - default: siteConfig.name, - template: `%s - ${siteConfig.name}`, - }, - description: siteConfig.description, - themeColor: [ - { media: "(prefers-color-scheme: light)", color: "white" }, - { media: "(prefers-color-scheme: dark)", color: "black" }, - ], - icons: { - icon: "/logohumas.ico", - shortcut: "/favicon-16x16.png", - apple: "/apple-touch-icon.png", - }, -}; +// export const metadata: Metadata = { +// title: { +// default: siteConfig.name, +// template: `%s - ${siteConfig.name}`, +// }, +// description: siteConfig.description, +// themeColor: [ +// { media: "(prefers-color-scheme: light)", color: "white" }, +// { media: "(prefers-color-scheme: dark)", color: "black" }, +// ], +// icons: { +// icon: "/logohumas.ico", +// shortcut: "/favicon-16x16.png", +// apple: "/apple-touch-icon.png", +// }, +// }; export default function RootLayout({ children, + params, }: { - children: React.ReactNode; + children: ReactNode; + params: { locale: string }; }) { + // const { locale } = params; + const [localeNow, setLocaleNow] = useState("id"); + + const locale = storedLanguage((state) => state.locale); + // Load messages dynamically based on locale + // const messages = (await import(`../messages/${locale}.json`)).default; + + useEffect(() => { + if (locale) { + setLocaleNow(locale); + } + }, [locale]); + + const [messages, setMessages] = useState(null); + useEffect(() => { + (async () => { + const loadedMessages = (await import(`../messages/${locale}.json`)) + .default; + setMessages(loadedMessages); + })(); + }, [locale]); return ( @@ -49,9 +77,11 @@ export default function RootLayout({ fontSans.variable )} > - -
{children}
-
+ + +
{children}
+
+
); diff --git a/components/icons.tsx b/components/icons.tsx index b1e51a9..14b24df 100644 --- a/components/icons.tsx +++ b/components/icons.tsx @@ -2,1519 +2,2162 @@ import * as React from "react"; import { IconSvgProps } from "@/types"; export const Logo: React.FC = ({ - size = 36, - width, - height, - ...props + size = 36, + width, + height, + ...props }) => ( - - - + + + ); export const DiscordIcon: React.FC = ({ - size = 24, - width, - height, - ...props + size = 24, + width, + height, + ...props }) => { - return ( - - - - ); + return ( + + + + ); }; export const TwitterIcon: React.FC = ({ - size = 30, - width, - height, - color = "white", - ...props + size = 30, + width, + height, + color = "white", + ...props }) => { - return ( - - - - ); + return ( + + + + ); }; export const IconX: React.FC = ({ - size = 30, - width, - height, - color = "white", - ...props + size = 30, + width, + height, + color = "white", + ...props }) => { - return ( - - - - - ); + return ( + + + + ); }; export const SendIcon: React.FC = ({ - size, - width, - height, - color = "white", - ...props + size, + width, + height, + color = "white", + ...props }) => { - return ( - - - - - - - - - - - - - - - - ); + return ( + + + + + + + + + + + + + + + + ); }; export const GithubIcon: React.FC = ({ - size = 24, - width, - height, - ...props + size = 24, + width, + height, + ...props }) => { - return ( - - - - ); + return ( + + + + ); }; export const MoonFilledIcon = ({ - size = 24, - width, - height, - ...props + size = 24, + width, + height, + ...props }: IconSvgProps) => ( - + ); export const SunFilledIcon = ({ - size = 24, - width, - height, - ...props + size = 24, + width, + height, + ...props }: IconSvgProps) => ( - + ); export const HeartFilledIcon = ({ - size = 24, - width, - height, - ...props + size = 24, + width, + height, + ...props }: IconSvgProps) => ( - + ); export const SearchIcon = (props: IconSvgProps) => ( - + ); export const NextUILogo: React.FC = (props) => { - const { width, height = 40 } = props; + const { width, height = 40 } = props; - return ( - - - - - - ); + return ( + + + + + + ); }; export const FbIcon: React.FC = (props) => { - const { width, height = 40 } = props; + const { width, height = 40 } = props; - return ( - - - - - - - - - - - - ); + return ( + + + + + + + + + + + + ); }; export const ChevronUpIcon = ({ - size, - height = 24, - width = 24, - fill = "currentColor", - ...props + size, + height = 24, + width = 24, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - + + + ); export const ChevronDownIcon = ({ - size, - height = 24, - width = 14, - fill = "currentColor", - ...props + size, + height = 24, + width = 14, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - + + + ); export const ChevronRightIcon = ({ - size, - height = 24, - width = 24, - fill = "currentColor", - ...props + size, + height = 24, + width = 24, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - + + + ); export const ChevronLeftWhite = ({ - size, - height = 24, - width = 24, - color = "white", - ...props + size, + height = 24, + width = 24, + color = "white", + ...props }: IconSvgProps & { color?: string }) => ( - - - - + + + ); export const ChevronRightWhite = ({ - size, - height = 24, - width = 24, - color = "white", - ...props + size, + height = 24, + width = 24, + color = "white", + ...props }: IconSvgProps) => ( - - - + + + ); export const IgIcon = ({ - size, - height = 24, - width = 14, - fill = "currentColor", - ...props + size, + height = 24, + width = 14, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - - + + + + ); export const YtIcon = ({ - size, - height = 24, - width = 14, - fill = "currentColor", - ...props + size, + height = 24, + width = 14, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - - - - - - - - - + + + + + + + + + + + ); export const IdnIcon = ({ - size, - height = 24, - width = 14, - fill = "currentColor", - ...props + size, + height = 24, + width = 14, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - - - - - - - - - - - + + + + + + + + + + + + + +); +export const UKIcon = ({ + size, + height = 24, + width = 14, + fill = "currentColor", + ...props +}: IconSvgProps) => ( + + + + + + + + + + + + + + + + + + + ); export const TwIcon = ({ - size, - height = 24, - width = 14, - fill = "currentColor", - ...props + size, + height = 24, + width = 14, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - - + + + + ); export const TtIcon = ({ - size, - height = 24, - width = 14, - fill = "currentColor", - ...props + size, + height = 24, + width = 14, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - - - - - - - - - + + + + + + + + + + + ); export const EyeIcon = ({ - size, - height = 24, - width = 14, - fill = "currentColor", - color = "black", - ...props + size, + height = 24, + width = 14, + fill = "currentColor", + color = "black", + ...props }: IconSvgProps) => ( - - - + + + ); export const DotsIcon = ({ - size, - height = 24, - width = 24, - fill = "none", - ...props + size, + height = 24, + width = 24, + fill = "none", + ...props }: IconSvgProps) => ( - - - + + + ); export const MailIcon = (props: any) => ( - + ); export const SearchIcons = (props: any) => ( - -) + +); export const UnderLine = (props: any) => ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +); export const EyeSlashFilledIcon = (props: any) => ( - -) + +); export const EyeFilledIcon = (props: any) => ( - + ); export const ArrowIcons: React.FC = ({ - size = 30, - width, - height, - color = "white", - ...props + size = 30, + width, + height, + color = "white", + ...props }) => { - return ( - - - - - - - - - - - ); + return ( + + + + + + + + + + + ); }; export const Hotline = ({ - size = 24, - width, - height, - ...props + size = 24, + width, + height, + ...props }: IconSvgProps) => ( - - - - + + + + ); export const CustomerService = ({ - size = 24, - width, - height, - ...props + size = 24, + width, + height, + ...props }: IconSvgProps) => ( - - - - + + + + ); -export const Mail = ({ - size = 24, - width, - height, - ...props -}: IconSvgProps) => ( - - - +export const Mail = ({ size = 24, width, height, ...props }: IconSvgProps) => ( + + + ); export const Location = ({ - size = 24, - width, - height, - ...props + size = 24, + width, + height, + ...props }: IconSvgProps) => ( - - - + + + ); export const Calender = ({ - size = 24, - width, - height, - ...props + size = 24, + width, + height, + ...props }: IconSvgProps) => ( - - - - - - - - - - + + + + + + + + + + ); export const WorldIcon = ({ - size = 24, - width, - height, - ...props + size = 24, + width, + height, + ...props }: IconSvgProps) => ( - - - - - - - - - - + + + + + + + + + + ); export const Checklist = ({ - size = 24, - width, - height, - ...props + size = 24, + width, + height, + ...props }: IconSvgProps) => ( - - - - - - - - - - + + + + + + + + + + ); export const ChevronLeftIcon = ({ - size, - height = 24, - width = 24, - fill = "currentColor", - ...props + size, + height = 24, + width = 24, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - + + + ); export const DotsYIcon = ({ - size, - height = 24, - width = 24, - fill = "currentColor", - ...props + size, + height = 24, + width = 24, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - - + + + ); - export const DotsXIcon = ({ - size, - height = 24, - width = 24, - fill = "currentColor", - ...props + size, + height = 24, + width = 24, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - - - + + + ); export const EyeIconMdi = ({ - size, - height = 24, - width = 24, - fill = "currentColor", - ...props + size, + height = 24, + width = 24, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - + + + ); - export const OnlineIcon = ({ - size, - height = 24, - width = 24, - fill = "currentColor", - ...props + size, + height = 24, + width = 24, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - - - + + + ); export const OfflineIcon = ({ - size, - height = 24, - width = 24, - fill = "currentColor", - ...props + size, + height = 24, + width = 24, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - - - - - - + + + + ); export const CreateIconIon = ({ - size, - height = 24, - width = 24, - fill = "currentColor", - ...props + size, + height = 24, + width = 24, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - - + + + + ); export const DeleteIcon = ({ - size, - height = 12, - width = 10, - fill = "none", - ...props + size, + height = 12, + width = 10, + fill = "none", + ...props }: IconSvgProps) => ( - - - + + + ); - export const AccIcon = ({ - size, - height = 12, - width = 10, - fill = "none", - ...props + size, + height = 12, + width = 10, + fill = "none", + ...props }: IconSvgProps) => ( - - - - + + + ); export const CloseIcon = ({ - size, - height = 12, - width = 10, - fill = "none", - ...props + size, + height = 12, + width = 10, + fill = "none", + ...props }: IconSvgProps) => ( - - - - + + + ); export const RefundIcon = ({ - size, - height = 12, - width = 10, - fill = "none", - ...props + size, + height = 12, + width = 10, + fill = "none", + ...props }: IconSvgProps) => ( - - - - - + + + ); export const AddIcon = ({ - size, - height = 12, - width = 12, - fill = "none", - ...props + size, + height = 12, + width = 12, + fill = "none", + ...props }: IconSvgProps) => ( - - - + + + ); export const CompanyIcon = ({ - size, - height = 12, - width = 12, - fill = "none", - ...props + size, + height = 12, + width = 12, + fill = "none", + ...props }: IconSvgProps) => ( - - - - + + + ); export const EmailIcon = ({ - size, - height = 12, - width = 12, - fill = "none", - ...props + size, + height = 12, + width = 12, + fill = "none", + ...props }: IconSvgProps) => ( - - - - - + + + ); export const PhoneIcon = ({ - size, - height = 12, - width = 12, - fill = "none", - ...props + size, + height = 12, + width = 12, + fill = "none", + ...props }: IconSvgProps) => ( - - - - + + + ); export const MessageIcon = ({ - size, - height = 12, - width = 12, - fill = "none", - ...props + size, + height = 12, + width = 12, + fill = "none", + ...props }: IconSvgProps) => ( - - - - - + + + ); - export const UserIcon = ({ - size, - height = 12, - width = 12, - fill = "none", - ...props + size, + height = 12, + width = 12, + fill = "none", + ...props }: IconSvgProps) => ( - - - - - - + + + ); export const EyeOffIconMdi = ({ - size, - height = 24, - width = 24, - fill = "currentColor", - ...props + size, + height = 24, + width = 24, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - + + + ); export const DateIcon = ({ - size, - height = 24, - width = 24, - fill = "currentColor", - ...props + size, + height = 24, + width = 24, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - - - - - + + + + ); export const WarningIcon = ({ - size, - height = 24, - width = 24, - fill = "currentColor", - ...props + size, + height = 24, + width = 24, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - - - + + + ); export const PasswordIcon = ({ - size, - height = 24, - width = 24, - fill = "currentColor", - ...props + size, + height = 24, + width = 24, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - - - + + + ); export const TimeIcon = ({ - size, - height = 24, - width = 24, - fill = "currentColor", - ...props + size, + height = 24, + width = 24, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - - - - - + + + + ); export const VolumeLowIcon = ({ - size, - height = 24, - width = 24, - fill = "currentColor", - ...props + size, + height = 24, + width = 24, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - - + + + ); export const VolumeHighIcon = ({ - size, - height = 24, - width = 24, - fill = "currentColor", - ...props + size, + height = 24, + width = 24, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - - - - - - + + + + + ); export const FormVerticalIcon = ({ - size, - height = 24, - width = 24, - fill = "currentColor", - ...props + size, + height = 24, + width = 24, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - + + + ); export const FormHorizontalIcon = ({ - size, - height = 24, - width = 24, - fill = "currentColor", - ...props + size, + height = 24, + width = 24, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - + + + ); export const FormCustomIcon = ({ - size, - height = 24, - width = 24, - fill = "currentColor", - ...props + size, + height = 24, + width = 24, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - + + + ); export const FormLayoutIcon = ({ - size, - height = 24, - width = 24, - fill = "currentColor", - ...props + size, + height = 24, + width = 24, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - + + + ); export const FormValidationIcon = ({ - size, - height = 24, - width = 24, - fill = "currentColor", - ...props + size, + height = 24, + width = 24, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - + + + + ); export const FormWizardIcon = ({ - size, - height = 24, - width = 24, - fill = "currentColor", - ...props + size, + height = 24, + width = 24, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - + + + + ); export const FacebookIcon = ({ - size, - height = 24, - width = 24, - fill = "currentColor", - ...props + size, + height = 24, + width = 24, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - - - - + + + + ); export const GoogleIcon = ({ - size, - height = 24, - width = 24, - fill = "currentColor", - ...props + size, + height = 24, + width = 24, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - - - - - - - - - - + + + + + + + ); - - export const TimesIcon = ({ - size, - height = 24, - width = 24, - fill = "currentColor", - ...props + size, + height = 24, + width = 24, + fill = "currentColor", + ...props }: IconSvgProps) => ( - - - + + + ); diff --git a/components/layout/navbar/NavbarHumas.tsx b/components/layout/navbar/NavbarHumas.tsx index f39b354..e296744 100644 --- a/components/layout/navbar/NavbarHumas.tsx +++ b/components/layout/navbar/NavbarHumas.tsx @@ -29,11 +29,14 @@ import { SearchIcon, TtIcon, TwIcon, + UKIcon, YtIcon, } from "../../icons"; import { ThemeSwitch } from "../../theme-switch"; import Cookies from "js-cookie"; import { useRouter } from "next/navigation"; +import { useTranslations } from "next-intl"; +import storedLanguage from "@/store/language-store"; interface MenuItem { key: string; @@ -54,15 +57,18 @@ interface DropdownOpenState { export default function NavbarHumas() { const [dropdownOpen, setDropdownOpen] = useState({}); const router = useRouter(); - + const t = useTranslations("Navbar"); const token = Cookies.get("access_token"); const isAuthenticated = Cookies.get("is_authenticated"); - // useEffect(() => { - // if (!isAuthenticated) { - // onLogout(); - // } - // }, [token]); + const language = storedLanguage((state) => state.locale); + const setLanguage = storedLanguage((state) => state.setLocale); + + useEffect(() => { + if (!isAuthenticated) { + onLogout(); + } + }, [token]); const onLogout = () => { Object.keys(Cookies.get()).forEach((cookieName) => { @@ -143,13 +149,18 @@ export default function NavbarHumas() { -
- -
+ + language === "id" ? setLanguage("en") : setLanguage("id") + } + > + {language === "id" ? : } +
-
Beranda
+
{t("beranda")}
@@ -162,13 +173,13 @@ export default function NavbarHumas() { variant="light" endContent={} > - Tentang + {t("tentang")} - Tentang Humas POLRI + {t("tentang")} Humas POLRI @@ -194,7 +205,7 @@ export default function NavbarHumas() { href="/static/profile-kapolri" className="flex justify-between" > - Profile Pimpinan POLRI + {t("profilPimpinan")} @@ -203,7 +214,7 @@ export default function NavbarHumas() { href="/static/struktur-mabes" className="flex justify-between" > - Struktur Organisasi + {t("strukturOrganisasi")} @@ -212,7 +223,7 @@ export default function NavbarHumas() { href="/static/visi-misi-polri" className="flex justify-between" > - Visi & Misi + {t("visi")} & {t("misi")} @@ -221,7 +232,7 @@ export default function NavbarHumas() { href="/static/tugas-dan-fungsi-polri" className="flex justify-between" > - Tugas & Fungsi + {t("tugas")} & {t("fungsi")} @@ -235,7 +246,10 @@ export default function NavbarHumas() {
- + {/* + Portal PPID + */} + Portal PPID
@@ -250,7 +264,7 @@ export default function NavbarHumas() { variant="light" endContent={} > - Pelayanan Masyarakat + {t("pelayananMasyarakat")} @@ -378,7 +392,7 @@ export default function NavbarHumas() {
- Kontak + {t("kontak")}
{searchInput}
@@ -414,7 +428,7 @@ export default function NavbarHumas() { ) : ( - + )}
@@ -431,12 +445,17 @@ export default function NavbarHumas() { {item.key === "login" ? ( token ? ( - ) : ( - + ) ) : item.key === "dashboard" ? ( diff --git a/i18n/request.ts b/i18n/request.ts new file mode 100644 index 0000000..17e05e4 --- /dev/null +++ b/i18n/request.ts @@ -0,0 +1,15 @@ +"use client"; +import { notFound } from "next/navigation"; +import { getRequestConfig } from "next-intl/server"; +import storedLanguage from "@/store/language-store"; + +export default getRequestConfig(async () => { + const supportedLocale = ["en", "id"]; + const locale = storedLanguage((state) => state.locale); + // Validate that the incoming `locale` parameter is valid + if (!supportedLocale.includes(locale)) notFound(); + + return { + messages: (await import(`../messages/${locale}.json`)).default, + }; +}); diff --git a/messages/en.json b/messages/en.json new file mode 100644 index 0000000..9e54d9a --- /dev/null +++ b/messages/en.json @@ -0,0 +1,14 @@ +{ + "Navbar": { + "beranda": "Home", + "tentang": "About", + "pelayananMasyarakat": "Public Service", + "kontak": "Contact", + "visi": "Vision", + "misi": "Mission", + "strukturOrganisasi": "Organizational Structure", + "profilPimpinan": "Profile of The Police Leader", + "tugas": "Duties", + "fungsi": "Functions" + } +} diff --git a/messages/id.json b/messages/id.json new file mode 100644 index 0000000..ab69ea1 --- /dev/null +++ b/messages/id.json @@ -0,0 +1,14 @@ +{ + "Navbar": { + "beranda": "Beranda", + "tentang": "Tentang", + "pelayananMasyarakat": "Pelayanan Masyarakat", + "kontak": "Kontak", + "visi": "Visi", + "misi": "Misi", + "strukturOrganisasi": "Struktur Organisasi", + "profilPimpinan": "Profil Pimpinan Polri", + "tugas": "Tugas", + "fungsi": "Fungsi" + } +} diff --git a/package-lock.json b/package-lock.json index 2aa213e..ceb6adb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,6 +42,7 @@ "jodit-react": "^4.0.25", "js-cookie": "^3.0.5", "next": "14.0.2", + "next-intl": "^3.26.0", "next-themes": "^0.2.1", "postcss": "8.4.31", "react": "18.2.0", @@ -434,42 +435,49 @@ "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" }, "node_modules/@formatjs/ecma402-abstract": { - "version": "1.17.3", - "license": "MIT", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.1.tgz", + "integrity": "sha512-Ip9uV+/MpLXWRk03U/GzeJMuPeOXpJBSB5V1tjA6kJhvqssye5J5LoYLc7Z5IAHb7nR62sRoguzrFiVCP/hnzw==", "dependencies": { - "@formatjs/intl-localematcher": "0.5.0", - "tslib": "^2.4.0" + "@formatjs/fast-memoize": "2.2.5", + "@formatjs/intl-localematcher": "0.5.9", + "decimal.js": "10", + "tslib": "2" } }, "node_modules/@formatjs/fast-memoize": { - "version": "2.2.0", - "license": "MIT", + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.5.tgz", + "integrity": "sha512-6PoewUMrrcqxSoBXAOJDiW1m+AmkrAj0RiXnOMD59GRaswjXhm3MDhgepXPBgonc09oSirAJTsAggzAGQf6A6g==", "dependencies": { - "tslib": "^2.4.0" + "tslib": "2" } }, "node_modules/@formatjs/icu-messageformat-parser": { - "version": "2.7.1", - "license": "MIT", + "version": "2.9.7", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.9.7.tgz", + "integrity": "sha512-cuEHyRM5VqLQobANOjtjlgU7+qmk9Q3fDQuBiRRJ3+Wp3ZoZhpUPtUfuimZXsir6SaI2TaAJ+SLo9vLnV5QcbA==", "dependencies": { - "@formatjs/ecma402-abstract": "1.17.3", - "@formatjs/icu-skeleton-parser": "1.6.3", - "tslib": "^2.4.0" + "@formatjs/ecma402-abstract": "2.3.1", + "@formatjs/icu-skeleton-parser": "1.8.11", + "tslib": "2" } }, "node_modules/@formatjs/icu-skeleton-parser": { - "version": "1.6.3", - "license": "MIT", + "version": "1.8.11", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.11.tgz", + "integrity": "sha512-8LlHHE/yL/zVJZHAX3pbKaCjZKmBIO6aJY1mkVh4RMSEu/2WRZ4Ysvv3kKXJ9M8RJLBHdnk1/dUQFdod1Dt7Dw==", "dependencies": { - "@formatjs/ecma402-abstract": "1.17.3", - "tslib": "^2.4.0" + "@formatjs/ecma402-abstract": "2.3.1", + "tslib": "2" } }, "node_modules/@formatjs/intl-localematcher": { - "version": "0.5.0", - "license": "MIT", + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.9.tgz", + "integrity": "sha512-8zkGu/sv5euxbjfZ/xmklqLyDGQSxsLqg8XOq88JW3cmJtzhCP8EtSJXlaKZnVO4beEaoiT9wj4eIoCQ9smwxA==", "dependencies": { - "tslib": "^2.4.0" + "tslib": "2" } }, "node_modules/@hookform/resolvers": { @@ -3678,6 +3686,11 @@ } } }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" + }, "node_modules/deep-is": { "version": "0.1.4", "license": "MIT" @@ -4884,13 +4897,14 @@ } }, "node_modules/intl-messageformat": { - "version": "10.5.5", - "license": "BSD-3-Clause", + "version": "10.7.10", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.7.10.tgz", + "integrity": "sha512-hp7iejCBiJdW3zmOe18FdlJu8U/JsADSDiBPQhfdSeI8B9POtvPRvPh3nMlvhYayGMKLv6maldhR7y3Pf1vkpw==", "dependencies": { - "@formatjs/ecma402-abstract": "1.17.3", - "@formatjs/fast-memoize": "2.2.0", - "@formatjs/icu-messageformat-parser": "2.7.1", - "tslib": "^2.4.0" + "@formatjs/ecma402-abstract": "2.3.1", + "@formatjs/fast-memoize": "2.2.5", + "@formatjs/icu-messageformat-parser": "2.9.7", + "tslib": "2" } }, "node_modules/invariant": { @@ -5497,6 +5511,14 @@ "version": "1.4.0", "license": "MIT" }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/next": { "version": "14.0.2", "license": "MIT", @@ -5541,6 +5563,26 @@ } } }, + "node_modules/next-intl": { + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/next-intl/-/next-intl-3.26.0.tgz", + "integrity": "sha512-gkamnHIANQzeW8xpTGRxd0xiOCztQhY8GDp79fgdlw0GioqrjTEfSWLhHkgaAtvHRbuh/ByJdwiEY5eNK9bUSQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/amannn" + } + ], + "dependencies": { + "@formatjs/intl-localematcher": "^0.5.4", + "negotiator": "^1.0.0", + "use-intl": "^3.26.0" + }, + "peerDependencies": { + "next": "^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0" + } + }, "node_modules/next-themes": { "version": "0.2.1", "license": "MIT", @@ -7114,6 +7156,18 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/use-intl": { + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/use-intl/-/use-intl-3.26.0.tgz", + "integrity": "sha512-HGXmpjGlbEv1uFZPfm557LK8p/hv0pKF9UwnrJeHUTxQx6bUGzMgpmPRLCVY3zkr7hfjy4LPwQJfk4Fhnn+dIg==", + "dependencies": { + "@formatjs/fast-memoize": "^2.2.0", + "intl-messageformat": "^10.5.14" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0" + } + }, "node_modules/use-isomorphic-layout-effect": { "version": "1.1.2", "license": "MIT", diff --git a/package.json b/package.json index e554516..98822d0 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "jodit-react": "^4.0.25", "js-cookie": "^3.0.5", "next": "14.0.2", + "next-intl": "^3.26.0", "next-themes": "^0.2.1", "postcss": "8.4.31", "react": "18.2.0", diff --git a/store/language-store.tsx b/store/language-store.tsx new file mode 100644 index 0000000..10bcfd0 --- /dev/null +++ b/store/language-store.tsx @@ -0,0 +1,24 @@ +import { create } from "zustand"; + +interface targetStore { + locale: string; + setLocale: (newTarget: string) => void; +} + +const getInitialTarget = () => { + if (typeof localStorage !== "undefined") { + const stored = localStorage.getItem("locale"); + const initial = stored ? JSON.parse(stored) : "id"; + return initial; + } +}; + +const storedLanguage = create((set) => ({ + locale: getInitialTarget(), + setLocale: (newTarget: string) => { + localStorage.setItem("locale", JSON.stringify(newTarget)); + set({ locale: newTarget }); + }, +})); + +export default storedLanguage;