From 9a6ce6b7c3cf2d7de89a8389e3d8c6708b599b6c Mon Sep 17 00:00:00 2001 From: javayhu Date: Tue, 11 Mar 2025 00:08:32 +0800 Subject: [PATCH] feat: add internationalization for theme and language switchers - Update `en.json` and `zh.json` with new translations for theme and language switching - Modify `LocaleSwitcher` and `ThemeSwitcher` components to use internationalized labels - Replace hardcoded strings with translations from `useTranslations` hook - Improve accessibility by using translated aria-labels and sr-only text - Refactor button styling to use `size-9` utility class --- messages/en.json | 7 ++++++- messages/zh.json | 7 ++++++- src/components/layout/locale-switcher.tsx | 11 ++++++----- src/components/layout/theme-switcher-horizontal.tsx | 8 +++++--- src/components/layout/theme-switcher.tsx | 12 +++++++----- 5 files changed, 30 insertions(+), 15 deletions(-) diff --git a/messages/en.json b/messages/en.json index 333215b..bf39a8c 100644 --- a/messages/en.json +++ b/messages/en.json @@ -8,7 +8,12 @@ "Common": { "login": "Login", "logout": "Log out", - "signUp": "Sign up" + "signUp": "Sign up", + "theme": "Toggle theme", + "language": "Switch language", + "light": "Light", + "dark": "Dark", + "system": "System" }, "HomePage": { "title": "next-intl example" diff --git a/messages/zh.json b/messages/zh.json index 715012d..fdcbc1b 100644 --- a/messages/zh.json +++ b/messages/zh.json @@ -8,7 +8,12 @@ "Common": { "login": "登录", "logout": "退出", - "signUp": "注册" + "signUp": "注册", + "theme": "切换主题", + "language": "切换语言", + "light": "浅色模式", + "dark": "深色模式", + "system": "跟随系统" }, "HomePage": { "title": "next-intl 示例" diff --git a/src/components/layout/locale-switcher.tsx b/src/components/layout/locale-switcher.tsx index 587b05b..c2edb6d 100644 --- a/src/components/layout/locale-switcher.tsx +++ b/src/components/layout/locale-switcher.tsx @@ -8,10 +8,10 @@ import { DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; import { useLocalePathname, useLocaleRouter } from '@/i18n/navigation'; -import { DEFAULT_LOCALE, Locale, LOCALE_LIST, routing } from '@/i18n/routing'; +import { Locale, LOCALE_LIST, routing } from '@/i18n/routing'; import { useLocaleStore } from '@/stores/locale-store'; import { Languages } from 'lucide-react'; -import { useLocale } from 'next-intl'; +import { useLocale, useTranslations } from 'next-intl'; import { useParams } from 'next/navigation'; import { useEffect, useTransition } from 'react'; @@ -30,7 +30,8 @@ export default function LocaleSwitcher() { const locale = useLocale(); const { currentLocale, setCurrentLocale } = useLocaleStore(); const [, startTransition] = useTransition(); - + const t = useTranslations('Common'); + useEffect(() => { setCurrentLocale(locale); }, [locale, setCurrentLocale]); @@ -55,10 +56,10 @@ export default function LocaleSwitcher() { diff --git a/src/components/layout/theme-switcher-horizontal.tsx b/src/components/layout/theme-switcher-horizontal.tsx index 620bfe4..2eaa14a 100644 --- a/src/components/layout/theme-switcher-horizontal.tsx +++ b/src/components/layout/theme-switcher-horizontal.tsx @@ -5,6 +5,7 @@ import { LaptopIcon, MoonIcon, SunIcon } from 'lucide-react'; import { useTheme } from 'next-themes'; import { cn } from '@/lib/utils'; import { useEffect, useState } from 'react'; +import { useTranslations } from 'next-intl'; /** * Theme switcher component, used in the footer, switch theme by theme variable @@ -12,6 +13,7 @@ import { useEffect, useState } from 'react'; export function ThemeSwitcherHorizontal() { const { theme, setTheme } = useTheme(); const [mounted, setMounted] = useState(false); + const t = useTranslations('Common'); // Only show the UI after hydration to prevent hydration mismatch useEffect(() => { @@ -38,7 +40,7 @@ export function ThemeSwitcherHorizontal() { theme === 'light' && 'bg-muted text-foreground' )} onClick={() => setTheme('light')} - aria-label="Light mode" + aria-label={t('light')} > @@ -51,7 +53,7 @@ export function ThemeSwitcherHorizontal() { theme === 'dark' && 'bg-muted text-foreground' )} onClick={() => setTheme('dark')} - aria-label="Dark mode" + aria-label={t('dark')} > @@ -64,7 +66,7 @@ export function ThemeSwitcherHorizontal() { theme === 'system' && 'bg-muted text-foreground' )} onClick={() => setTheme('system')} - aria-label="System mode" + aria-label={t('system')} > diff --git a/src/components/layout/theme-switcher.tsx b/src/components/layout/theme-switcher.tsx index 9c249c8..1788dff 100644 --- a/src/components/layout/theme-switcher.tsx +++ b/src/components/layout/theme-switcher.tsx @@ -8,6 +8,7 @@ import { DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; import { LaptopIcon, MoonIcon, SunIcon } from 'lucide-react'; +import { useTranslations } from 'next-intl'; import { useTheme } from 'next-themes'; /** @@ -15,6 +16,7 @@ import { useTheme } from 'next-themes'; */ export function ThemeSwitcher() { const { setTheme } = useTheme(); + const t = useTranslations('Common'); return ( @@ -22,11 +24,11 @@ export function ThemeSwitcher() { @@ -35,21 +37,21 @@ export function ThemeSwitcher() { className="cursor-pointer" > - Light + {t('light')} setTheme('dark')} className="cursor-pointer" > - Dark + {t('dark')} setTheme('system')} className="cursor-pointer" > - System + {t('system')}