/** * Locale switcher component for i18n-enabled sites. * * Used in both the content list (to filter by locale) and the content editor * (to switch between locale versions of a content item). * * Only renders when i18n is configured (manifest.i18n is present). */ import { useLingui } from "@lingui/react/macro"; import { GlobeSimple } from "@phosphor-icons/react"; import React from "react"; import { cn } from "../lib/utils.js"; interface LocaleSwitcherProps { locales: string[]; defaultLocale: string; value: string; onChange: (locale: string) => void; /** Show "All locales" option (for list filtering) */ showAll?: boolean; className?: string; /** Size variant */ size?: "sm" | "md"; } /** * Get a display label for a locale code. * Uses Intl.DisplayNames when available, falls back to uppercase code. */ function getLocaleLabel(code: string): string { try { const names = new Intl.DisplayNames(["en"], { type: "language" }); return names.of(code) ?? code.toUpperCase(); } catch { return code.toUpperCase(); } } export function LocaleSwitcher({ locales, defaultLocale, value, onChange, showAll = false, className, size = "md", }: LocaleSwitcherProps) { const { t } = useLingui(); return (
); } /** * Compact locale badges showing which translations exist for a content item. * Renders as a row of small locale codes, with existing translations highlighted. */ export function LocaleBadges({ locales, existingLocales, onLocaleClick, }: { locales: string[]; existingLocales: string[]; onLocaleClick?: (locale: string) => void; }) { const { t } = useLingui(); const existingSet = new Set(existingLocales); return (
{locales.map((locale) => { const exists = existingSet.has(locale); const label = getLocaleLabel(locale); return ( ); })}
); } /** * Hook to get i18n config from the manifest query. * Returns null if i18n is not configured. */ export function useI18nConfig( manifest: { i18n?: { defaultLocale: string; locales: string[] } } | undefined, ) { return React.useMemo(() => { if (!manifest?.i18n) return null; return manifest.i18n; }, [manifest?.i18n]); }