@uniweb/core 0.11.1 → 0.11.2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniweb/core",
3
- "version": "0.11.1",
3
+ "version": "0.11.2",
4
4
  "description": "Core classes for the Uniweb platform - Uniweb, Website, Page, Block",
5
5
  "type": "module",
6
6
  "exports": {
@@ -41,6 +41,72 @@ function codeOf(entry) {
41
41
  * @param {*} value - The authored `languages` value.
42
42
  * @returns {boolean}
43
43
  */
44
+ /**
45
+ * Human-readable display names for the locales a site is likely to declare.
46
+ *
47
+ * This lives in core, not kit, because core is what BUILDS the locale objects a
48
+ * foundation reads (`website.getLocales()`, `website.langs`). It used to live
49
+ * only in kit, so core could not resolve a label and left the field absent for
50
+ * a plain-string `languages:` entry — which meant the very form this module
51
+ * tells authors to migrate TO produced worse labels than the legacy object form
52
+ * it warns about. Measured 2026-08-23 on a site with 11 locales: dropping the
53
+ * `label:` keys silently turned "Français" into "fr" in the switcher, because
54
+ * the common foundation idiom is `locale.label || locale.code`.
55
+ *
56
+ * Kit re-exports this so `@uniweb/kit`'s `LOCALE_DISPLAY_NAMES` keeps working.
57
+ */
58
+ export const LOCALE_DISPLAY_NAMES = {
59
+ en: 'English',
60
+ es: 'Español',
61
+ fr: 'Français',
62
+ de: 'Deutsch',
63
+ it: 'Italiano',
64
+ pt: 'Português',
65
+ nl: 'Nederlands',
66
+ pl: 'Polski',
67
+ ru: 'Русский',
68
+ ja: '日本語',
69
+ ko: '한국어',
70
+ zh: '中文',
71
+ 'zh-CN': '简体中文',
72
+ 'zh-TW': '繁體中文',
73
+ ar: 'العربية',
74
+ he: 'עברית',
75
+ hi: 'हिन्दी',
76
+ th: 'ไทย',
77
+ vi: 'Tiếng Việt',
78
+ tr: 'Türkçe',
79
+ uk: 'Українська',
80
+ cs: 'Čeština',
81
+ el: 'Ελληνικά',
82
+ hu: 'Magyar',
83
+ ro: 'Română',
84
+ sv: 'Svenska',
85
+ da: 'Dansk',
86
+ fi: 'Suomi',
87
+ no: 'Norsk',
88
+ id: 'Bahasa Indonesia',
89
+ ms: 'Bahasa Melayu'
90
+ }
91
+
92
+ /**
93
+ * Resolve a locale's display label.
94
+ *
95
+ * Priority: an explicitly configured `label` -> the display-name table -> the
96
+ * code uppercased. Accepts either a bare code string or a `{ code, label? }`
97
+ * object, so callers do not have to branch on which form the config used.
98
+ *
99
+ * @param {string|{code: string, label?: string}} entry
100
+ * @returns {string} Display label, or '' when the entry carries no code.
101
+ */
102
+ export function localeLabel(entry) {
103
+ if (typeof entry === 'string') {
104
+ return LOCALE_DISPLAY_NAMES[entry] || entry.toUpperCase()
105
+ }
106
+ if (!entry || typeof entry.code !== 'string' || !entry.code) return ''
107
+ return entry.label || LOCALE_DISPLAY_NAMES[entry.code] || entry.code.toUpperCase()
108
+ }
109
+
44
110
  export function isWildcardLanguages(value) {
45
111
  return value === '*' || (Array.isArray(value) && value.includes('*'))
46
112
  }
package/src/website.js CHANGED
@@ -10,7 +10,7 @@ import EntityStore from './entity-store.js'
10
10
  import FetcherDispatcher from './fetcher-dispatcher.js'
11
11
  import ObservableState from './observable-state.js'
12
12
  import { normalizeSeo } from './seo.js'
13
- import { resolveDefaultLocale } from './locale-config.js'
13
+ import { resolveDefaultLocale, localeLabel } from './locale-config.js'
14
14
  import { matchDynamicRoute, decodeRouteValue } from './route-match.js'
15
15
 
16
16
  /**
@@ -226,8 +226,12 @@ export default class Website {
226
226
  /**
227
227
  * Build locales list from config
228
228
  * Supports both string codes and objects: ['es', 'fr'] or [{code: 'es', label: 'Español'}]
229
- * Labels are passed through if provided; otherwise only code is returned.
230
- * Use kit's getLocaleLabel() for display names.
229
+ * Every returned locale carries a resolved `label`: an explicitly configured
230
+ * one wins, otherwise it comes from LOCALE_DISPLAY_NAMES, otherwise the code
231
+ * uppercased. It used to be passed through only when configured, which made
232
+ * the common foundation idiom `locale.label || locale.code` render "fr"
233
+ * instead of "Français" for a plain-string `languages:` entry — i.e. the form
234
+ * locale-config tells authors to migrate to was the one that read worse.
231
235
  * @private
232
236
  */
233
237
  buildLocalesList(config) {
@@ -262,6 +266,7 @@ export default class Website {
262
266
  // Build final array with isDefault flag
263
267
  return Array.from(localeMap.values()).map(locale => ({
264
268
  ...locale,
269
+ label: localeLabel(locale),
265
270
  isDefault: locale.code === defaultLocale
266
271
  }))
267
272
  }
@@ -857,9 +862,16 @@ export default class Website {
857
862
  // ─────────────────────────────────────────────────────────────────
858
863
 
859
864
  /**
860
- * Get all available locales
861
- * Label is optional - use kit's getLocaleLabel() for display names if not provided.
862
- * @returns {Array<{code: string, label?: string, isDefault: boolean}>}
865
+ * Get all available locales.
866
+ *
867
+ * `label` is always present and always displayable: an explicitly configured
868
+ * label wins, otherwise it is resolved from LOCALE_DISPLAY_NAMES, otherwise it
869
+ * is the code uppercased. So `locale.label` needs no fallback at the call site
870
+ * — the idiom `locale.label || locale.code` is now redundant rather than
871
+ * load-bearing, and kit's `getLocaleLabel()` is only needed for a code that
872
+ * did not come from here.
873
+ *
874
+ * @returns {Array<{code: string, label: string, isDefault: boolean}>}
863
875
  */
864
876
  getLocales() {
865
877
  return this.locales