LanguageSwitcher
The LanguageSwitcher component provides a button to toggle between Spanish (es) and English (en) versions of the site, maintaining the current page path across languages.
Import
---
import LanguageSwitcher from '@/components/LanguageSwitcher.astro';
---
Props
This component does not accept any props. It automatically detects the current language from the URL.
Usage
---
import LanguageSwitcher from '@/components/LanguageSwitcher.astro';
---
<header>
<nav>
<LanguageSwitcher />
</nav>
</header>
The component is typically placed in the site header alongside navigation links and the theme toggle.
Features
Automatic Language Detection
The component uses the getLangFromUrl utility to detect the current language from the URL path:
import { getLangFromUrl } from "../utils/i18n";
const lang = getLangFromUrl(Astro.url); // "es" or "en"
Path Preservation
When switching languages, the component preserves the current page path:
// Current: /es/palabras/chapin
// Switches to: /en/palabras/chapin
// Current: /en/indice
// Switches to: /es/indice
The algorithm removes the current language prefix and prepends the target language:
const basePath = currentPath.replace(/^\/(es|en)/, "") || "/";
const targetPath = `/${targetLang}${basePath}`;
Dynamic Label
The button displays the target language code:
- When on Spanish pages: Shows “EN”
- When on English pages: Shows “ES”
Accessibility
The component includes a localized aria-label:
aria-label={lang === "es" ? "Switch to English" : "Cambiar a Español"}
This provides screen reader users with clear information about what the button does.
Analytics Tracking
Language switches are tracked using Umami analytics with source and target language context:
data-umami-event="Language Switch"
data-umami-event-from={lang}
data-umami-event-to={targetLang}
View Transitions Support
The component includes a client-side script that updates after each navigation when using Astro’s View Transitions:
document.addEventListener("astro:page-load", updateLanguageSwitchers);
This ensures the switcher always points to the correct target language, even after client-side navigation.
Styling
The component uses utility classes for styling:
<a
class="language-switcher border-theme bg-card text-theme hover:bg-card-hover hover:border-primary-light inline-flex items-center gap-2 rounded-lg border px-3 py-2 text-sm font-medium transition-all"
>
<Globe size="18" />
<span>{lang === "es" ? "EN" : "ES"}</span>
</a>
The styling includes:
- Card background with hover effects
- Theme-aware borders and text colors
- Globe icon from Lucide
- Smooth transitions
Implementation Details
URL Structure
Chapinismos uses language prefixes in all URLs:
/es/ # Spanish homepage
/en/ # English homepage
/es/palabras/ # Spanish word index
/en/palabras/ # English word index
The switcher assumes this structure and transforms URLs accordingly.
Multiple Switchers
The component supports multiple instances on the same page (e.g., desktop and mobile headers). The client-side script updates all instances:
const switchers = document.querySelectorAll(".language-switcher");
switchers.forEach((switcher) => {
switcher.setAttribute("href", targetPath);
});
Complete Example
---
import LanguageSwitcher from '@/components/LanguageSwitcher.astro';
import ThemeToggle from '@/components/ThemeToggle.astro';
import { getLangFromUrl } from '@/utils/i18n';
const lang = getLangFromUrl(Astro.url);
---
<!DOCTYPE html>
<html lang={lang}>
<head>
<meta charset="UTF-8" />
<title>Chapinismos</title>
</head>
<body>
<header>
<nav class="flex items-center gap-4">
<a href={`/${lang}/`}>Home</a>
<a href={`/${lang}/buscar`}>Search</a>
<a href={`/${lang}/indice`}>Index</a>
<div class="flex items-center gap-2 ml-auto">
<LanguageSwitcher />
<ThemeToggle />
</div>
</nav>
</header>
<main>
<slot />
</main>
</body>
</html>
Edge Cases
Root Path
When on the language root (e.g., /es/ or /en/), the switcher correctly handles the base path:
const basePath = currentPath.replace(/^\/(es|en)/, "") || "/";
// Result: "/"
This ensures switching from /es/ goes to /en/, not /en//.
Missing Content
The component does not check whether content exists in the target language. If a word exists in Spanish but not in English, the switcher will still link to the English version, which may result in a 404.
For production use, consider adding validation to check if the target language version exists before rendering the switcher link.
- Header - Includes the language switcher in the navigation bar
- i18n Utilities - Language detection and translation utilities
Internationalization
For a complete guide on how the bilingual system works, see Internationalization.