i18n · canonical pattern

i18n

RU / EN / TR3-locale

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>

Source: packages/wam-astro-components/src/i18n/ · packages/wam-astro-components/src/patterns/LangSwitcher.astro · content/i18n-pattern.md