feat(i18n): add internationalization support with astro-i18next
- Add astro-i18next package for i18n support - Create LanguageSwitcher component with English and Chinese options - Add i18n guide documentation - Update .gitignore and package.json
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import ThemeToggle from "./ui/theme-toggle";
|
||||
import LanguageSwitcher from "./LanguageSwitcher"; // Added import for LanguageSwitcher
|
||||
import { personalInfo } from "@/lib/data";
|
||||
import { useState } from "react";
|
||||
import { Menu, X } from "lucide-react";
|
||||
@@ -46,9 +47,11 @@ export default function GlassHeader() {
|
||||
</nav>
|
||||
|
||||
<div className="flex items-center space-x-2">
|
||||
{/* Language Switcher added here */}
|
||||
<LanguageSwitcher />
|
||||
<ThemeToggle />
|
||||
|
||||
{/* Mobile Menu Button */}
|
||||
{/* Mobile Menu Button */}
|
||||
<motion.button
|
||||
className="md:hidden p-2 text-foreground"
|
||||
onClick={toggleMenu}
|
||||
|
||||
64
src/components/LanguageSwitcher.tsx
Normal file
64
src/components/LanguageSwitcher.tsx
Normal file
@@ -0,0 +1,64 @@
|
||||
import { useState } from "react";
|
||||
import { Languages, Check } from "lucide-react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
|
||||
const languages = [
|
||||
{ code: "en", name: "English", icon: "🇬🇧" }, // Added icon for English
|
||||
{ code: "zh", name: "中文", icon: "🇨🇳" }, // Added icon for Chinese
|
||||
];
|
||||
|
||||
export default function LanguageSwitcher() {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
// TODO: Implement actual language switching logic, e.g., using a context or a library
|
||||
const [selectedLanguage, setSelectedLanguage] = useState(languages[0]);
|
||||
|
||||
const toggleOpen = () => setIsOpen(!isOpen);
|
||||
|
||||
const handleSelectLanguage = (lang: typeof languages[0]) => {
|
||||
setSelectedLanguage(lang);
|
||||
setIsOpen(false);
|
||||
// Here you would typically call a function to change the language of the application
|
||||
console.log(`Language changed to: ${lang.name}`);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<motion.button
|
||||
onClick={toggleOpen}
|
||||
className="p-2 rounded-md hover:bg-accent hover:text-accent-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
|
||||
aria-label="Change language"
|
||||
whileTap={{ scale: 0.95 }}
|
||||
>
|
||||
<Languages size={20} />
|
||||
</motion.button>
|
||||
<AnimatePresence>
|
||||
{isOpen && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: -10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: -10 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
className="absolute right-0 mt-2 w-40 origin-top-right rounded-md bg-popover text-popover-foreground shadow-md focus:outline-none z-50 border border-border/20"
|
||||
>
|
||||
<div className="p-1" role="menu" aria-orientation="vertical" aria-labelledby="options-menu">
|
||||
{languages.map((lang) => (
|
||||
<button
|
||||
key={lang.code}
|
||||
onClick={() => handleSelectLanguage(lang)}
|
||||
className="w-full text-left px-3 py-1.5 text-sm rounded-sm hover:bg-accent hover:text-accent-foreground flex items-center justify-between cursor-pointer focus:bg-accent focus:outline-none"
|
||||
role="menuitem"
|
||||
>
|
||||
<span className="flex items-center">
|
||||
<span className="mr-2">{lang.icon}</span> {/* Display icon */}
|
||||
{lang.name}
|
||||
</span>
|
||||
{selectedLanguage.code === lang.code && <Check size={16} className="text-primary" />}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</motion.div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user