Архитектура
/en/blog/hello ← локаль по умолчанию, всё равно с префиксом (чище, чем особый случай)
/ru/blog/hello
/zh/blog/hello
/ja/blog/hello
/de/blog/hello
Три движущиеся части:
- Словари — один JSON на локаль, одинаковая форма, типизированная как
Record<Locale, typeof en>, чтобы TypeScript вопил, когда ключ разъехался. - Динамические роуты —
src/pages/[locale]/...сgetStaticPaths(), возвращающей все локали. - Контентный fallback — пиши посты один раз в
en/и рендери их под каждой локалью, пока не появятся переводы.
Типовой трюк, который тебя спасает
export type Locale = "en" | "ru" | "zh" | "ja" | "de";
const dictionaries: Record<Locale, typeof en> = { en, ru, zh, ja, de };
typeof en — это схема. Добавь ключ в en.json, и билд упадёт, пока остальные четыре словаря не догонят.
Не забудь про head
<link rel="alternate" hreflang="..."> для каждой локали плюс x-default, canonical на каждую страницу и пути, выведенные из Astro.url. Поисковики вознаграждают скучную сантехнику.