@saasicat/ui-vue 0.16.0 → 0.17.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.
Files changed (40) hide show
  1. package/README.md +12 -11
  2. package/dist/{messages-DetB75lX.d.ts → catalog-C4Gv2_KM.d.cts} +115 -40
  3. package/dist/{messages-DetB75lX.d.cts → catalog-C4Gv2_KM.d.ts} +115 -40
  4. package/dist/{chunk-MGKJCVDU.js → chunk-247RJPU4.js} +18 -18
  5. package/dist/{chunk-TZ2NGQXK.js → chunk-IZGFS5RS.js} +44 -8
  6. package/dist/{chunk-CRUUZMMN.js → chunk-XPSD5HKG.js} +30 -4
  7. package/dist/client/index.cjs +75 -10
  8. package/dist/client/index.d.cts +51 -5
  9. package/dist/client/index.d.ts +51 -5
  10. package/dist/client/index.js +12 -4
  11. package/dist/index.cjs +90 -22
  12. package/dist/index.d.cts +5 -5
  13. package/dist/index.d.ts +5 -5
  14. package/dist/index.js +13 -5
  15. package/dist/quasar/index.cjs +54 -20
  16. package/dist/quasar/index.d.cts +2 -2
  17. package/dist/quasar/index.d.ts +2 -2
  18. package/dist/quasar/index.js +2 -2
  19. package/dist/{use-super-admin-i18n-DokHhkS_.d.cts → use-super-admin-i18n-BdPqeTHl.d.cts} +29 -9
  20. package/dist/{use-super-admin-i18n-BPC-H9jz.d.ts → use-super-admin-i18n-uteRCL9q.d.ts} +29 -9
  21. package/package.json +8 -3
  22. package/src/client/i18n/catalog.ts +120 -0
  23. package/src/client/i18n/currency.ts +7 -2
  24. package/src/client/i18n/define.ts +2 -2
  25. package/src/client/i18n/index.ts +1 -0
  26. package/src/client/i18n/locale.ts +40 -11
  27. package/src/client/i18n/messages/bundles.ts +2 -3
  28. package/src/client/i18n/messages/marketing.ts +2 -2
  29. package/src/client/i18n/messages/nav.ts +3 -3
  30. package/src/client/i18n/messages.ts +7 -4
  31. package/src/client/index.ts +1 -0
  32. package/src/client/login-branding.ts +61 -0
  33. package/src/client/nav-builder.ts +33 -6
  34. package/src/components/LocaleSwitcher.vue +21 -12
  35. package/src/components/bundle-editor/bundle-version-status.ts +16 -8
  36. package/src/pages-standard/AdminLayout.vue +7 -3
  37. package/src/pages-standard/SuperAdminLoginPage.vue +8 -9
  38. package/src/pages-standard/discovery-page/discovery-ui.ts +8 -8
  39. package/src/pages-standard/plan-versions/format.ts +2 -2
  40. package/src/vue/use-super-admin-i18n.ts +59 -28
package/dist/index.cjs CHANGED
@@ -67,11 +67,13 @@ __export(src_exports, {
67
67
  buildQuotaRegistry: () => buildQuotaRegistry,
68
68
  buildRoutes: () => buildRoutes,
69
69
  buildSidebar: () => buildSidebar,
70
+ builtinLocaleOf: () => builtinLocaleOf,
70
71
  createAdminResourceClient: () => createAdminResourceClient,
71
72
  createAdminRoutes: () => createAdminRoutes,
72
73
  createManifestStore: () => createManifestStore,
73
74
  createPlatformLoaders: () => createPlatformLoaders,
74
75
  createProjectPageHostRoute: () => createProjectPageHostRoute,
76
+ createSaCatalog: () => createSaCatalog,
75
77
  createSuperAdminI18n: () => createSuperAdminI18n,
76
78
  defaultHttpClient: () => defaultHttpClient,
77
79
  defaultIconForActionKey: () => defaultIconForActionKey,
@@ -83,11 +85,13 @@ __export(src_exports, {
83
85
  formatCurrency: () => formatCurrency,
84
86
  formatMessage: () => formatMessage,
85
87
  getJson: () => getJson,
86
- isSaLocale: () => isSaLocale,
88
+ isProductionBoot: () => isProductionBoot,
89
+ isSaBuiltinLocale: () => isSaBuiltinLocale,
87
90
  mergeMessages: () => mergeMessages,
88
91
  postJson: () => postJson,
89
92
  provideEntitlement: () => provideEntitlement,
90
93
  resolveExtension: () => resolveExtension,
94
+ resolveLoginBranding: () => resolveLoginBranding,
91
95
  resolveMessages: () => resolveMessages,
92
96
  trimTrailingSlashes: () => trimTrailingSlashes,
93
97
  useActions: () => useActions,
@@ -345,9 +349,12 @@ var SA_LOCALE_LABELS = {
345
349
  de: "Deutsch",
346
350
  en: "English"
347
351
  };
348
- function isSaLocale(value) {
352
+ function isSaBuiltinLocale(value) {
349
353
  return typeof value === "string" && SA_LOCALES.includes(value);
350
354
  }
355
+ function builtinLocaleOf(locale, fallback = DEFAULT_SA_LOCALE) {
356
+ return isSaBuiltinLocale(locale) ? locale : fallback;
357
+ }
351
358
 
352
359
  // src/client/i18n/define.ts
353
360
  function defineMessages(de, en) {
@@ -469,15 +476,21 @@ var PAGE_SECTIONS = {
469
476
  platformEmail: "system",
470
477
  platformEmailHistory: "system"
471
478
  };
479
+ function resolveNav(options) {
480
+ return options.nav ?? builtinNav(options.locale);
481
+ }
482
+ function builtinNav(locale) {
483
+ return navMessages[isSaBuiltinLocale(locale) ? locale : DEFAULT_SA_LOCALE];
484
+ }
472
485
  function defaultSectionOrder(locale = DEFAULT_SA_LOCALE) {
473
- const sections = navMessages[locale].sections;
486
+ const sections = typeof locale === "string" ? builtinNav(locale).sections : locale.sections;
474
487
  return [sections.overview, sections.catalog, sections.customers, sections.system];
475
488
  }
476
489
  function buildRoutes(manifest, options = {}) {
477
490
  const routes = [];
478
491
  const capabilities = manifest.capabilities ?? {};
479
492
  const standard = manifest.navigation?.standardPages ?? {};
480
- const nav = navMessages[options.locale ?? DEFAULT_SA_LOCALE];
493
+ const nav = resolveNav(options);
481
494
  const defaultNavSections = Object.fromEntries(
482
495
  Object.entries(PAGE_SECTIONS).map(([page, section]) => [page, nav.sections[section]])
483
496
  );
@@ -812,7 +825,7 @@ function formatterFor(locale, currency, decimals) {
812
825
  const key = `${locale}:${currency}:${decimals}`;
813
826
  let formatter = formatters.get(key);
814
827
  if (!formatter) {
815
- formatter = new Intl.NumberFormat(SA_INTL_LOCALES[locale], {
828
+ formatter = new Intl.NumberFormat(SA_INTL_LOCALES[locale] ?? locale, {
816
829
  style: "currency",
817
830
  currency,
818
831
  minimumFractionDigits: decimals,
@@ -978,7 +991,7 @@ var bundlesMessages = defineMessages(
978
991
  bundleKeyHint: "API-stabil \xB7 wird aus dem Label erzeugt",
979
992
  errorKeyFormat: "Nur A-Z, 0-9, Underscore; muss mit Buchstabe beginnen.",
980
993
  errorKeyExists: "Dieser Bundle-Key existiert bereits.",
981
- descriptionPlaceholder: "z. B. Kampagnen, WhatsApp und Korrespondenz f\xFCr aktive Vereine.",
994
+ descriptionPlaceholder: "z. B. Kampagnen, WhatsApp und Korrespondenz.",
982
995
  sectionPricing: "v1 \xB7 Pricing & G\xFCltigkeit",
983
996
  pricingHint: "Monats- & Jahrespreis sowie Datum, ab dem das Bundle verkaufbar wird.",
984
997
  validFromImmediate: "\u2713 Bundle ist nach Anlage sofort live und verkaufbar.",
@@ -1190,7 +1203,7 @@ var bundlesMessages = defineMessages(
1190
1203
  bundleKeyHint: "API-stable \xB7 derived from the label",
1191
1204
  errorKeyFormat: "Only A-Z, 0-9, underscore; must start with a letter.",
1192
1205
  errorKeyExists: "This bundle key already exists.",
1193
- descriptionPlaceholder: "e.g. Campaigns, WhatsApp and correspondence for active clubs.",
1206
+ descriptionPlaceholder: "e.g. Campaigns, WhatsApp and correspondence.",
1194
1207
  sectionPricing: "v1 \xB7 pricing & validity",
1195
1208
  pricingHint: "Monthly & yearly price plus the date from which the bundle becomes sellable.",
1196
1209
  validFromImmediate: "\u2713 The bundle is live and sellable right after creation.",
@@ -1864,7 +1877,7 @@ var marketingMessages = defineMessages(
1864
1877
  ctaOverrideLabel: "CTA-Text \xFCberschreiben (optional)",
1865
1878
  ctaOverrideHint: "leer lassen f\xFCr Auto-Text",
1866
1879
  topFeatureCount: "{count} Eintr\xE4ge",
1867
- featureLabelPlaceholder: "z. B. Beitragsverwaltung",
1880
+ featureLabelPlaceholder: "z. B. Erweiterte Berichte",
1868
1881
  featureStrongPlaceholder: "Highlight, z. B. bis 100",
1869
1882
  moveUp: "Nach oben",
1870
1883
  moveDown: "Nach unten",
@@ -1992,7 +2005,7 @@ var marketingMessages = defineMessages(
1992
2005
  ctaOverrideLabel: "Override CTA text (optional)",
1993
2006
  ctaOverrideHint: "leave empty for the auto text",
1994
2007
  topFeatureCount: "{count} entries",
1995
- featureLabelPlaceholder: "e.g. Membership management",
2008
+ featureLabelPlaceholder: "e.g. Advanced reporting",
1996
2009
  featureStrongPlaceholder: "Highlight, e.g. up to 100",
1997
2010
  moveUp: "Move up",
1998
2011
  moveDown: "Move down",
@@ -3778,6 +3791,54 @@ function resolveMessages(locale, overrides) {
3778
3791
  return mergeMessages(SA_MESSAGES[locale], overrides);
3779
3792
  }
3780
3793
 
3794
+ // src/client/i18n/catalog.ts
3795
+ function createSaCatalog(options = {}) {
3796
+ const additional = options.additionalLocales ?? {};
3797
+ const known = /* @__PURE__ */ new Set([...SA_LOCALES, ...Object.keys(additional)]);
3798
+ const requested = options.locales?.filter((code) => known.has(code));
3799
+ const offered = requested && requested.length > 0 ? requested : [...SA_LOCALES, ...Object.keys(additional)];
3800
+ const labelFor = (locale) => additional[locale]?.label ?? (isSaBuiltinLocale(locale) ? SA_LOCALE_LABELS[locale] : locale);
3801
+ const cache = /* @__PURE__ */ new Map();
3802
+ const messagesFor = (locale) => {
3803
+ const hit = cache.get(locale);
3804
+ if (hit) return hit;
3805
+ const definition = additional[locale];
3806
+ const base = SA_MESSAGES[definition?.basedOn ?? (isSaBuiltinLocale(locale) ? locale : "en")];
3807
+ const translated = definition ? mergeMessages(base, definition.messages) : base;
3808
+ const resolved = mergeMessages(translated, options.overrides?.[locale]);
3809
+ cache.set(locale, resolved);
3810
+ return resolved;
3811
+ };
3812
+ const offeredSet = new Set(offered);
3813
+ return {
3814
+ locales: offered.map((code) => ({ code, label: labelFor(code) })),
3815
+ has: (locale) => offeredSet.has(locale),
3816
+ // The app's first offered locale beats the platform default: an app
3817
+ // shipping English only must not start in German.
3818
+ defaultLocale: offered.includes(DEFAULT_SA_LOCALE) ? DEFAULT_SA_LOCALE : offered[0],
3819
+ messagesFor,
3820
+ intlLocaleFor: (locale) => additional[locale]?.intlLocale ?? (isSaBuiltinLocale(locale) ? SA_INTL_LOCALES[locale] : locale),
3821
+ labelFor
3822
+ };
3823
+ }
3824
+
3825
+ // src/client/login-branding.ts
3826
+ var DEFAULT_TAG = "SuperAdmin";
3827
+ function resolveLoginBranding(boot, fallback = {}) {
3828
+ const project = boot?.project ?? null;
3829
+ const environment = project?.environment ?? null;
3830
+ return {
3831
+ name: project?.displayName || fallback.name || "",
3832
+ tag: project?.label || fallback.tag || DEFAULT_TAG,
3833
+ icon: project?.icon || fallback.logoText || "",
3834
+ logoUrl: project?.logoUrl || null,
3835
+ environment: environment && environment !== "production" ? environment : null
3836
+ };
3837
+ }
3838
+ function isProductionBoot(boot) {
3839
+ return boot?.project?.environment === "production";
3840
+ }
3841
+
3781
3842
  // src/vue/super-admin-context.ts
3782
3843
  var SUPER_ADMIN_BRAND_KEY = /* @__PURE__ */ Symbol.for(
3783
3844
  "@saasicat/ui-vue/SUPER_ADMIN_BRAND"
@@ -3880,27 +3941,30 @@ var SUPER_ADMIN_I18N_KEY = /* @__PURE__ */ Symbol.for(
3880
3941
  "@saasicat/ui-vue/SUPER_ADMIN_I18N"
3881
3942
  );
3882
3943
  function createSuperAdminI18n(options = {}) {
3883
- const locale = (0, import_vue2.isRef)(options.locale) ? options.locale : createOwnedLocale(options);
3884
- const messages = (0, import_vue2.computed)(
3885
- () => resolveMessages(locale.value, options.overrides?.[locale.value])
3944
+ const catalog = createSaCatalog(options);
3945
+ const locale = (0, import_vue2.isRef)(options.locale) ? options.locale : createOwnedLocale(options, catalog);
3946
+ const active = (0, import_vue2.computed)(
3947
+ () => catalog.has(locale.value) ? locale.value : catalog.defaultLocale
3886
3948
  );
3887
- const intlLocale = (0, import_vue2.computed)(() => SA_INTL_LOCALES[locale.value]);
3949
+ const messages = (0, import_vue2.computed)(() => catalog.messagesFor(active.value));
3950
+ const intlLocale = (0, import_vue2.computed)(() => catalog.intlLocaleFor(active.value));
3888
3951
  const writable = !(0, import_vue2.isReadonly)(locale);
3889
3952
  return {
3890
3953
  locale,
3891
3954
  messages,
3892
3955
  intlLocale,
3893
- switcherEnabled: (options.switcher ?? true) && writable
3956
+ switcherEnabled: (options.switcher ?? true) && writable && catalog.locales.length > 1,
3957
+ availableLocales: catalog.locales
3894
3958
  };
3895
3959
  }
3896
- function createOwnedLocale(options) {
3897
- if (options.persist === false) {
3898
- return (0, import_vue2.ref)(options.locale ?? DEFAULT_SA_LOCALE);
3899
- }
3960
+ function createOwnedLocale(options, catalog) {
3961
+ const initial = options.locale ?? catalog.defaultLocale;
3962
+ if (options.persist === false) return (0, import_vue2.ref)(initial);
3900
3963
  const storage = options.storage ?? defaultKvStore();
3901
- const stored = storage.get(SA_LOCALE_STORAGE_KEY);
3902
- const locale = (0, import_vue2.ref)(isSaLocale(stored) ? stored : options.locale ?? DEFAULT_SA_LOCALE);
3903
- (0, import_vue2.watch)(locale, (next) => storage.set(SA_LOCALE_STORAGE_KEY, next));
3964
+ const key = `${options.storageKeyPrefix ?? ""}${SA_LOCALE_STORAGE_KEY}`;
3965
+ const stored = storage.get(key);
3966
+ const locale = (0, import_vue2.ref)(stored && catalog.has(stored) ? stored : initial);
3967
+ (0, import_vue2.watch)(locale, (next) => storage.set(key, next));
3904
3968
  return locale;
3905
3969
  }
3906
3970
  var fallbackI18n = null;
@@ -6656,11 +6720,13 @@ function defaultTenantPlanSectionI18n(locale) {
6656
6720
  buildQuotaRegistry,
6657
6721
  buildRoutes,
6658
6722
  buildSidebar,
6723
+ builtinLocaleOf,
6659
6724
  createAdminResourceClient,
6660
6725
  createAdminRoutes,
6661
6726
  createManifestStore,
6662
6727
  createPlatformLoaders,
6663
6728
  createProjectPageHostRoute,
6729
+ createSaCatalog,
6664
6730
  createSuperAdminI18n,
6665
6731
  defaultHttpClient,
6666
6732
  defaultIconForActionKey,
@@ -6672,11 +6738,13 @@ function defaultTenantPlanSectionI18n(locale) {
6672
6738
  formatCurrency,
6673
6739
  formatMessage,
6674
6740
  getJson,
6675
- isSaLocale,
6741
+ isProductionBoot,
6742
+ isSaBuiltinLocale,
6676
6743
  mergeMessages,
6677
6744
  postJson,
6678
6745
  provideEntitlement,
6679
6746
  resolveExtension,
6747
+ resolveLoginBranding,
6680
6748
  resolveMessages,
6681
6749
  trimTrailingSlashes,
6682
6750
  useActions,
package/dist/index.d.cts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { BootLoaderOptions, ManifestLoaderOptions, BuildRouteEntry, SidebarSection, NavBuilderOptions, BatchColumnData, BatchColumnFetcherOptions, BootLoader, ManifestLoader } from './client/index.cjs';
2
- export { ADMIN_UI_VERSION, AdminPromoListFilter, AdminPromoListRow, AdminResourceClientOptions, BatchColumnDriftError, BatchColumnFetcher, BatchColumnRow, BatchColumnValue, BootLoadError, CachedManifestEntry, DEFAULT_STANDARD_PAGE_ROUTES, HttpJsonError, ManifestLoadError, MessageParams, ParamStyle, SidebarItem, buildRoutes, buildSidebar, createAdminResourceClient, defaultSectionOrder, formatCurrency, formatMessage, getJson, postJson, resolveExtension, trimTrailingSlashes } from './client/index.cjs';
3
- import { H as HttpClient, c as ActionRegistry, A as ActionHandler, K as KvStore, S as SaLocale } from './messages-DetB75lX.cjs';
4
- export { d as ActionDefNotInManifestError, D as DEFAULT_SA_LOCALE, e as HttpResponse, M as MessageTree, f as MissingHandlerError, P as PartialMessages, R as ResolvedAction, g as SA_INTL_LOCALES, h as SA_LOCALES, i as SA_LOCALE_LABELS, j as SA_MESSAGES, a as SaMessages, b as SaMessagesOverrides, T as TranslationOf, k as defaultHttpClient, l as defaultKvStore, m as defineMessages, n as isSaLocale, o as mergeMessages, r as resolveMessages } from './messages-DetB75lX.cjs';
5
- import { A as ActionsMap, a as SuperAdminBrand, b as SuperAdminEndpoints, E as ExtensionsMap, c as SuperAdminLoginAdapter } from './use-super-admin-i18n-DokHhkS_.cjs';
6
- export { f as ExtensionLoader, I as InstallPlugin, g as SA_LOCALE_STORAGE_KEY, h as SUPER_ADMIN_ACTIONS_KEY, i as SUPER_ADMIN_BRAND_KEY, j as SUPER_ADMIN_ENDPOINTS_KEY, k as SUPER_ADMIN_EXTENSIONS_KEY, l as SUPER_ADMIN_HTTP_KEY, m as SUPER_ADMIN_I18N_KEY, n as SUPER_ADMIN_LOGIN_ADAPTER_KEY, o as SUPER_ADMIN_MANIFEST_KEY, p as SUPER_ADMIN_NOTIFY_KEY, q as SuperAdminAuthGuardOptions, S as SuperAdminGuardOptions, e as SuperAdminI18n, d as SuperAdminI18nOptions, r as SuperAdminLoginResult, s as SuperAdminManifestGuardOptions, U as UiNotify, t as UiNotifyKind, u as UiNotifyOptions, v as buildNavigationGuard, w as createSuperAdminI18n, x as useSaMessages, y as useSuperAdminI18n } from './use-super-admin-i18n-DokHhkS_.cjs';
2
+ export { ADMIN_UI_VERSION, AdminPromoListFilter, AdminPromoListRow, AdminResourceClientOptions, BatchColumnDriftError, BatchColumnFetcher, BatchColumnRow, BatchColumnValue, BootLoadError, CachedManifestEntry, DEFAULT_STANDARD_PAGE_ROUTES, HttpJsonError, LoginBootProject, LoginBrandFallback, LoginBranding, ManifestLoadError, MessageParams, ParamStyle, SidebarItem, buildRoutes, buildSidebar, createAdminResourceClient, defaultSectionOrder, formatCurrency, formatMessage, getJson, isProductionBoot, postJson, resolveExtension, resolveLoginBranding, trimTrailingSlashes } from './client/index.cjs';
3
+ import { H as HttpClient, e as ActionRegistry, A as ActionHandler, K as KvStore, S as SaLocale } from './catalog-C4Gv2_KM.cjs';
4
+ export { f as ActionDefNotInManifestError, D as DEFAULT_SA_LOCALE, g as HttpResponse, M as MessageTree, h as MissingHandlerError, P as PartialMessages, R as ResolvedAction, i as SA_INTL_LOCALES, j as SA_LOCALES, k as SA_LOCALE_LABELS, l as SA_MESSAGES, m as SaBuiltinLocale, n as SaCatalog, o as SaCatalogOptions, c as SaLocaleDefinition, b as SaLocaleOption, a as SaMessages, d as SaMessagesOverrides, T as TranslationOf, p as builtinLocaleOf, q as createSaCatalog, r as defaultHttpClient, s as defaultKvStore, t as defineMessages, u as isSaBuiltinLocale, v as mergeMessages, w as resolveMessages } from './catalog-C4Gv2_KM.cjs';
5
+ import { A as ActionsMap, a as SuperAdminBrand, b as SuperAdminEndpoints, E as ExtensionsMap, c as SuperAdminLoginAdapter } from './use-super-admin-i18n-BdPqeTHl.cjs';
6
+ export { f as ExtensionLoader, I as InstallPlugin, g as SA_LOCALE_STORAGE_KEY, h as SUPER_ADMIN_ACTIONS_KEY, i as SUPER_ADMIN_BRAND_KEY, j as SUPER_ADMIN_ENDPOINTS_KEY, k as SUPER_ADMIN_EXTENSIONS_KEY, l as SUPER_ADMIN_HTTP_KEY, m as SUPER_ADMIN_I18N_KEY, n as SUPER_ADMIN_LOGIN_ADAPTER_KEY, o as SUPER_ADMIN_MANIFEST_KEY, p as SUPER_ADMIN_NOTIFY_KEY, q as SuperAdminAuthGuardOptions, S as SuperAdminGuardOptions, e as SuperAdminI18n, d as SuperAdminI18nOptions, r as SuperAdminLoginResult, s as SuperAdminManifestGuardOptions, U as UiNotify, t as UiNotifyKind, u as UiNotifyOptions, v as buildNavigationGuard, w as createSuperAdminI18n, x as useSaMessages, y as useSuperAdminI18n } from './use-super-admin-i18n-BdPqeTHl.cjs';
7
7
  import { AdminManifest, TenantListFilter, TenantDto, AuditQuery, AuditEntry, FeatureUiRegistry, PromoPreviewResponse, OnboardingSelectionRequest, PublicMarketingBundle, FeatureDef, FeatureKey, PublicBootResponse, DiscoverySnapshot, CapabilityCatalogEntryRow, FeatureCatalogEntryRow, QuotaCatalogEntryRow, ReviewCatalogEntryData, CatalogEntryI18n, UpdateCatalogEntryBaseData, SyncDiscoveryResult, BundleVersionRow, CreateBundleVersionDraftData, BundleVersionMutationResult, UpdateBundleVersionDraftData, BundleRow, CreateBundleData, UpdateBundleData, SubscriptionBundleRecord, MarketingProjectionFilter, MarketingProjectionRow, CreateMarketingProjectionData, UpdateMarketingProjectionData, PromotionRow, CreatePromotionData, UpdatePromotionData, PlanVersionRow, CreatePlanVersionDraftData, PlanVersionMutationResult, UpdatePlanVersionDraftData, PlanRow, CreatePlanData, UpdatePlanData, TenantActionDef } from '@saasicat/types';
8
8
  import { RouteRecordRaw, NavigationGuardWithThis } from 'vue-router';
9
9
  import * as vue from 'vue';
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { BootLoaderOptions, ManifestLoaderOptions, BuildRouteEntry, SidebarSection, NavBuilderOptions, BatchColumnData, BatchColumnFetcherOptions, BootLoader, ManifestLoader } from './client/index.js';
2
- export { ADMIN_UI_VERSION, AdminPromoListFilter, AdminPromoListRow, AdminResourceClientOptions, BatchColumnDriftError, BatchColumnFetcher, BatchColumnRow, BatchColumnValue, BootLoadError, CachedManifestEntry, DEFAULT_STANDARD_PAGE_ROUTES, HttpJsonError, ManifestLoadError, MessageParams, ParamStyle, SidebarItem, buildRoutes, buildSidebar, createAdminResourceClient, defaultSectionOrder, formatCurrency, formatMessage, getJson, postJson, resolveExtension, trimTrailingSlashes } from './client/index.js';
3
- import { H as HttpClient, c as ActionRegistry, A as ActionHandler, K as KvStore, S as SaLocale } from './messages-DetB75lX.js';
4
- export { d as ActionDefNotInManifestError, D as DEFAULT_SA_LOCALE, e as HttpResponse, M as MessageTree, f as MissingHandlerError, P as PartialMessages, R as ResolvedAction, g as SA_INTL_LOCALES, h as SA_LOCALES, i as SA_LOCALE_LABELS, j as SA_MESSAGES, a as SaMessages, b as SaMessagesOverrides, T as TranslationOf, k as defaultHttpClient, l as defaultKvStore, m as defineMessages, n as isSaLocale, o as mergeMessages, r as resolveMessages } from './messages-DetB75lX.js';
5
- import { A as ActionsMap, a as SuperAdminBrand, b as SuperAdminEndpoints, E as ExtensionsMap, c as SuperAdminLoginAdapter } from './use-super-admin-i18n-BPC-H9jz.js';
6
- export { f as ExtensionLoader, I as InstallPlugin, g as SA_LOCALE_STORAGE_KEY, h as SUPER_ADMIN_ACTIONS_KEY, i as SUPER_ADMIN_BRAND_KEY, j as SUPER_ADMIN_ENDPOINTS_KEY, k as SUPER_ADMIN_EXTENSIONS_KEY, l as SUPER_ADMIN_HTTP_KEY, m as SUPER_ADMIN_I18N_KEY, n as SUPER_ADMIN_LOGIN_ADAPTER_KEY, o as SUPER_ADMIN_MANIFEST_KEY, p as SUPER_ADMIN_NOTIFY_KEY, q as SuperAdminAuthGuardOptions, S as SuperAdminGuardOptions, e as SuperAdminI18n, d as SuperAdminI18nOptions, r as SuperAdminLoginResult, s as SuperAdminManifestGuardOptions, U as UiNotify, t as UiNotifyKind, u as UiNotifyOptions, v as buildNavigationGuard, w as createSuperAdminI18n, x as useSaMessages, y as useSuperAdminI18n } from './use-super-admin-i18n-BPC-H9jz.js';
2
+ export { ADMIN_UI_VERSION, AdminPromoListFilter, AdminPromoListRow, AdminResourceClientOptions, BatchColumnDriftError, BatchColumnFetcher, BatchColumnRow, BatchColumnValue, BootLoadError, CachedManifestEntry, DEFAULT_STANDARD_PAGE_ROUTES, HttpJsonError, LoginBootProject, LoginBrandFallback, LoginBranding, ManifestLoadError, MessageParams, ParamStyle, SidebarItem, buildRoutes, buildSidebar, createAdminResourceClient, defaultSectionOrder, formatCurrency, formatMessage, getJson, isProductionBoot, postJson, resolveExtension, resolveLoginBranding, trimTrailingSlashes } from './client/index.js';
3
+ import { H as HttpClient, e as ActionRegistry, A as ActionHandler, K as KvStore, S as SaLocale } from './catalog-C4Gv2_KM.js';
4
+ export { f as ActionDefNotInManifestError, D as DEFAULT_SA_LOCALE, g as HttpResponse, M as MessageTree, h as MissingHandlerError, P as PartialMessages, R as ResolvedAction, i as SA_INTL_LOCALES, j as SA_LOCALES, k as SA_LOCALE_LABELS, l as SA_MESSAGES, m as SaBuiltinLocale, n as SaCatalog, o as SaCatalogOptions, c as SaLocaleDefinition, b as SaLocaleOption, a as SaMessages, d as SaMessagesOverrides, T as TranslationOf, p as builtinLocaleOf, q as createSaCatalog, r as defaultHttpClient, s as defaultKvStore, t as defineMessages, u as isSaBuiltinLocale, v as mergeMessages, w as resolveMessages } from './catalog-C4Gv2_KM.js';
5
+ import { A as ActionsMap, a as SuperAdminBrand, b as SuperAdminEndpoints, E as ExtensionsMap, c as SuperAdminLoginAdapter } from './use-super-admin-i18n-uteRCL9q.js';
6
+ export { f as ExtensionLoader, I as InstallPlugin, g as SA_LOCALE_STORAGE_KEY, h as SUPER_ADMIN_ACTIONS_KEY, i as SUPER_ADMIN_BRAND_KEY, j as SUPER_ADMIN_ENDPOINTS_KEY, k as SUPER_ADMIN_EXTENSIONS_KEY, l as SUPER_ADMIN_HTTP_KEY, m as SUPER_ADMIN_I18N_KEY, n as SUPER_ADMIN_LOGIN_ADAPTER_KEY, o as SUPER_ADMIN_MANIFEST_KEY, p as SUPER_ADMIN_NOTIFY_KEY, q as SuperAdminAuthGuardOptions, S as SuperAdminGuardOptions, e as SuperAdminI18n, d as SuperAdminI18nOptions, r as SuperAdminLoginResult, s as SuperAdminManifestGuardOptions, U as UiNotify, t as UiNotifyKind, u as UiNotifyOptions, v as buildNavigationGuard, w as createSuperAdminI18n, x as useSaMessages, y as useSuperAdminI18n } from './use-super-admin-i18n-uteRCL9q.js';
7
7
  import { AdminManifest, TenantListFilter, TenantDto, AuditQuery, AuditEntry, FeatureUiRegistry, PromoPreviewResponse, OnboardingSelectionRequest, PublicMarketingBundle, FeatureDef, FeatureKey, PublicBootResponse, DiscoverySnapshot, CapabilityCatalogEntryRow, FeatureCatalogEntryRow, QuotaCatalogEntryRow, ReviewCatalogEntryData, CatalogEntryI18n, UpdateCatalogEntryBaseData, SyncDiscoveryResult, BundleVersionRow, CreateBundleVersionDraftData, BundleVersionMutationResult, UpdateBundleVersionDraftData, BundleRow, CreateBundleData, UpdateBundleData, SubscriptionBundleRecord, MarketingProjectionFilter, MarketingProjectionRow, CreateMarketingProjectionData, UpdateMarketingProjectionData, PromotionRow, CreatePromotionData, UpdatePromotionData, PlanVersionRow, CreatePlanVersionDraftData, PlanVersionMutationResult, UpdatePlanVersionDraftData, PlanRow, CreatePlanData, UpdatePlanData, TenantActionDef } from '@saasicat/types';
8
8
  import { RouteRecordRaw, NavigationGuardWithThis } from 'vue-router';
9
9
  import * as vue from 'vue';
package/dist/index.js CHANGED
@@ -16,10 +16,12 @@ import {
16
16
  createAdminResourceClient,
17
17
  defaultSectionOrder,
18
18
  getJson,
19
+ isProductionBoot,
19
20
  postJson,
20
21
  resolveExtension,
22
+ resolveLoginBranding,
21
23
  trimTrailingSlashes
22
- } from "./chunk-CRUUZMMN.js";
24
+ } from "./chunk-XPSD5HKG.js";
23
25
  import {
24
26
  SA_LOCALE_STORAGE_KEY,
25
27
  SUPER_ADMIN_ACTIONS_KEY,
@@ -35,22 +37,24 @@ import {
35
37
  createSuperAdminI18n,
36
38
  useSaMessages,
37
39
  useSuperAdminI18n
38
- } from "./chunk-MGKJCVDU.js";
40
+ } from "./chunk-247RJPU4.js";
39
41
  import {
40
42
  DEFAULT_SA_LOCALE,
41
43
  SA_INTL_LOCALES,
42
44
  SA_LOCALES,
43
45
  SA_LOCALE_LABELS,
44
46
  SA_MESSAGES,
47
+ builtinLocaleOf,
48
+ createSaCatalog,
45
49
  defaultHttpClient,
46
50
  defaultKvStore,
47
51
  defineMessages,
48
52
  formatCurrency,
49
53
  formatMessage,
50
- isSaLocale,
54
+ isSaBuiltinLocale,
51
55
  mergeMessages,
52
56
  resolveMessages
53
- } from "./chunk-TZ2NGQXK.js";
57
+ } from "./chunk-IZGFS5RS.js";
54
58
 
55
59
  // src/vue/use-super-admin-context.ts
56
60
  import { inject } from "vue";
@@ -2837,11 +2841,13 @@ export {
2837
2841
  buildQuotaRegistry,
2838
2842
  buildRoutes,
2839
2843
  buildSidebar,
2844
+ builtinLocaleOf,
2840
2845
  createAdminResourceClient,
2841
2846
  createAdminRoutes,
2842
2847
  createManifestStore,
2843
2848
  createPlatformLoaders,
2844
2849
  createProjectPageHostRoute,
2850
+ createSaCatalog,
2845
2851
  createSuperAdminI18n,
2846
2852
  defaultHttpClient,
2847
2853
  defaultIconForActionKey,
@@ -2853,11 +2859,13 @@ export {
2853
2859
  formatCurrency,
2854
2860
  formatMessage,
2855
2861
  getJson,
2856
- isSaLocale,
2862
+ isProductionBoot,
2863
+ isSaBuiltinLocale,
2857
2864
  mergeMessages,
2858
2865
  postJson,
2859
2866
  provideEntitlement,
2860
2867
  resolveExtension,
2868
+ resolveLoginBranding,
2861
2869
  resolveMessages,
2862
2870
  trimTrailingSlashes,
2863
2871
  useActions,
@@ -138,7 +138,11 @@ var SA_INTL_LOCALES = {
138
138
  de: "de-DE",
139
139
  en: "en-US"
140
140
  };
141
- function isSaLocale(value) {
141
+ var SA_LOCALE_LABELS = {
142
+ de: "Deutsch",
143
+ en: "English"
144
+ };
145
+ function isSaBuiltinLocale(value) {
142
146
  return typeof value === "string" && SA_LOCALES.includes(value);
143
147
  }
144
148
 
@@ -313,7 +317,7 @@ var bundlesMessages = defineMessages(
313
317
  bundleKeyHint: "API-stabil \xB7 wird aus dem Label erzeugt",
314
318
  errorKeyFormat: "Nur A-Z, 0-9, Underscore; muss mit Buchstabe beginnen.",
315
319
  errorKeyExists: "Dieser Bundle-Key existiert bereits.",
316
- descriptionPlaceholder: "z. B. Kampagnen, WhatsApp und Korrespondenz f\xFCr aktive Vereine.",
320
+ descriptionPlaceholder: "z. B. Kampagnen, WhatsApp und Korrespondenz.",
317
321
  sectionPricing: "v1 \xB7 Pricing & G\xFCltigkeit",
318
322
  pricingHint: "Monats- & Jahrespreis sowie Datum, ab dem das Bundle verkaufbar wird.",
319
323
  validFromImmediate: "\u2713 Bundle ist nach Anlage sofort live und verkaufbar.",
@@ -525,7 +529,7 @@ var bundlesMessages = defineMessages(
525
529
  bundleKeyHint: "API-stable \xB7 derived from the label",
526
530
  errorKeyFormat: "Only A-Z, 0-9, underscore; must start with a letter.",
527
531
  errorKeyExists: "This bundle key already exists.",
528
- descriptionPlaceholder: "e.g. Campaigns, WhatsApp and correspondence for active clubs.",
532
+ descriptionPlaceholder: "e.g. Campaigns, WhatsApp and correspondence.",
529
533
  sectionPricing: "v1 \xB7 pricing & validity",
530
534
  pricingHint: "Monthly & yearly price plus the date from which the bundle becomes sellable.",
531
535
  validFromImmediate: "\u2713 The bundle is live and sellable right after creation.",
@@ -1199,7 +1203,7 @@ var marketingMessages = defineMessages(
1199
1203
  ctaOverrideLabel: "CTA-Text \xFCberschreiben (optional)",
1200
1204
  ctaOverrideHint: "leer lassen f\xFCr Auto-Text",
1201
1205
  topFeatureCount: "{count} Eintr\xE4ge",
1202
- featureLabelPlaceholder: "z. B. Beitragsverwaltung",
1206
+ featureLabelPlaceholder: "z. B. Erweiterte Berichte",
1203
1207
  featureStrongPlaceholder: "Highlight, z. B. bis 100",
1204
1208
  moveUp: "Nach oben",
1205
1209
  moveDown: "Nach unten",
@@ -1327,7 +1331,7 @@ var marketingMessages = defineMessages(
1327
1331
  ctaOverrideLabel: "Override CTA text (optional)",
1328
1332
  ctaOverrideHint: "leave empty for the auto text",
1329
1333
  topFeatureCount: "{count} entries",
1330
- featureLabelPlaceholder: "e.g. Membership management",
1334
+ featureLabelPlaceholder: "e.g. Advanced reporting",
1331
1335
  featureStrongPlaceholder: "Highlight, e.g. up to 100",
1332
1336
  moveUp: "Move up",
1333
1337
  moveDown: "Move down",
@@ -3158,9 +3162,36 @@ var SA_MESSAGES = {
3158
3162
  de: catalogFor("de"),
3159
3163
  en: catalogFor("en")
3160
3164
  };
3161
- function resolveMessages(locale, overrides) {
3162
- if (!overrides) return SA_MESSAGES[locale];
3163
- return mergeMessages(SA_MESSAGES[locale], overrides);
3165
+
3166
+ // src/client/i18n/catalog.ts
3167
+ function createSaCatalog(options = {}) {
3168
+ const additional = options.additionalLocales ?? {};
3169
+ const known = /* @__PURE__ */ new Set([...SA_LOCALES, ...Object.keys(additional)]);
3170
+ const requested = options.locales?.filter((code) => known.has(code));
3171
+ const offered = requested && requested.length > 0 ? requested : [...SA_LOCALES, ...Object.keys(additional)];
3172
+ const labelFor = (locale) => additional[locale]?.label ?? (isSaBuiltinLocale(locale) ? SA_LOCALE_LABELS[locale] : locale);
3173
+ const cache = /* @__PURE__ */ new Map();
3174
+ const messagesFor = (locale) => {
3175
+ const hit = cache.get(locale);
3176
+ if (hit) return hit;
3177
+ const definition = additional[locale];
3178
+ const base = SA_MESSAGES[definition?.basedOn ?? (isSaBuiltinLocale(locale) ? locale : "en")];
3179
+ const translated = definition ? mergeMessages(base, definition.messages) : base;
3180
+ const resolved = mergeMessages(translated, options.overrides?.[locale]);
3181
+ cache.set(locale, resolved);
3182
+ return resolved;
3183
+ };
3184
+ const offeredSet = new Set(offered);
3185
+ return {
3186
+ locales: offered.map((code) => ({ code, label: labelFor(code) })),
3187
+ has: (locale) => offeredSet.has(locale),
3188
+ // The app's first offered locale beats the platform default: an app
3189
+ // shipping English only must not start in German.
3190
+ defaultLocale: offered.includes(DEFAULT_SA_LOCALE) ? DEFAULT_SA_LOCALE : offered[0],
3191
+ messagesFor,
3192
+ intlLocaleFor: (locale) => additional[locale]?.intlLocale ?? (isSaBuiltinLocale(locale) ? SA_INTL_LOCALES[locale] : locale),
3193
+ labelFor
3194
+ };
3164
3195
  }
3165
3196
 
3166
3197
  // src/vue/use-super-admin-i18n.ts
@@ -3169,27 +3200,30 @@ var SUPER_ADMIN_I18N_KEY = /* @__PURE__ */ Symbol.for(
3169
3200
  "@saasicat/ui-vue/SUPER_ADMIN_I18N"
3170
3201
  );
3171
3202
  function createSuperAdminI18n(options = {}) {
3172
- const locale = (0, import_vue.isRef)(options.locale) ? options.locale : createOwnedLocale(options);
3173
- const messages = (0, import_vue.computed)(
3174
- () => resolveMessages(locale.value, options.overrides?.[locale.value])
3203
+ const catalog = createSaCatalog(options);
3204
+ const locale = (0, import_vue.isRef)(options.locale) ? options.locale : createOwnedLocale(options, catalog);
3205
+ const active = (0, import_vue.computed)(
3206
+ () => catalog.has(locale.value) ? locale.value : catalog.defaultLocale
3175
3207
  );
3176
- const intlLocale = (0, import_vue.computed)(() => SA_INTL_LOCALES[locale.value]);
3208
+ const messages = (0, import_vue.computed)(() => catalog.messagesFor(active.value));
3209
+ const intlLocale = (0, import_vue.computed)(() => catalog.intlLocaleFor(active.value));
3177
3210
  const writable = !(0, import_vue.isReadonly)(locale);
3178
3211
  return {
3179
3212
  locale,
3180
3213
  messages,
3181
3214
  intlLocale,
3182
- switcherEnabled: (options.switcher ?? true) && writable
3215
+ switcherEnabled: (options.switcher ?? true) && writable && catalog.locales.length > 1,
3216
+ availableLocales: catalog.locales
3183
3217
  };
3184
3218
  }
3185
- function createOwnedLocale(options) {
3186
- if (options.persist === false) {
3187
- return (0, import_vue.ref)(options.locale ?? DEFAULT_SA_LOCALE);
3188
- }
3219
+ function createOwnedLocale(options, catalog) {
3220
+ const initial = options.locale ?? catalog.defaultLocale;
3221
+ if (options.persist === false) return (0, import_vue.ref)(initial);
3189
3222
  const storage = options.storage ?? defaultKvStore();
3190
- const stored = storage.get(SA_LOCALE_STORAGE_KEY);
3191
- const locale = (0, import_vue.ref)(isSaLocale(stored) ? stored : options.locale ?? DEFAULT_SA_LOCALE);
3192
- (0, import_vue.watch)(locale, (next) => storage.set(SA_LOCALE_STORAGE_KEY, next));
3223
+ const key = `${options.storageKeyPrefix ?? ""}${SA_LOCALE_STORAGE_KEY}`;
3224
+ const stored = storage.get(key);
3225
+ const locale = (0, import_vue.ref)(stored && catalog.has(stored) ? stored : initial);
3226
+ (0, import_vue.watch)(locale, (next) => storage.set(key, next));
3193
3227
  return locale;
3194
3228
  }
3195
3229
 
@@ -2,8 +2,8 @@ import { Component, App } from 'vue';
2
2
  import { QuasarPluginOptions } from 'quasar';
3
3
  import { Pinia } from 'pinia';
4
4
  import { RouteRecordRaw, RouterHistory, Router } from 'vue-router';
5
- import { H as HttpClient } from '../messages-DetB75lX.cjs';
6
- import { S as SuperAdminGuardOptions, a as SuperAdminBrand, b as SuperAdminEndpoints, E as ExtensionsMap, A as ActionsMap, c as SuperAdminLoginAdapter, U as UiNotify, I as InstallPlugin, d as SuperAdminI18nOptions, e as SuperAdminI18n } from '../use-super-admin-i18n-DokHhkS_.cjs';
5
+ import { H as HttpClient } from '../catalog-C4Gv2_KM.cjs';
6
+ import { S as SuperAdminGuardOptions, a as SuperAdminBrand, b as SuperAdminEndpoints, E as ExtensionsMap, A as ActionsMap, c as SuperAdminLoginAdapter, U as UiNotify, I as InstallPlugin, d as SuperAdminI18nOptions, e as SuperAdminI18n } from '../use-super-admin-i18n-BdPqeTHl.cjs';
7
7
  import '@saasicat/types';
8
8
 
9
9
  interface CreateSuperAdminAppOptions extends SuperAdminGuardOptions {
@@ -2,8 +2,8 @@ import { Component, App } from 'vue';
2
2
  import { QuasarPluginOptions } from 'quasar';
3
3
  import { Pinia } from 'pinia';
4
4
  import { RouteRecordRaw, RouterHistory, Router } from 'vue-router';
5
- import { H as HttpClient } from '../messages-DetB75lX.js';
6
- import { S as SuperAdminGuardOptions, a as SuperAdminBrand, b as SuperAdminEndpoints, E as ExtensionsMap, A as ActionsMap, c as SuperAdminLoginAdapter, U as UiNotify, I as InstallPlugin, d as SuperAdminI18nOptions, e as SuperAdminI18n } from '../use-super-admin-i18n-BPC-H9jz.js';
5
+ import { H as HttpClient } from '../catalog-C4Gv2_KM.js';
6
+ import { S as SuperAdminGuardOptions, a as SuperAdminBrand, b as SuperAdminEndpoints, E as ExtensionsMap, A as ActionsMap, c as SuperAdminLoginAdapter, U as UiNotify, I as InstallPlugin, d as SuperAdminI18nOptions, e as SuperAdminI18n } from '../use-super-admin-i18n-uteRCL9q.js';
7
7
  import '@saasicat/types';
8
8
 
9
9
  interface CreateSuperAdminAppOptions extends SuperAdminGuardOptions {
@@ -10,10 +10,10 @@ import {
10
10
  SUPER_ADMIN_NOTIFY_KEY,
11
11
  buildNavigationGuard,
12
12
  createSuperAdminI18n
13
- } from "../chunk-MGKJCVDU.js";
13
+ } from "../chunk-247RJPU4.js";
14
14
  import {
15
15
  defaultHttpClient
16
- } from "../chunk-TZ2NGQXK.js";
16
+ } from "../chunk-IZGFS5RS.js";
17
17
 
18
18
  // src/quasar/create-super-admin-app.ts
19
19
  import { createApp } from "vue";
@@ -1,7 +1,7 @@
1
1
  import { Component, App, InjectionKey, Ref, ComputedRef } from 'vue';
2
2
  import { NavigationGuardWithThis } from 'vue-router';
3
3
  import { ActionKey, ComponentKey, AdminManifest } from '@saasicat/types';
4
- import { A as ActionHandler, H as HttpClient, S as SaLocale, a as SaMessages, b as SaMessagesOverrides, K as KvStore } from './messages-DetB75lX.cjs';
4
+ import { A as ActionHandler, H as HttpClient, S as SaLocale, a as SaMessages, b as SaLocaleOption, c as SaLocaleDefinition, d as SaMessagesOverrides, K as KvStore } from './catalog-C4Gv2_KM.cjs';
5
5
 
6
6
  /**
7
7
  * App-specific branding data that the platform `AdminLayout` and other
@@ -184,19 +184,34 @@ interface SuperAdminI18n {
184
184
  intlLocale: ComputedRef<string>;
185
185
  /**
186
186
  * Whether the shell renders its language switcher. `false` when the app
187
- * opted out or when `locale` cannot be written to — a switcher that cannot
188
- * change anything is worse than none.
187
+ * opted out, when `locale` cannot be written to, or when only one language
188
+ * is on offer — a switcher that cannot change anything is worse than none.
189
189
  */
190
190
  switcherEnabled: boolean;
191
+ /** Locales the switcher offers, in order, with their display names. */
192
+ availableLocales: readonly SaLocaleOption[];
191
193
  }
192
194
  interface SuperAdminI18nOptions {
193
195
  /**
194
- * Starting UI locale, default `'de'` — the shell's switcher lets the user
195
- * pick another one, and a stored pick outranks this. Pass a `Ref` when the
196
- * app wants to keep control (e.g. a user-profile setting).
196
+ * Starting UI locale — the shell's switcher lets the user pick another one,
197
+ * and a stored pick outranks this. Defaults to `'de'` when offered,
198
+ * otherwise to the first entry of `locales`. Pass a `Ref` when the app wants
199
+ * to keep control (e.g. a user-profile setting).
197
200
  */
198
201
  locale?: SaLocale | Ref<SaLocale>;
199
- /** Per-locale string overrides layered over the platform catalog. */
202
+ /**
203
+ * Languages to offer, in switcher order. Default: German, English and
204
+ * everything in `additionalLocales`. Narrow it to ship a single language —
205
+ * the switcher then hides itself.
206
+ */
207
+ locales?: readonly SaLocale[];
208
+ /**
209
+ * Languages the app adds on top of the two the platform ships, keyed by
210
+ * locale code. Untranslated keys fall back to `basedOn`, so a partial
211
+ * catalog is usable from the first key onwards.
212
+ */
213
+ additionalLocales?: Readonly<Record<string, SaLocaleDefinition>>;
214
+ /** Per-locale string overrides layered over whatever catalog applies. */
200
215
  overrides?: Partial<Record<SaLocale, SaMessagesOverrides>>;
201
216
  /**
202
217
  * Remembers the locale picked in the header switcher across reloads,
@@ -205,10 +220,15 @@ interface SuperAdminI18nOptions {
205
220
  */
206
221
  persist?: boolean;
207
222
  /**
208
- * Storage adapter for `persist`. Defaults to `defaultKvStore()`. Pass a
209
- * key-prefixing wrapper when several apps share one origin.
223
+ * Storage adapter for `persist`. Defaults to `defaultKvStore()`.
210
224
  */
211
225
  storage?: KvStore;
226
+ /**
227
+ * Prefix for the persisted key, mirroring `createPlatformLoaders`. Set it
228
+ * when several apps share one origin and must not inherit each other's
229
+ * language pick.
230
+ */
231
+ storageKeyPrefix?: string;
212
232
  /**
213
233
  * Renders the language switcher in the shell chrome, default `true`. Set
214
234
  * `false` for a deployment that ships one language. A readonly `locale`