/** * Flag — renders a country flag image from an ISO 3166-1 alpha-2 code. * Images served from flagcdn.com (free, no auth required). */ const COUNTRY_NAMES: Record = { RU: "Россия", DE: "Германия", NL: "Нидерланды", SG: "Сингапур", US: "США", GB: "Великобритания", FR: "Франция", FI: "Финляндия", SE: "Швеция", PL: "Польша", UA: "Украина", TR: "Турция", JP: "Япония", HK: "Гонконг", } let regionNames: Intl.DisplayNames | null | undefined function regionDisplayName(iso: string): string | undefined { try { if (regionNames === undefined) { regionNames = typeof Intl !== "undefined" && "DisplayNames" in Intl ? new Intl.DisplayNames(["ru"], { type: "region" }) : null } return regionNames?.of(iso) ?? undefined } catch { return undefined } } /** Country name in Russian (fallback to ISO code) */ export function countryName(code: string): string { const iso = code.toUpperCase() if (!iso) return code if (COUNTRY_NAMES[iso]) return COUNTRY_NAMES[iso] const intl = regionDisplayName(iso) if (intl && intl !== iso) return intl return iso } interface FlagProps { code: string /** px size — width of the flag image (height auto-scales 3:2 ratio) */ size?: number className?: string } // flagcdn.com supports only these widths const CDN_SIZES = [20, 40, 80, 160, 320, 640, 1280, 2560] function nearestCdnSize(px: number): number { return CDN_SIZES.find(s => s >= px) ?? CDN_SIZES[CDN_SIZES.length - 1] } /** CDN URL for SVG `` (flagcdn widths only). */ export function flagCdnUrl(code: string, size = 40): string | null { const lower = code.toLowerCase() if (!/^[a-z]{2}$/.test(lower)) return null return `https://flagcdn.com/w${nearestCdnSize(size)}/${lower}.png` } /** * Renders a flag for a given ISO 3166-1 alpha-2 country code. * Source: https://flagcdn.com — free CDN, no API key needed. */ export function Flag({ code, size = 20, className }: FlagProps) { if (!code) return null const lower = code.toLowerCase() if (!/^[a-z]{2}$/.test(lower)) return null const name = countryName(code.toUpperCase()) const cdnSrc = nearestCdnSize(size) const cdnSrc2x = nearestCdnSize(size * 2) return ( // Внешний CDN (динамический URL) — next/image без remotePatterns не подходит // eslint-disable-next-line @next/next/no-img-element -- flagcdn.com, размеры задаём явно {name} ) }