diff --git a/frontend/package.json b/frontend/package.json
index 2354ae04..196d5dfb 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -46,11 +46,14 @@
"dayjs": "^1.11.10",
"embla-carousel-react": "^8.0.2",
"gradient-avatar": "^1.0.2",
+ "i18next": "^23.12.2",
+ "i18next-browser-languagedetector": "^8.0.0",
"lucide-react": "^0.363.0",
"posthog-js": "^1.116.6",
"react": "^18.2.0",
"react-day-picker": "^8.10.1",
"react-dom": "^18.2.0",
+ "react-i18next": "^15.0.0",
"react-lottie": "^1.2.4",
"react-qr-code": "^2.0.12",
"react-router-dom": "^6.21.0",
diff --git a/frontend/src/components/LocaleSwitcher.tsx b/frontend/src/components/LocaleSwitcher.tsx
new file mode 100644
index 00000000..5e96f63b
--- /dev/null
+++ b/frontend/src/components/LocaleSwitcher.tsx
@@ -0,0 +1,45 @@
+import type { FallbackLng } from "i18next";
+import { useState } from "react";
+import { useTranslation } from "react-i18next";
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "src/components/ui/select";
+import { toast } from "src/components/ui/use-toast";
+import i18n, { supportedLocales } from "src/i18n/i18nConfig";
+
+export default function LocaleSwitcher() {
+ const { t } = useTranslation("components", {
+ keyPrefix: "locale_switcher",
+ });
+ const fallbackLng = i18n.options.fallbackLng?.[0 as keyof FallbackLng];
+ const [dropdownLang, setDropdownLang] = useState(
+ i18n.language || fallbackLng
+ );
+
+ const onLanguageChange = async (newLanguage: string) => {
+ if (dropdownLang !== newLanguage) {
+ setDropdownLang(newLanguage);
+ i18n.changeLanguage(newLanguage);
+ toast({ title: t("success") });
+ }
+ };
+
+ return (
+
+ );
+}
diff --git a/frontend/src/components/layouts/SettingsLayout.tsx b/frontend/src/components/layouts/SettingsLayout.tsx
index 57fac529..8052c4d4 100644
--- a/frontend/src/components/layouts/SettingsLayout.tsx
+++ b/frontend/src/components/layouts/SettingsLayout.tsx
@@ -98,7 +98,7 @@ export default function SettingsLayout() {