@devslab/site-kit 0.8.1 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -215,7 +215,9 @@ function acceptedLocales(header, canonicalLocale) {
215
215
  /** The family registry — what every helper in this package uses by default. */
216
216
  var FAMILY_LOCALES = defineLocaleRegistry();
217
217
  var { canonicalLocale, localeAttributes, resolveLocale } = FAMILY_LOCALES;
218
- Object.freeze({
218
+ //#endregion
219
+ //#region src/core/flag-countries.mjs
220
+ var FLAG_COUNTRY = Object.freeze({
219
221
  "ko": "kr",
220
222
  "en": "us",
221
223
  "ja": "jp",
@@ -231,6 +233,30 @@ Object.freeze({
231
233
  "es": "es",
232
234
  "ar": "sa"
233
235
  });
236
+ /** Every vendored flag is 4:3 on this box, so any <use> can point at any symbol. */
237
+ var FLAG_VIEWBOX = "0 0 640 480";
238
+ var VENDORED = new Set(Object.values(FLAG_COUNTRY));
239
+ /**
240
+ * The country whose flag stands for a locale — a family locale through
241
+ * FLAG_COUNTRY, a product's own through its registry's `flagCountry`.
242
+ * Same lookup order and errors as `flagFor`, without loading a body.
243
+ *
244
+ * @param {string} locale
245
+ * @param {{ LOCALES?: ReadonlyArray<{ code: string, flagCountry?: string }> }} [registry]
246
+ * @returns {string}
247
+ */
248
+ function flagCountryFor(locale, registry) {
249
+ const country = FLAG_COUNTRY[locale];
250
+ if (country) return country;
251
+ const extra = registry?.LOCALES?.find((definition) => definition.code === locale);
252
+ if (extra?.flagCountry) {
253
+ if (VENDORED.has(extra.flagCountry)) return extra.flagCountry;
254
+ throw new RangeError(`No vendored flag for country: ${extra.flagCountry} (locale ${locale})`);
255
+ }
256
+ throw new RangeError(`No flag for locale: ${locale}`);
257
+ }
258
+ //#endregion
259
+ //#region src/core/flag-bodies.mjs
234
260
  /**
235
261
  * Flags indexed by country, not by locale.
236
262
  *
@@ -311,67 +337,52 @@ var FLAGS_BY_COUNTRY = Object.freeze({
311
337
  body: "<defs>\n <clipPath id=\"sa-a\">\n <path fill-opacity=\".7\" d=\"M-85.3 0h682.6v512H-85.3z\"/>\n </clipPath>\n </defs>\n <g fill-rule=\"evenodd\" clip-path=\"url(#sa-a)\" transform=\"translate(80)scale(.9375)\">\n <path fill=\"#165d31\" d=\"M-128 0h768v512h-768z\"/>\n <path fill=\"#fff\" d=\"M65.5 145.1c-.8 12-2 33 8.3 35.2 12.3 1.2 5.5-20.8 10-24.8.8-2 2.3-2 2.4.5v18.7c0 6 4 7.8 7 9 3.2-.2 5.4 0 6.6 3l1.6 32.3s7.4 2.2 7.8-18.1c.3-12-2.4-21.9-.8-24.2 0-2.3 3-2.4 5-1.3 3.2 2.2 4.6 5 9.6 4 7.6-2.2 12.2-5.9 12.3-11.7a47 47 0 0 0-3.5-16.6c.4-1-1.4-3.7-1-4.7 1.3 2.2 3.4 2 3.8 0-1.3-4.2-3.3-8.3-6.5-10-2.7-2.4-6.7-2-8 3-.8 5.7 2 12.4 6.1 18 .9 2.1 2.1 5.7 1.6 8.9q-3.4 1.8-6.3-1.2s-6-4.5-6-5.6c1.6-10.2.3-11.4-.6-14.3-.6-3.9-2.5-5.2-4-7.8-1.5-1.6-3.5-1.6-4.5 0-2.7 4.6-1.4 14.5.5 19 1.4 4.1 3.5 6.7 2.5 6.7-.8 2.3-2.5 1.7-3.8-1a67 67 0 0 1-2.1-17.4c-.5-4.6-1.1-14.4-4.2-17-1.8-2.4-4.5-1.2-5.5 1a82 82 0 0 0 .3 13.4c2 7.4 2.7 14 3.7 21.5.3 10.1-5.8 4.4-5.5-.7a45 45 0 0 0-.3-19.4c-1-2.6-2.1-3.2-4.6-2.8-1.9 0-6.8 5.3-8.2 14.3 0 0-1.2 4.6-1.7 8.7-.7 4.6-3.7 8-5.9-.6-1.8-6.3-3-21.6-6-18z\"/>\n <path fill=\"#fff\" d=\"m99 194.2-32 15.4c.3-7.3 15.1-20.4 25.3-20.5 6.5.1 4.9 2.5 6.6 5.1z\"/>\n <path fill=\"#fff\" d=\"M93.3 204.2c-16.8 43.5 39.5 49.6 45.8 1.8.6-2 3-3.9 3.4-.7-1.3 43.3-43.6 46.2-50.8 32.6a42 42 0 0 1-2.5-14.6c-1-8.5-5.5-5.2-6.2 3.2-.7 4.7-.5 6-.5 10.5 2.2 34.2 56.7 19.5 65.6-8.7 4.7-15.6-.8-27.1 1.7-27.1 5.4 5.8 13 .8 14.7-1.2.7-1 2.5-1.7 3.7-.4 4.2 3 11.6 1.6 13.2-3.7q1.4-8 1.8-16.2c-3.5 1-6 1.7-6.3 3.2l-.7 4.6c-.3 1.5-3.2 1.5-3.4-.4-1.3-6-6.7-6.7-10 2.5-2.1 1.8-6.1 2.2-6.5-.5.5-6.2-2-7-7-4.1l-4.8-36.2c2 0 4 1.5 5.9-.9-2-6.5-6.5-19.7-9-20.7-1.1-1.4-2.1-.5-3.7-.1-2.6.8-5 3-4.2 7.4 3 18.8 5 33.1 8.1 52 .5 2.1-1.3 5-3.7 4.7-4-2.7-5-8.2-12-8-5 0-10.6 5.5-11.3 10.7-.9 4.2-1.2 8.7 0 12.3 3.5 4.2 7.7 3.8 11.4 2.9 3-1.3 5.5-4.3 6.6-3.6.7.9.1 10.9-14.3 18.5-8.7 4-15.7 4.8-19.4-2.3-2.3-4.5.2-21.4-5.6-17.5\"/>\n <path fill=\"#fff\" d=\"M165 160c3.3-1.2 19.3-19.6 19.3-19.6l-2.4-2q-1.3-1.1 0-2.2c4-2.4 2.7-7.4.7-9.8a10 10 0 0 0-8.7.1c-2.8 2.7-3.4 7-1.2 9.6 2.1 1 4.2 3.2 2.8 4.4-6.6 7-24.5 19.1-22.4 19.5.4.6 11.5.6 11.8 0zm-97 65c-6 9.6-6.5 23.9-3.2 28.2 1.8 2 4.7 2.9 6.8 2.2 3.8-1.6 5.5-9.3 4.6-12q-1.8-3-3.6-.7c-2.6 5.4-3.7 1.7-4-1.3a70 70 0 0 1 .8-15.2c.7-4.2 0-3-1.4-1.2m257.1-15.3c-5.8-12.6-13.9-25-16.4-29.7a558 558 0 0 0-24.8-36c-6.2-7.4 10.2 3.1-2-11.7l-8.9-7.5c-2-1.4-6.8-4-7.6.2-.4 3.8-.2 5.8.4 8.9.5 2 3.5 5.5 5 7.5a565 565 0 0 1 53.8 86.5c2.6-1.3 2-16.1.5-18.2\"/>\n <path fill=\"#fff\" d=\"M299.6 251.5c-1.2 1.3 2.8 6.8 8 6.8 8.6-1 16.2-5.8 23.2-18.6a33 33 0 0 0 5.3-14.2 317 317 0 0 0-5.8-72.4c-.3-2 0-4.4.2-5 .6-.7 2.5 0 3.5-1.7 1.5-1.5-4-14-7-18.7-1-2.2-1.5-3.6-3.3.2a27 27 0 0 0-3 13.6c4.1 28.5 5.4 53.4 8 81.9.3 2.8-.1 6.8-2 8.4a80 80 0 0 1-27.1 19.7m116.5-.1c-6.2 3.6-6.2 7.7-1.2 7.8 8.6-1 18.8-1.7 25.8-12.3a41 41 0 0 0 4.2-16 303 303 0 0 0-4.7-71.4c-.2-2-1.1-6.7-.8-7.3.6-1.4 3.4.1 4.4-1.5 1.4-1.5-7.3-12.7-10.4-17.5-1-2.2-1.4-3.6-3.3.2a22 22 0 0 0-1.8 13.6c4.6 31 8 54.2 8.7 81.6-.4 2.6-.5 4-1.7 7.3-2.7 3.4-5.7 7.8-8.5 9.9-2.8 2-8.8 4-10.7 5.6\"/>\n <path fill=\"#fff\" d=\"M420.7 223.7q.1-10.9-.1-19a34 34 0 0 0-3-13.5c-1.8-4.1-.7-7.4-1.6-11.8-.8-4.4-.6-11-1.8-16.1-.4-2-1.4-8.5-1.1-9.2.5-1.4 2.4 0 3.4-1.6 1.4-1.5-5-18-8.2-22.7-1.1-2.1-3.3-1.4-5.8 2-2.5 2.3-1.6 7.4-.6 12.3 6.1 32.3 10.8 61.6 9.8 92.3-.4 2.6 9-7.8 9-12.7m-45.7-40c-3.9-.2-12-7.7-14.4-12a8 8 0 0 1 .4-6.5c1.5-1 3.7-2 5.4-1 0 0 1.7 2.4 1.4 2.7 2 1 3 .5 3.2-.4.1-1.5-.6-2.4-.6-4 .9-4.6 6-5.3 8-2.4 1.4 1.8 2 5.5 2.1 8 0 1.3-2-.2-3.3 0-1.1.4-1.4 1.8-1.5 3-.2 3.3-.6 8.6-.7 12.5zm-71.8 48c1-9.8-.4-27.3-.5-33.1A477 477 0 0 0 299 154c-1.2-8.4 3.4.9 2.8-4-1.5-8.3-6.1-14-11.6-21.5-1.7-2.5-1.7-3-4.4.6-3 6.7-.4 11.4.4 16.7 3.9 17.2 6.2 33 7.3 48.7a393 393 0 0 1 .4 49c3 .1 7.6-4.7 9.3-11.8\"/>\n <path fill=\"#fff\" d=\"M434 216c-6.9-11.6-17.2-24-20-28.7a658 658 0 0 0-29.2-37.8c-8.5-9 4-1.5-1.6-8.5-4.7-5.1-6-6.8-10.1-9.9-2-1.3-3.2-3.8-4 .5a83 83 0 0 0-.2 11.2c0 1.7 1.8 5 3.4 7 20.7 25.5 43.4 51.5 61.6 84.2 2.6-1.3 1.7-16 0-18z\"/>\n <path fill=\"#165d31\" d=\"M122.6 194.7c-.5.9-1.6 2-1.2 3.1q1 1.4 2.6 1.3c1.1 0 2.7.3 3-.3q1-1.2.6-3.3c-1.2-3-4.4-1.8-5-.8\"/>\n <path fill=\"#fff\" d=\"M354.2 362.5c9.2.4 15.2.5 23.3 1.4l9.6-1c10.6-1 11 15.1 11 15.1 0 9.5-3.7 10-8.4 11-2.7.4-4-1.6-5.5-3.6a14 14 0 0 1-7 .4l-11.5-.5c-4-.3-6.2.5-10.3.1-.8 1.3-2 3.1-4.4 2.6-2-.3-4.5-6-3.8-10.5 1.5-3.2 1-2.1 1-3.5-37.6-1-75.5-2.7-112.3-2.2-28.8.1-57.2 1.3-85.7 2.5-15.2-.2-26.8-2.6-34.8-14.3.8 0 38.8 2.1 49.9 1.4 20.5-.2 39.3-1.9 60.2-2.5 41.2.7 82.1.7 123.3 3.6-4-2.7-4-9 2-10.6.5-.4.8 3.1 1.7 3 4.9-.3 2.7 6.3 1.7 7.6M188.6 135.3c-6.2 17.8 3.6 37.4 10.4 35.5 5 2 8-7.4 10-17.6 1.5-2.9 2.5-3.2 3.2-1.7-.2 13.6 1 16.7 4.5 20.8 7.8 6 14.3.8 14.8.3l6-6.1q2.2-2.2 5.1-.3c1.9 1.7 1.6 4.6 5.6 6.6 3.4 1.4 10.5.4 12.2-2.5 2.2-3.9 2.8-5.2 3.8-6.6 1.6-2.1 4.3-1.2 4.3-.5-.3 1.2-1.9 2.3-.8 4.5 2 1.4 2.4.5 3.5.2 4-2 7-10.6 7-10.6.1-3.2-1.7-3-2.9-2.2l-3.1 2.1c-2 .3-5.7 1.6-7.6-1.3-1.9-3.4-1.9-8.3-3.3-11.8 0-.2-2.6-5.5-.2-5.8 1.2.2 3.7.9 4.1-1.2 1.2-2.1-2.6-8-5.3-11-2.3-2.5-5.5-2.8-8.6-.2-2.2 2-1.9 4.2-2.3 6.3a10 10 0 0 0 2 8.7c2.2 4.2 6.1 9.7 4.8 17.5 0 0-2.3 3.6-6.3 3.1-1.7-.3-4.4-1-5.8-11.8-1.1-8 .2-19.4-3.2-24.7-1.3-3.3-2.2-6.4-5.2-.9-.8 2.2-4.3 5.5-1.8 12.2a36 36 0 0 1 2 19c-1.5 2.2-1.8 2.9-3.7 5-2.6 3-5.5 2.2-7.7 1.1-2-1.3-3.6-2-4.6-6.5.2-7 .6-18.5-.7-20.9-1.9-3.8-5-2.4-6.3-1.2a48 48 0 0 0-11.5 23.5c-1.8 5.8-3.7 4.1-5 1.8-3.2-3-3.5-26.7-7.4-22.8\"/>\n <path fill=\"#fff\" d=\"M207.4 174.1c2.9-2 1.6-3.4 5.8.8a72 72 0 0 1 9.2 31.3c-.2 2.6 1.6 4.2 2.5 3.6.4-6 15.1-14.4 28.6-15.6 2-.5 1-4.4 1.3-6.4-.8-7.5 4.2-14.3 11.2-14.8 9.6 1.4 12.8 6.5 13 14.2-1.1 15-16.7 17.5-25.4 18.7-1.3.5-1.9 1.1 0 1.8l36.6.2 1.9 1c.2 1-.6.2-2 2.6a30 30 0 0 0-3.7 11.5c-10.9 3.6-22.2 5-33.6 6.5-4 2-6 4.7-5.2 7.7 1.4 3.3 10.2 6.7 10.2 6.8 1.7 1 3.6 3.5-.5 8.6-17.8-.8-31.7-8.4-36.5-19.1-1.4-1.1-3 0-4 1.4-7 9-13.8 17-25.7 21.4-7 1.8-14.3-1.1-17.7-5.7-2.3-2.7-2.2-5.6-3-6.2-3.9 1.7-36.9 15.7-32.7 9.1 8-8.5 22-14.9 34.2-23.3.9-2.9 2.5-12.5 7.3-15.6.3 0-.7 5.6-.6 8 0 2-.2 2.7.2 2.2.9-.5 15.7-12.2 17-15.8 1.4-2 .3-7.2.3-7.4-2.8-7.2-6.7-7.8-8.1-11.4-1.3-4.7-.7-10.1 2-11.7q3.7-3.1 7.9.5c3 2.7 5.6 8 6.4 11.9-.5 1.5-4-1-5-.3a16 16 0 0 1 3.7 7.8c2 8.2 1.4 11.4-.6 16.7-6.6 13.9-15 18-22.4 23.2-.2 0-.3 3.5 2.4 5.4 1 1 4.9 1.5 9.4 0a55 55 0 0 0 22.3-23.3 51 51 0 0 0-2.4-22.2c-2.9-6.7-6.3-16.2-6.3-16.4-.1-4.2.2-5.6 2-7.7m-95.8-38.6c4.2 2 12.2 1.1 11.8-5.7l-.2-3.1c-.8-2-3.2-1.5-3.7.5-.2.7.3 1.8-.3 2.1-.4.4-1.7.2-1.7-1.7q-.1-1-.7-1.6-.2-.2-.9-.2c-.6 0-.6.1-.9.6l-.3 1.6q-.1.9-.8 1c-.6 0-.5 0-1-.2q-.4-.3-.5-1l-.3-1.6q-.3-.4-1-.6c-2.3 0-2.5 2.7-2.3 3.7-.2.2-.3 4.9 2.8 6.2\"/>\n <path fill=\"#fff\" d=\"M235.1 187.7c4.2 2 14.3.9 11.8-5.6l-.2-3.2c-.9-2-3.2-1.5-3.7.6-.2.6.3 1.7-.4 2-.3.4-1.7.2-1.6-1.6q-.1-1-.7-1.7-.3-.2-1-.2c-.5 0-.5.2-.8.7q-.3.7-.3 1.6-.2.8-.9 1c-.5 0-.4 0-.8-.3q-.5-.3-.6-.9l-.3-1.6q-.3-.5-1-.6c-2.3 0-2.5 2.6-2.4 3.6-.1.2-.2 5 3 6.2zm72-21.6c4.2 2 12.1 1.1 11.8-5.6l-.2-3.2c-.9-2-3.2-1.5-3.7.5-.2.7.3 1.8-.4 2.2-.3.3-1.7.1-1.6-1.8q-.1-1-.7-1.6-.3-.2-1-.2t-.8.7l-.3 1.5q-.1 1-.9 1c-.8 0-.4 0-.8-.2q-.5-.3-.6-.9 0-1-.3-1.7-.4-.4-1-.5c-2.3 0-2.5 2.6-2.4 3.6-.1.2-.2 4.9 3 6.2zm37.3 54.3c-7.3 8.3-4.1 22-2.4 25 2.4 4.8 4.3 7.9 9 10.3 4.3 3.1 7.7 1.2 9.5-1 4.3-4.5 4.4-16 6.4-18.2 1.4-4.2 5-3.5 6.7-1.6a17 17 0 0 0 6.2 5.3c4 3.5 8.8 4.2 13.6 1 3.2-1.9 5.3-4.2 7.2-8.9 2-5.6 1-31.6.5-47l-4.2-21.5c0-.2-.5-10.2-1-12.5 0-1-.3-1.3.7-1.2 1.1 1 1.2 1 2 1.3 1 .2 2-1.7 1.3-3.3l-10-18.6c-.8-.8-1.9-1.6-3.2.2a7 7 0 0 0-2.4 5.5l1.3 13.3 4 22.6c1.3 16 1.6 29.2 2.9 45.3-.2 6.8-2.3 12.7-4.3 13.6 0 0-3 1.7-5-.2-1.5-.6-7.4-9.9-7.4-9.9-3-2.7-5-2-7.1 0-6 5.8-8.6 16.4-12.7 23.8-1 1.7-4 3-7.2-.1-8.2-11.3-3.4-27.3-4.4-23.2M309 126.7c3.8 1.5 6.4 9.2 5.6 13-.8 4.5-2.8 9.5-4.2 8.9-1.6-.6 1-4.6-.5-8.8-.8-2.8-6-7.8-5.4-9.2-1-3.1 2.2-4.5 4.5-4z\"/>\n <path fill=\"#fff\" d=\"M356.6 225c.7-9.2-.6-14.8-.8-20.2s-6.1-46.6-7.3-50.6c-1.5-7.8 5.7-1 4.9-5.6-2.5-5.6-8.6-13.9-10.5-18.8-1.2-2-.7-4-3.3-.5a42 42 0 0 0-2.3 19.2c6.2 32.3 12.5 59.1 11.5 89.8 3 0 6.3-6.7 7.8-13.3m64.4-85.3c3.5 1.7 5.5 11.3 5.1 14-.7 5-2.5 10.4-3.8 9.7-1.5-.6.3-7.4-.4-9.5-.8-3-5.5-8.4-5-10-1-3.4 2-4.8 4.1-4.2m-255.7 67.9c3.3 1.3 5.3 8.3 5 10.3-.8 3.7-2.5 7.7-3.8 7.1-1.3-.4.3-5.4-.3-7-.3-3.7-4.9-5.7-4.8-7.3-.8-3 2-3.5 4-3.1z\"/>\n <path fill=\"#165d31\" d=\"M244.9 218.2c4.2.2 6.3 3.6 2.4 5-4 1.3-7.7 2.4-7.8 8 1.5 8-2 5.2-4 4.2-2.4-1.8-9.2-6-10.2-15-.1-2.1 1.6-4 4.3-4 4 1.1 10 1.2 15.3 1.8\"/>\n <path fill=\"#fff\" d=\"M77.4 124.4c4.8 1.4 5.1 8.6 4.8 10.7-.7 3.8-2.4 7.9-3.6 7.4-1.4-.5 0-5.7-.7-7.3-.7-2.2-4.8-6.4-4.4-7.6-.9-2.5 2-3.7 3.9-3.2m95.9 33.6c-3.8 2-5.2 8-2.9 11.6 2.2 3 5.6 1.9 6 1.9 3.7.4 5.9-6.9 5.9-6.9s.1-2-4.2 1.9c-1.9.3-2-.4-2.5-1.4a9 9 0 0 1 .5-5.7c.7-1.8-.7-2.6-2.8-1.4m28-36.4c-2 1.3-5.7 5.2-5.8 9.6-.1 2.5-.6 2.5 1 4 1.3 1.8 2.4 1.7 4.8.4a5 5 0 0 0 2.3-3.4c.6-2.8-3 1.4-3.4-1.8-.8-3 1.5-4.2 3.7-7 0-2 0-3.3-2.7-1.8zm22.4 4a60 60 0 0 0-1.6 11.1c-.6 2.8 3 4 4.5.4 2.4-6.5 2.4-9.3 2.6-12-.7-4.3-3.6-4.2-5.5.5m142 72.3c.4-.5 20-14.4 20-14.4 2-.7 1.5 7.2.6 7.1a78 78 0 0 1-20.7 14.3c-1 .7-1.9-5.3 0-7zm17.7-.2c3.5 1.7 4.9 11.8 4.5 14.5 0 5.4-3.3 9.6-4.7 9-1.4-.7.2-6.7-.5-8.8-.8-3-3.7-8.5-3.2-10.1-1-3.4 1.8-5.2 4-4.6zm-116 43.4a26 26 0 0 1 5.6-4.9c2-1 3.8.8 3.7.7.3 2-1.2 3.7-.7 6.3.4 1 .7 2.2 2.6 1.8 3.1-2.5 6-2.7 9-2.8 2.5.1 2.6 4.2 1 4.2-5.7 1.2-8.2 2.8-12.3 4.3-2 1.2-3.6-.3-3.6-.4s-1.1-1.1-.4-3.7q.3-3.2-2.4-3c-1.2.8-2.4 1.2-3-.3q-.6-1.4.5-2.2m136.6 5.4c.8 1 1.4 2-.1 3.8l-3.7 3.2c-.6 1-1 2.8 1 3.3 3.6 1 12-4.5 12-4.6 1.4-1 1-3 .8-3-.8-.9-2.6-.3-3.8-.5-.6 0-2.5-.2-1.6-2a11 11 0 0 0 1.6-2.9q.9-1.7-2-2.7c-2.1-.4-3-.2-5.3 0q-1.6.2-1.9 2.3c.1 2.3 1.5 2.2 3 3z\"/>\n <path fill=\"#165d31\" d=\"M268.1 189.7c-.5 1-2.3 1-4 0s-2.7-2.6-2.1-3.5 2.3-.9 4 0 2.6 2.6 2.1 3.5m-89-53.6c-1 .3-2.4-.6-3-2s-.3-2.6.7-2.9 2.3.7 3 2 .3 2.7-.8 3zM355.2 375c9.4.4 18.2 0 27.5.5 1.7 1.5.5 5-.6 4.8l-7.8-.3c-.1-3-7.7-2.5-7.5.1-4.1.5-7.8-.1-12-.3-1.2-1.5-1-4.2.4-4.8\"/>\n </g>"
312
338
  })
313
339
  });
314
- var LOCALE_FLAGS = Object.freeze({
315
- "ko": FLAGS_BY_COUNTRY["kr"],
316
- "en": FLAGS_BY_COUNTRY["us"],
317
- "ja": FLAGS_BY_COUNTRY["jp"],
318
- "zh-HK": FLAGS_BY_COUNTRY["hk"],
319
- "zh-TW": FLAGS_BY_COUNTRY["tw"],
320
- "hi": FLAGS_BY_COUNTRY["in"],
321
- "vi": FLAGS_BY_COUNTRY["vn"],
322
- "id": FLAGS_BY_COUNTRY["id"],
323
- "th": FLAGS_BY_COUNTRY["th"],
324
- "pt-BR": FLAGS_BY_COUNTRY["br"],
325
- "fr": FLAGS_BY_COUNTRY["fr"],
326
- "de": FLAGS_BY_COUNTRY["de"],
327
- "es": FLAGS_BY_COUNTRY["es"],
328
- "ar": FLAGS_BY_COUNTRY["sa"]
329
- });
340
+ //#endregion
341
+ //#region src/solid/flag-bodies.server.ts
330
342
  /**
331
- * @param {string} locale
332
- * @param {{ LOCALES?: ReadonlyArray<{ code: string, flagCountry?: string }> }} [registry]
333
- * A product's locale registry, for a locale the family does not carry.
334
- * Its `flagCountry` names one of FLAGS_BY_COUNTRY.
343
+ * How the Solid menu reaches the flag artwork — server build.
344
+ *
345
+ * The server writes the sprite into the HTML in one pass, so it needs the
346
+ * bodies synchronously and may carry them: a Worker bundle is not a page
347
+ * weight. Same signatures as flag-bodies.ts; the server Vite and Vitest
348
+ * configs alias `./flag-bodies` here.
335
349
  */
336
- function flagFor(locale, registry) {
337
- const flag = LOCALE_FLAGS[locale];
338
- if (flag) return flag;
339
- const extra = registry?.LOCALES?.find((definition) => definition.code === locale);
340
- if (extra?.flagCountry) {
341
- const vendored = FLAGS_BY_COUNTRY[extra.flagCountry];
342
- if (vendored) return vendored;
343
- throw new RangeError(`No vendored flag for country: ${extra.flagCountry} (locale ${locale})`);
344
- }
345
- throw new RangeError(`No flag for locale: ${locale}`);
346
- }
350
+ var flagBodiesNow = () => FLAGS_BY_COUNTRY;
347
351
  //#endregion
348
352
  //#region src/solid/locale-menu.tsx
349
353
  var _tmpl$$5 = [
350
354
  "<svg",
351
- " aria-hidden=\"true\">",
355
+ " class=\"site-flag-sprite\" aria-hidden=\"true\">",
352
356
  "</svg>"
353
357
  ];
354
- var _tmpl$2$3 = [
358
+ var _tmpl$2$3 = ["<svg", " class=\"site-flag-sprite\" aria-hidden=\"true\"></svg>"];
359
+ var _tmpl$3$3 = [
360
+ "<svg",
361
+ " aria-hidden=\"true\"><use href=\"",
362
+ "\"></use></svg>"
363
+ ];
364
+ var _tmpl$4$3 = [
355
365
  "<label",
356
366
  "><span class=\"dds-sr-only\">",
357
367
  "</span><span class=\"dds-select site-locale\"><select class=\"dds-select__input\"",
358
368
  ">",
359
369
  "</select></span></label>"
360
370
  ];
361
- var _tmpl$3$3 = [
371
+ var _tmpl$5$3 = [
362
372
  "<option",
363
373
  "",
364
374
  ">",
365
375
  "</option>"
366
376
  ];
367
- var _tmpl$4$3 = [
377
+ var _tmpl$6$3 = [
368
378
  "<details",
369
379
  " class=\"site-locale-flag\"><summary class=\"site-locale-flag__trigger\"",
370
- ">",
371
- "</summary><ul class=\"site-locale-flag__list\" role=\"list\">",
380
+ "><!--$-->",
381
+ "<!--/--><!--$-->",
382
+ "<!--/--></summary><ul class=\"site-locale-flag__list\" role=\"list\">",
372
383
  "</ul></details>"
373
384
  ];
374
- var _tmpl$5$3 = [
385
+ var _tmpl$7$3 = [
375
386
  "<li",
376
387
  "><a class=\"site-locale-flag__option\"",
377
388
  "><!--$-->",
@@ -389,47 +400,81 @@ function scopeFlagIds(body, uid) {
389
400
  return scoped;
390
401
  }
391
402
  var registryOf = (props) => props.registry ?? FAMILY_LOCALES;
403
+ var symbolId = (country, uid) => `site-flag-${country}-${uid}`;
404
+ function spriteMarkup(countries, bodies, uid) {
405
+ return countries.map((country) => {
406
+ const flag = bodies[country];
407
+ if (!flag) throw new RangeError(`No vendored flag for country: ${country}`);
408
+ return `<symbol id="${symbolId(country, uid)}" viewBox="${flag.viewBox}">${scopeFlagIds(flag.body, uid)}</symbol>`;
409
+ }).join("");
410
+ }
411
+ /**
412
+ * One copy of each flag the menu shows, as <symbol>s the flags <use>.
413
+ *
414
+ * The trigger and the current row used to inline the same body twice, and
415
+ * the browser bundle carried every body so a client render could write
416
+ * them. With a sprite, a locale change on the client only swaps an href,
417
+ * so after hydration the browser never needs the artwork: the server build
418
+ * writes it (flagBodiesNow), hydration adopts it untouched, and only a
419
+ * render with no server HTML — a client-only app, a jsdom test — fetches
420
+ * the bodies through loadFlagBodies, which the browser build emits as its
421
+ * own chunk. Zero-sized rather than display:none so the referenced clip
422
+ * paths and gradients still resolve.
423
+ */
424
+ function FlagSprite(props) {
425
+ const bodies = flagBodiesNow();
426
+ if (bodies) return ssr(_tmpl$$5, ssrHydrationKey(), spriteMarkup(props.countries, bodies, props.uid));
427
+ return ssr(_tmpl$2$3, ssrHydrationKey());
428
+ }
392
429
  function Flag(props) {
393
- const uid = createUniqueId();
394
- const flag = () => flagFor(props.locale, props.registry);
395
- return ssr(_tmpl$$5, ssrHydrationKey() + ssrAttribute("class", escape(props.class, true), false) + ssrAttribute("viewBox", escape(flag().viewBox, true), false), scopeFlagIds(flag().body, uid));
430
+ const country = () => flagCountryFor(props.locale, props.registry);
431
+ return ssr(_tmpl$3$3, ssrHydrationKey() + ssrAttribute("class", escape(props.class, true), false) + ssrAttribute("viewBox", escape(FLAG_VIEWBOX, true), false), `#${escape(symbolId(country(), props.uid), true)}`);
396
432
  }
397
433
  function SelectLocaleMenu(props) {
398
434
  const registry = () => registryOf(props);
399
- return ssr(_tmpl$2$3, ssrHydrationKey(), escape(props.messages.localeLabel), ssrAttribute("aria-label", escape(props.messages.localeLabel, true), false), escape(createComponent(For, {
435
+ return ssr(_tmpl$4$3, ssrHydrationKey(), escape(props.messages.localeLabel), ssrAttribute("aria-label", escape(props.messages.localeLabel, true), false), escape(createComponent(For, {
400
436
  get each() {
401
437
  return registry().LOCALES;
402
438
  },
403
- children: (locale) => ssr(_tmpl$3$3, ssrHydrationKey() + ssrAttribute("value", escape(locale.code, true), false) + ssrAttribute("lang", escape(locale.code, true), false) + ssrAttribute("dir", escape(locale.dir, true), false), ssrAttribute("selected", locale.code === props.state.locale, true), escape(locale.nativeName))
439
+ children: (locale) => ssr(_tmpl$5$3, ssrHydrationKey() + ssrAttribute("value", escape(locale.code, true), false) + ssrAttribute("lang", escape(locale.code, true), false) + ssrAttribute("dir", escape(locale.dir, true), false), ssrAttribute("selected", locale.code === props.state.locale, true), escape(locale.nativeName))
404
440
  })));
405
441
  }
406
442
  function FlagLocaleMenu(props) {
443
+ const uid = createUniqueId();
407
444
  const registry = () => registryOf(props);
445
+ const countries = () => [...new Set(registry().LOCALES.map((entry) => flagCountryFor(entry.code, registry())))];
408
446
  const current = () => registry().LOCALES.find((entry) => entry.code === props.state.locale);
409
447
  const triggerLabel = () => {
410
448
  const name = current()?.nativeName;
411
449
  return name ? `${props.messages.localeLabel}: ${name}` : props.messages.localeLabel;
412
450
  };
413
- return ssr(_tmpl$4$3, ssrHydrationKey(), ssrAttribute("aria-label", escape(triggerLabel(), true), false) + ssrAttribute("title", escape(props.messages.localeLabel, true), false), escape(createComponent(Flag, {
451
+ return ssr(_tmpl$6$3, ssrHydrationKey(), ssrAttribute("aria-label", escape(triggerLabel(), true), false) + ssrAttribute("title", escape(props.messages.localeLabel, true), false), escape(createComponent(FlagSprite, {
452
+ get countries() {
453
+ return countries();
454
+ },
455
+ uid
456
+ })), escape(createComponent(Flag, {
414
457
  get locale() {
415
458
  return props.state.locale;
416
459
  },
417
460
  "class": "site-locale-flag__svg",
418
461
  get registry() {
419
462
  return registry();
420
- }
463
+ },
464
+ uid
421
465
  })), escape(createComponent(For, {
422
466
  get each() {
423
467
  return registry().LOCALES;
424
468
  },
425
- children: (entry) => ssr(_tmpl$5$3, ssrHydrationKey(), ssrAttribute("href", escape(props.state.hrefForLocale(entry.code), true), false) + ssrAttribute("lang", escape(entry.code, true), false) + ssrAttribute("hreflang", escape(entry.code, true), false) + ssrAttribute("dir", escape(entry.dir, true), false) + ssrAttribute("aria-current", entry.code === props.state.locale ? "true" : escape(void 0, true), false), escape(createComponent(Flag, {
469
+ children: (entry) => ssr(_tmpl$7$3, ssrHydrationKey(), ssrAttribute("href", escape(props.state.hrefForLocale(entry.code), true), false) + ssrAttribute("lang", escape(entry.code, true), false) + ssrAttribute("hreflang", escape(entry.code, true), false) + ssrAttribute("dir", escape(entry.dir, true), false) + ssrAttribute("aria-current", entry.code === props.state.locale ? "true" : escape(void 0, true), false), escape(createComponent(Flag, {
426
470
  get locale() {
427
471
  return entry.code;
428
472
  },
429
473
  "class": "site-locale-flag__svg",
430
474
  get registry() {
431
475
  return registry();
432
- }
476
+ },
477
+ uid
433
478
  })), escape(entry.nativeName))
434
479
  })));
435
480
  }
@@ -460,6 +505,15 @@ var _tmpl$2$2 = [
460
505
  "</a></li>"
461
506
  ];
462
507
  var _tmpl$3$2 = [
508
+ "<nav",
509
+ " class=\"site-footer__langs\"",
510
+ "><details class=\"site-footer__langs-menu\"><summary class=\"site-footer__langs-trigger\" aria-label=\"",
511
+ "\"><span",
512
+ ">",
513
+ "</span></summary><ul class=\"site-footer__langs-list\" role=\"list\">",
514
+ "</ul></details></nav>"
515
+ ];
516
+ var _tmpl$4$2 = [
463
517
  "<footer",
464
518
  " class=\"site-footer\"",
465
519
  "><div class=\"site-footer__inner\"><!--$-->",
@@ -470,18 +524,12 @@ var _tmpl$3$2 = [
470
524
  "<!--/--><li>",
471
525
  "</li></ul></div></div></footer>"
472
526
  ];
473
- var _tmpl$4$2 = [
474
- "<nav",
475
- " class=\"site-footer__langs\"",
476
- ">",
477
- "</nav>"
478
- ];
479
- var _tmpl$5$2 = [
527
+ var _tmpl$5$2 = ["<span", " aria-hidden=\"true\">·</span>"];
528
+ var _tmpl$6$2 = [
480
529
  "<a",
481
530
  ">",
482
531
  "</a>"
483
532
  ];
484
- var _tmpl$6$2 = ["<span", " aria-hidden=\"true\">·</span>"];
485
533
  var _tmpl$7$2 = [
486
534
  "<bdi",
487
535
  ">",
@@ -573,6 +621,30 @@ function SiteHeader(props) {
573
621
  } }))), escape(props.actions));
574
622
  }
575
623
  /**
624
+ * The footer's language row, collapsed.
625
+ *
626
+ * It used to be every language laid out flat, which is a different length in
627
+ * every product — ten for one, twenty for another — so the same footer carried
628
+ * a different visual weight depending on how many languages the product sells
629
+ * in. A `<details>` keeps all of them: the anchors are in the document whether
630
+ * it is open or not, so a crawler still follows every locale, and it works with
631
+ * no JavaScript. Same mechanism as the header's flag menu, including Escape
632
+ * returning focus to the trigger.
633
+ *
634
+ * The trigger is the current language's own name rather than a translated word
635
+ * for "language": it is the one label already meaningful to a reader who cannot
636
+ * read the page, and it is what the flat row marked with `aria-current`.
637
+ */
638
+ function FooterLocaleMenu(props) {
639
+ const current = () => props.registry.LOCALES.find((entry) => entry.code === props.state.locale);
640
+ return ssr(_tmpl$3$2, ssrHydrationKey(), ssrAttribute("aria-label", escape(props.label, true), false), `${escape(props.label, true)}: ${escape(current()?.nativeName ?? props.state.locale, true)}`, ssrAttribute("lang", escape(current()?.code, true), false) + ssrAttribute("dir", escape(current()?.dir, true), false), escape(current()?.nativeName ?? props.state.locale), escape(createComponent(For, {
641
+ get each() {
642
+ return props.registry.LOCALES;
643
+ },
644
+ children: (entry) => ssr(_tmpl$2$2, ssrHydrationKey(), ssrAttribute("href", escape(props.state.hrefForLocale(entry.code), true), false) + ssrAttribute("hreflang", escape(entry.code, true), false) + ssrAttribute("lang", escape(entry.code, true), false) + ssrAttribute("dir", escape(entry.dir, true), false) + ssrAttribute("aria-current", entry.code === props.state.locale ? "page" : escape(void 0, true), false), escape(entry.nativeName))
645
+ })));
646
+ }
647
+ /**
576
648
  * The family footer: a language row, then the brand beside its family links,
577
649
  * then the page's links and the copyright.
578
650
  *
@@ -587,21 +659,29 @@ function SiteHeader(props) {
587
659
  */
588
660
  function SiteFooter(props) {
589
661
  const registry = () => props.localeRegistry ?? FAMILY_LOCALES;
590
- return ssr(_tmpl$3$2, ssrHydrationKey(), ssrAttribute("aria-label", escape(props.messages.footerLabel, true), false), escape(createComponent(Show, {
662
+ return ssr(_tmpl$4$2, ssrHydrationKey(), ssrAttribute("aria-label", escape(props.messages.footerLabel, true), false), escape(createComponent(Show, {
591
663
  get when() {
592
664
  return props.locale;
593
665
  },
594
- children: (locale) => ssr(_tmpl$4$2, ssrHydrationKey(), ssrAttribute("aria-label", escape(props.messages.localeLabel, true), false), escape(createComponent(For, {
595
- get each() {
596
- return registry().LOCALES;
666
+ children: (locale) => createComponent(FooterLocaleMenu, {
667
+ get state() {
668
+ return locale();
669
+ },
670
+ get registry() {
671
+ return registry();
597
672
  },
598
- children: (entry) => ssr(_tmpl$5$2, ssrHydrationKey() + ssrAttribute("href", escape(locale().hrefForLocale(entry.code), true), false) + ssrAttribute("hreflang", escape(entry.code, true), false) + ssrAttribute("lang", escape(entry.code, true), false) + ssrAttribute("dir", escape(entry.dir, true), false) + ssrAttribute("aria-current", entry.code === locale().locale ? "page" : escape(void 0, true), false), escape(entry.nativeName))
599
- })))
673
+ get label() {
674
+ return props.messages.localeLabel;
675
+ },
676
+ get onSelect() {
677
+ return props.onLocaleSelect;
678
+ }
679
+ })
600
680
  })), escape(props.brand.logo), escape(props.brand.name), escape(createComponent(For, {
601
681
  get each() {
602
682
  return props.family ?? [];
603
683
  },
604
- children: (item) => [ssr(_tmpl$6$2, ssrHydrationKey()), ssr(_tmpl$5$2, ssrHydrationKey() + ssrAttribute("href", escape(item.href, true), false), escape(item.label))]
684
+ children: (item) => [ssr(_tmpl$5$2, ssrHydrationKey()), ssr(_tmpl$6$2, ssrHydrationKey() + ssrAttribute("href", escape(item.href, true), false), escape(item.label))]
605
685
  })), escape(createComponent(For, {
606
686
  get each() {
607
687
  return props.links;