feat(i18n): implement astro i18n integration and refactor locale handling
- Add i18n configuration to astro.config.mjs with default locale and routing - Refactor language handling to use Astro.currentLocale instead of URL parsing - Update tsconfig to include only necessary files for better type checking - Improve LanguageSwitcher to handle routing based on astro i18n config - Add new translation keys and update components to use dynamic titles - Simplify MotionWrapper component by removing unused default animations
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { getLangFromUrl, getLocalizedPath, type Lang } from "@/i18n/utils";
|
||||
import { getLocalizedPath, type Lang } from "@/i18n/utils"; // getLangFromUrl is removed as Astro.currentLocale is used now.
|
||||
import { languages as i18nLanguages, defaultLang } from "@/i18n/ui";
|
||||
import { Languages, Check } from "lucide-react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
@@ -30,12 +30,41 @@ export default function LanguageSwitcher({ lang: initialLang }: LanguageSwitcher
|
||||
|
||||
const toggleOpen = () => setIsOpen(!isOpen);
|
||||
|
||||
const handleSelectLanguage = (lang: typeof availableLanguages[0]) => {
|
||||
setSelectedLanguage(lang);
|
||||
const handleSelectLanguage = (languageOpt: typeof availableLanguages[0]) => {
|
||||
setSelectedLanguage(languageOpt);
|
||||
setIsOpen(false);
|
||||
if (typeof window !== 'undefined') {
|
||||
const currentPath = window.location.pathname.replace(/\/en|\/zh/, ''); // Remove lang prefix
|
||||
const newPath = getLocalizedPath(currentPath || '/', lang.code);
|
||||
const currentPathname = window.location.pathname;
|
||||
const currentPathParts = currentPathname.split('/').filter(p => p);
|
||||
let basePath = '';
|
||||
|
||||
// Check if the first part of the path is a known language code
|
||||
if (currentPathParts.length > 0 && Object.keys(i18nLanguages).includes(currentPathParts[0])) {
|
||||
basePath = '/' + currentPathParts.slice(1).join('/');
|
||||
} else {
|
||||
basePath = currentPathname;
|
||||
}
|
||||
|
||||
// Ensure basePath always starts with a slash, or is just a slash for the root
|
||||
if (!basePath.startsWith('/')) {
|
||||
basePath = '/' + basePath;
|
||||
}
|
||||
if (basePath === '//') basePath = '/';
|
||||
|
||||
let newPath;
|
||||
// If the target language is the default language and prefixDefaultLocale is false (as per our astro.config.mjs)
|
||||
// then no language prefix is needed.
|
||||
if (languageOpt.code === defaultLang) {
|
||||
newPath = basePath;
|
||||
} else {
|
||||
// For non-default languages, prefix with the language code.
|
||||
newPath = `/${languageOpt.code}${basePath}`;
|
||||
}
|
||||
|
||||
// Clean up double slashes, just in case
|
||||
newPath = newPath.replace(/\/\/+/g, '/');
|
||||
if (newPath === '') newPath = '/'; // Handle case where basePath might be empty resulting in just /zh or /en
|
||||
|
||||
window.location.href = newPath;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,25 +2,11 @@ import React from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import type { MotionProps } from "framer-motion";
|
||||
|
||||
interface MotionWrapperProps extends MotionProps {
|
||||
interface MotionWrapperProps extends Omit<MotionProps, 'custom'> {
|
||||
children: React.ReactNode;
|
||||
delay?: number;
|
||||
}
|
||||
|
||||
// Default animations for sections
|
||||
const defaultAnimations = {
|
||||
hidden: { opacity: 0, y: 20 },
|
||||
visible: (delay: number = 0) => ({
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: {
|
||||
duration: 0.6,
|
||||
delay: delay,
|
||||
ease: "easeOut",
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
export default function MotionWrapper({
|
||||
children,
|
||||
delay = 0,
|
||||
@@ -31,7 +17,18 @@ export default function MotionWrapper({
|
||||
initial="hidden"
|
||||
whileInView="visible"
|
||||
viewport={{ once: true, margin: "-100px" }}
|
||||
variants={defaultAnimations}
|
||||
variants={{
|
||||
hidden: { opacity: 0, y: 20 },
|
||||
visible: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: {
|
||||
duration: 0.6,
|
||||
delay,
|
||||
ease: [0.43, 0.13, 0.23, 0.96]
|
||||
}
|
||||
}
|
||||
}}
|
||||
custom={delay}
|
||||
{...props}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user