From 0ab31a16f6efcdc16f3199a66aa72a6551954dc7 Mon Sep 17 00:00:00 2001 From: yozuru Date: Sat, 19 Apr 2025 04:18:23 +0800 Subject: [PATCH] feat: add language switcher component --- src/components/LanguageSwitcher.astro | 172 ++++++++++++++++++++++++++ src/layouts/layout.astro | 16 ++- src/locales/en/translation.json | 7 ++ src/locales/zh/translation.json | 7 ++ 4 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 src/components/LanguageSwitcher.astro diff --git a/src/components/LanguageSwitcher.astro b/src/components/LanguageSwitcher.astro new file mode 100644 index 0000000..fa1ebec --- /dev/null +++ b/src/components/LanguageSwitcher.astro @@ -0,0 +1,172 @@ +--- +import { getSupportedLangs, getTranslator } from '@/i18n/utils'; +import i18n from '@/i18n'; +import { IoChevronDown } from 'react-icons/io5'; + +const { url } = Astro; +// 使用 fallbackLng 作为回退值 +const currentLocale = + Astro.currentLocale || + (Array.isArray(i18n.options.fallbackLng) + ? i18n.options.fallbackLng[0] + : i18n.options.fallbackLng) || + 'en'; +const t = await getTranslator(currentLocale); + +const supportedLangs = getSupportedLangs(); +const defaultLocaleCode = 'en'; + +let basePath = url.pathname; +const prefix = `/${currentLocale}`; + +// 只有当当前语言不是硬编码的默认语言时,才需要尝试移除前缀 +if (currentLocale !== defaultLocaleCode && basePath.startsWith(prefix)) { + basePath = basePath.substring(prefix.length) || '/'; +} +if (basePath !== '/' && !basePath.startsWith('/')) { + basePath = '/' + basePath; +} + +const currentLangName = + t(`languages.${currentLocale}`) || currentLocale.toUpperCase(); +--- + +
+
+ + {currentLangName} + + +
    + { + supportedLangs.map(langCode => { + if (langCode === currentLocale) return null; + + const isDefaultLang = langCode === defaultLocaleCode; + let targetPath = isDefaultLang ? basePath : `/${langCode}${basePath}`; + targetPath = targetPath.replace('//', '/'); + if (targetPath === '' && isDefaultLang) targetPath = '/'; + if (targetPath === '' && !isDefaultLang) targetPath = `/${langCode}`; + + return ( +
  • + + {t(`languages.${langCode}`) || langCode.toUpperCase()} + +
  • + ); + }) + } +
+
+
+ + diff --git a/src/layouts/layout.astro b/src/layouts/layout.astro index 05675e2..606dccf 100644 --- a/src/layouts/layout.astro +++ b/src/layouts/layout.astro @@ -8,7 +8,7 @@ import { count as soundCount } from '@/lib/sounds'; import { getTranslator } from '@/i18n/utils'; import '@/styles/global.css'; - +import LanguageSwitcher from '@/components/LanguageSwitcher.astro'; interface Props { description?: string; title?: string; @@ -46,8 +46,22 @@ const description = Astro.props.description || t('site.description', { count }); {pwaInfo && } +
+ +
+ diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index fbba755..34e028a 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -4,6 +4,13 @@ "description": "Moodist is a free and open-source ambient sound generator featuring {{count}} carefully curated sounds. Create your ideal atmosphere for relaxation, focus, or creativity with this versatile tool.", "ogSiteName": "Moodist" }, + "languages": { + "en": "English", + "zh": "简体中文" + }, + "languageSwitcher": { + "label": "Language selection" + }, "common": { "play": "Play", "pause": "Pause", diff --git a/src/locales/zh/translation.json b/src/locales/zh/translation.json index 7429bce..af78eb3 100644 --- a/src/locales/zh/translation.json +++ b/src/locales/zh/translation.json @@ -4,6 +4,13 @@ "description": "Moodist 是一个免费且开源的环境声音生成器,包含 {{count}} 种精心挑选的声音。使用这款多功能工具,为放松、专注或创造力营造理想的氛围。", "ogSiteName": "Moodist" }, + "languages": { + "en": "English", + "zh": "简体中文" + }, + "languageSwitcher": { + "label": "语言选择" + }, "common": { "play": "播放", "pause": "暂停",