fix(flags): replace hand-coded inline SVGs with official flag-icons assets
The previous inline flag SVGs were visually broken — most notably the 'en' Union Jack, which was reduced to a single X plus a cross and did not resemble the real flag at all. The 'de' and 'ru' stripes also had slight off-by-pixel rounding errors. Switched to lipis/flag-icons (CC-BY 4.0) shipped as static files under public/img/flags/. These are the canonical, professionally-designed flag icons with correct proportions and all the details of the real flags. Loaded via plain <img> tags (no JS, no external CDN at runtime, no FOUC, no extra request after the page is cached). Locale code mapping: en -> gb (per ADR-002, en = en-GB). Unknown locales fall back to a 1x1 transparent gif so the layout stays intact.
This commit is contained in:
@@ -47,7 +47,7 @@ final class LocaleSwitcher
|
||||
'UTF-8',
|
||||
);
|
||||
$currentCode = htmlspecialchars($this->currentLocale, ENT_QUOTES, 'UTF-8');
|
||||
$currentFlag = self::flagSvg($this->currentLocale);
|
||||
$currentFlag = self::flagImg($this->currentLocale);
|
||||
|
||||
$html = '<details class="locale-switcher">';
|
||||
$html .= '<summary class="locale-switcher__trigger"'
|
||||
@@ -68,7 +68,7 @@ final class LocaleSwitcher
|
||||
'UTF-8',
|
||||
);
|
||||
$codeAttr = htmlspecialchars($code, ENT_QUOTES, 'UTF-8');
|
||||
$flag = self::flagSvg($code);
|
||||
$flag = self::flagImg($code);
|
||||
|
||||
$html .= '<li>';
|
||||
if ($isCurrent) {
|
||||
@@ -99,46 +99,40 @@ final class LocaleSwitcher
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline 24×16 SVG for the four supported locales.
|
||||
* Country flag for the given locale. Renders a 24×18 <img>
|
||||
* pointing at the official flag-icons SVG asset shipped under
|
||||
* public/img/flags/. 4:3 aspect (de/gb/ua/ru), crisp at any DPI,
|
||||
* no external CDN dependency.
|
||||
*
|
||||
* - DE: black/red/gold horizontal stripes (Germany)
|
||||
* - EN: simplified Union Jack (en-GB per ADR-002)
|
||||
* - UK: blue/yellow horizontal stripes (Ukraine)
|
||||
* - RU: white/blue/red horizontal stripes (Russia)
|
||||
*
|
||||
* Decorative: marked `aria-hidden="true"` + `focusable="false"`.
|
||||
* The full accessible name is conveyed by the visible label and
|
||||
* the <a>'s hreflang/lang.
|
||||
* Decorative: `alt=""` (the visible locale-switcher label and
|
||||
* the <a>'s `hreflang`/`lang` carry the accessible name).
|
||||
*/
|
||||
public static function flagSvg(string $locale): string
|
||||
public static function flagImg(string $locale): string
|
||||
{
|
||||
$svg = match ($locale) {
|
||||
'de' => '<svg class="flag" viewBox="0 0 24 16" aria-hidden="true" focusable="false">'
|
||||
. '<rect width="24" height="5.33" fill="#000"/>'
|
||||
. '<rect y="5.33" width="24" height="5.34" fill="#DD0000"/>'
|
||||
. '<rect y="10.67" width="24" height="5.33" fill="#FFCC00"/>'
|
||||
. '</svg>',
|
||||
'en' => '<svg class="flag" viewBox="0 0 24 16" aria-hidden="true" focusable="false">'
|
||||
. '<rect width="24" height="16" fill="#012169"/>'
|
||||
. '<path d="M0,0 L24,16 M24,0 L0,16" stroke="#fff" stroke-width="2.4"/>'
|
||||
. '<path d="M0,0 L24,16 M24,0 L0,16" stroke="#C8102E" stroke-width="1.2"/>'
|
||||
. '<path d="M12,0 V16 M0,8 H24" stroke="#fff" stroke-width="3.2"/>'
|
||||
. '<path d="M12,0 V16 M0,8 H24" stroke="#C8102E" stroke-width="1.6"/>'
|
||||
. '</svg>',
|
||||
'uk' => '<svg class="flag" viewBox="0 0 24 16" aria-hidden="true" focusable="false">'
|
||||
. '<rect width="24" height="8" fill="#005BBB"/>'
|
||||
. '<rect y="8" width="24" height="8" fill="#FFD500"/>'
|
||||
. '</svg>',
|
||||
'ru' => '<svg class="flag" viewBox="0 0 24 16" aria-hidden="true" focusable="false">'
|
||||
. '<rect width="24" height="5.33" fill="#fff"/>'
|
||||
. '<rect y="5.33" width="24" height="5.34" fill="#0039A6"/>'
|
||||
. '<rect y="10.67" width="24" height="5.33" fill="#D52B1E"/>'
|
||||
. '</svg>',
|
||||
default => '<svg class="flag" viewBox="0 0 24 16" aria-hidden="true" focusable="false">'
|
||||
. '<rect width="24" height="16" fill="#888"/>'
|
||||
. '</svg>',
|
||||
$src = self::flagSource($locale);
|
||||
return '<img class="flag" src="' . $src . '" alt="" width="24" height="18" loading="lazy" decoding="async">';
|
||||
}
|
||||
|
||||
/**
|
||||
* Map our locale codes to flag-icons file names. Locale "en"
|
||||
* is en-GB per ADR-002, so the asset is "gb.svg". Anything we
|
||||
* do not know falls back to a transparent 1×1 gif so the layout
|
||||
* stays intact and the alt text (from the surrounding <a>) is
|
||||
* the only signal.
|
||||
*/
|
||||
private static function flagSource(string $locale): string
|
||||
{
|
||||
$file = match ($locale) {
|
||||
'de' => 'de',
|
||||
'en' => 'gb',
|
||||
'uk' => 'ua',
|
||||
'ru' => 'ru',
|
||||
default => null,
|
||||
};
|
||||
return $svg;
|
||||
if ($file === null) {
|
||||
return 'data:image/gif;base64,R0lGODlhAQABAAAAACwAAAAAAQABAAACAkQBADs=';
|
||||
}
|
||||
return '/img/flags/' . $file . '.svg';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user