i18n
LangSwitcher · 3-way switcher
Renders locale links. Each link carries a hreflang attribute for crawlers. Accepts an array of locales so consumers can restrict to an active subset.
current = "ru"
current = "en"
current = "tr"
import LangSwitcher from "@lisacorp/wam-astro-components/patterns/LangSwitcher.astro";
<!-- Pass current language and Astro's pathname -->
<LangSwitcher current={lang} pathname={Astro.url.pathname} />
<!-- Restrict to a subset of locales -->
<LangSwitcher current="en" pathname={Astro.url.pathname} locales={['en', 'tr']} /> hreflang in <head> · SEO alternates
Add <link rel="alternate"> tags directly in your layout's <head>. Use the withLocale path helper to build each href.
import { withLocale } from "@lisacorp/wam-astro-components/i18n";
const pathname = Astro.url.pathname;
const baseUrl = "https://magnets.tg";
---
<head>
<link rel="alternate" hreflang="ru" href={`${baseUrl}${withLocale(pathname, 'ru')}`} />
<link rel="alternate" hreflang="en" href={`${baseUrl}${withLocale(pathname, 'en')}`} />
<link rel="alternate" hreflang="tr" href={`${baseUrl}${withLocale(pathname, 'tr')}`} />
<link rel="alternate" hreflang="x-default" href={`${baseUrl}${withLocale(pathname, 'ru')}`} />
</head> Path helpers · detectLang / withLocale / swapLocale
Pure TypeScript utilities. Convention: ru (default) has no prefix;
en and tr use /en/ and /tr/ prefixes.
import { detectLang, withLocale, swapLocale, type Lang } from "@lisacorp/wam-astro-components/i18n";
// Detect lang from URL — use in layout or middleware
detectLang('/en/about') // → 'en'
detectLang('/about') // → 'ru' (default, no prefix)
detectLang('/tr/pricing') // → 'tr'
// Build locale-aware path
withLocale('/about', 'en') // → '/en/about'
withLocale('/en/about', 'ru') // → '/about' (strips prefix for default)
withLocale('/en/about', 'tr') // → '/tr/about'
// Swap locale in the current URL (used inside a switcher)
swapLocale(Astro.url.pathname, 'tr') i18n string convention · site copy pattern
Store strings in the consumer repo, not in the styleguide — copy is product-specific. The styleguide owns the structural pattern; consumers own the text.
// src/i18n/strings.ts (in your consumer repo, e.g. wam-online)
import type { Lang } from "@lisacorp/wam-astro-components/i18n";
export const strings = {
ru: {
hero: { title: "Ваш AI-агент в Telegram", lede: "Работает в любом чате." },
nav: { start: "Начать", docs: "Документация" },
},
en: {
hero: { title: "Your AI agent in Telegram", lede: "Works in any chat." },
nav: { start: "Get started", docs: "Docs" },
},
tr: {
hero: { title: "Telegram'da AI ajanınız", lede: "Her sohbette çalışır." },
nav: { start: "Başlayın", docs: "Belgeler" },
},
} satisfies Record<Lang, { hero: { title: string; lede: string }; nav: { start: string; docs: string } }>;
export function t(lang: Lang) { return strings[lang]; } satisfies Record<Lang, …> makes TypeScript fail at compile time
if a key is missing when a new locale is added to Lang.
Full integration example
// src/layouts/Shell.astro
---
import { detectLang, withLocale } from "@lisacorp/wam-astro-components/i18n";
import LangSwitcher from "@lisacorp/wam-astro-components/patterns/LangSwitcher.astro";
import { t } from "../i18n/strings";
const lang = detectLang(Astro.url.pathname);
const tx = t(lang);
const pathname = Astro.url.pathname;
const base = "https://magnets.tg";
---
<html lang={lang}>
<head>
<link rel="alternate" hreflang="ru" href={`${base}${withLocale(pathname,'ru')}`} />
<link rel="alternate" hreflang="en" href={`${base}${withLocale(pathname,'en')}`} />
<link rel="alternate" hreflang="tr" href={`${base}${withLocale(pathname,'tr')}`} />
<link rel="alternate" hreflang="x-default" href={`${base}${withLocale(pathname,'ru')}`} />
</head>
<body>
<nav>
<LangSwitcher current={lang} pathname={pathname} />
</nav>
<h1>{tx.hero.title}</h1>
<slot />
</body>
</html>