@saasicat/ui-vue 0.15.1 → 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.
- package/README.md +13 -10
- package/dist/{messages-BIYw32u1.d.ts → catalog-C4Gv2_KM.d.cts} +126 -39
- package/dist/{messages-BIYw32u1.d.cts → catalog-C4Gv2_KM.d.ts} +126 -39
- package/dist/{chunk-TY2WYKME.js → chunk-247RJPU4.js} +38 -11
- package/dist/{chunk-TBLXKSTR.js → chunk-IZGFS5RS.js} +90 -21
- package/dist/{chunk-66BUSVC5.js → chunk-XPSD5HKG.js} +30 -4
- package/dist/client/index.cjs +122 -22
- package/dist/client/index.d.cts +51 -5
- package/dist/client/index.d.ts +51 -5
- package/dist/client/index.js +14 -2
- package/dist/index.cjs +152 -30
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +17 -3
- package/dist/quasar/index.cjs +110 -14
- package/dist/quasar/index.d.cts +2 -2
- package/dist/quasar/index.d.ts +2 -2
- package/dist/quasar/index.js +2 -2
- package/dist/{use-super-admin-i18n-DL_qI1BY.d.cts → use-super-admin-i18n-BdPqeTHl.d.cts} +51 -5
- package/dist/{use-super-admin-i18n-CWNu_W3u.d.ts → use-super-admin-i18n-uteRCL9q.d.ts} +51 -5
- package/package.json +8 -3
- package/src/client/i18n/catalog.ts +120 -0
- package/src/client/i18n/currency.ts +7 -2
- package/src/client/i18n/define.ts +2 -2
- package/src/client/i18n/index.ts +1 -0
- package/src/client/i18n/locale.ts +52 -8
- package/src/client/i18n/messages/bundles.ts +2 -3
- package/src/client/i18n/messages/marketing.ts +2 -2
- package/src/client/i18n/messages/nav.ts +3 -3
- package/src/client/i18n/messages/shell.ts +2 -0
- package/src/client/i18n/messages.ts +7 -4
- package/src/client/index.ts +1 -0
- package/src/client/login-branding.ts +61 -0
- package/src/client/nav-builder.ts +33 -6
- package/src/client/types.ts +51 -14
- package/src/components/LocaleSwitcher.vue +77 -0
- package/src/components/bundle-editor/bundle-version-status.ts +16 -8
- package/src/pages-standard/AdminLayout.vue +9 -3
- package/src/pages-standard/SuperAdminLoginPage.vue +17 -9
- package/src/pages-standard/SuperAdminSetupWizard.vue +7 -0
- package/src/pages-standard/discovery-page/discovery-ui.ts +8 -8
- package/src/pages-standard/plan-versions/format.ts +2 -2
- package/src/vue/use-super-admin-i18n.ts +116 -19
package/dist/index.js
CHANGED
|
@@ -16,11 +16,14 @@ 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-
|
|
24
|
+
} from "./chunk-XPSD5HKG.js";
|
|
23
25
|
import {
|
|
26
|
+
SA_LOCALE_STORAGE_KEY,
|
|
24
27
|
SUPER_ADMIN_ACTIONS_KEY,
|
|
25
28
|
SUPER_ADMIN_BRAND_KEY,
|
|
26
29
|
SUPER_ADMIN_ENDPOINTS_KEY,
|
|
@@ -34,20 +37,24 @@ import {
|
|
|
34
37
|
createSuperAdminI18n,
|
|
35
38
|
useSaMessages,
|
|
36
39
|
useSuperAdminI18n
|
|
37
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-247RJPU4.js";
|
|
38
41
|
import {
|
|
39
42
|
DEFAULT_SA_LOCALE,
|
|
40
43
|
SA_INTL_LOCALES,
|
|
41
44
|
SA_LOCALES,
|
|
45
|
+
SA_LOCALE_LABELS,
|
|
42
46
|
SA_MESSAGES,
|
|
47
|
+
builtinLocaleOf,
|
|
48
|
+
createSaCatalog,
|
|
43
49
|
defaultHttpClient,
|
|
44
50
|
defaultKvStore,
|
|
45
51
|
defineMessages,
|
|
46
52
|
formatCurrency,
|
|
47
53
|
formatMessage,
|
|
54
|
+
isSaBuiltinLocale,
|
|
48
55
|
mergeMessages,
|
|
49
56
|
resolveMessages
|
|
50
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-IZGFS5RS.js";
|
|
51
58
|
|
|
52
59
|
// src/vue/use-super-admin-context.ts
|
|
53
60
|
import { inject } from "vue";
|
|
@@ -2815,6 +2822,8 @@ export {
|
|
|
2815
2822
|
PromotionsApiError,
|
|
2816
2823
|
SA_INTL_LOCALES,
|
|
2817
2824
|
SA_LOCALES,
|
|
2825
|
+
SA_LOCALE_LABELS,
|
|
2826
|
+
SA_LOCALE_STORAGE_KEY,
|
|
2818
2827
|
SA_MESSAGES,
|
|
2819
2828
|
SUPER_ADMIN_ACTIONS_KEY,
|
|
2820
2829
|
SUPER_ADMIN_BRAND_KEY,
|
|
@@ -2832,11 +2841,13 @@ export {
|
|
|
2832
2841
|
buildQuotaRegistry,
|
|
2833
2842
|
buildRoutes,
|
|
2834
2843
|
buildSidebar,
|
|
2844
|
+
builtinLocaleOf,
|
|
2835
2845
|
createAdminResourceClient,
|
|
2836
2846
|
createAdminRoutes,
|
|
2837
2847
|
createManifestStore,
|
|
2838
2848
|
createPlatformLoaders,
|
|
2839
2849
|
createProjectPageHostRoute,
|
|
2850
|
+
createSaCatalog,
|
|
2840
2851
|
createSuperAdminI18n,
|
|
2841
2852
|
defaultHttpClient,
|
|
2842
2853
|
defaultIconForActionKey,
|
|
@@ -2848,10 +2859,13 @@ export {
|
|
|
2848
2859
|
formatCurrency,
|
|
2849
2860
|
formatMessage,
|
|
2850
2861
|
getJson,
|
|
2862
|
+
isProductionBoot,
|
|
2863
|
+
isSaBuiltinLocale,
|
|
2851
2864
|
mergeMessages,
|
|
2852
2865
|
postJson,
|
|
2853
2866
|
provideEntitlement,
|
|
2854
2867
|
resolveExtension,
|
|
2868
|
+
resolveLoginBranding,
|
|
2855
2869
|
resolveMessages,
|
|
2856
2870
|
trimTrailingSlashes,
|
|
2857
2871
|
useActions,
|
package/dist/quasar/index.cjs
CHANGED
|
@@ -33,6 +33,45 @@ var import_pinia = require("pinia");
|
|
|
33
33
|
var import_vue_router = require("vue-router");
|
|
34
34
|
|
|
35
35
|
// src/client/types.ts
|
|
36
|
+
var NOOP_KV_STORE = {
|
|
37
|
+
get: () => null,
|
|
38
|
+
set: () => {
|
|
39
|
+
},
|
|
40
|
+
remove: () => {
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
function defaultKvStore() {
|
|
44
|
+
const ls = resolveLocalStorage();
|
|
45
|
+
if (!ls) return NOOP_KV_STORE;
|
|
46
|
+
return {
|
|
47
|
+
get: (k) => {
|
|
48
|
+
try {
|
|
49
|
+
return ls.getItem(k);
|
|
50
|
+
} catch {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
set: (k, v) => {
|
|
55
|
+
try {
|
|
56
|
+
ls.setItem(k, v);
|
|
57
|
+
} catch {
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
remove: (k) => {
|
|
61
|
+
try {
|
|
62
|
+
ls.removeItem(k);
|
|
63
|
+
} catch {
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function resolveLocalStorage() {
|
|
69
|
+
try {
|
|
70
|
+
return globalThis.localStorage ?? null;
|
|
71
|
+
} catch {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
36
75
|
function defaultHttpClient() {
|
|
37
76
|
return (url, init) => fetch(url, init);
|
|
38
77
|
}
|
|
@@ -93,11 +132,19 @@ var SUPER_ADMIN_NOTIFY_KEY = /* @__PURE__ */ Symbol.for(
|
|
|
93
132
|
var import_vue = require("vue");
|
|
94
133
|
|
|
95
134
|
// src/client/i18n/locale.ts
|
|
135
|
+
var SA_LOCALES = ["de", "en"];
|
|
96
136
|
var DEFAULT_SA_LOCALE = "de";
|
|
97
137
|
var SA_INTL_LOCALES = {
|
|
98
138
|
de: "de-DE",
|
|
99
139
|
en: "en-US"
|
|
100
140
|
};
|
|
141
|
+
var SA_LOCALE_LABELS = {
|
|
142
|
+
de: "Deutsch",
|
|
143
|
+
en: "English"
|
|
144
|
+
};
|
|
145
|
+
function isSaBuiltinLocale(value) {
|
|
146
|
+
return typeof value === "string" && SA_LOCALES.includes(value);
|
|
147
|
+
}
|
|
101
148
|
|
|
102
149
|
// src/client/i18n/define.ts
|
|
103
150
|
function defineMessages(de, en) {
|
|
@@ -270,7 +317,7 @@ var bundlesMessages = defineMessages(
|
|
|
270
317
|
bundleKeyHint: "API-stabil \xB7 wird aus dem Label erzeugt",
|
|
271
318
|
errorKeyFormat: "Nur A-Z, 0-9, Underscore; muss mit Buchstabe beginnen.",
|
|
272
319
|
errorKeyExists: "Dieser Bundle-Key existiert bereits.",
|
|
273
|
-
descriptionPlaceholder: "z. B. Kampagnen, WhatsApp und Korrespondenz
|
|
320
|
+
descriptionPlaceholder: "z. B. Kampagnen, WhatsApp und Korrespondenz.",
|
|
274
321
|
sectionPricing: "v1 \xB7 Pricing & G\xFCltigkeit",
|
|
275
322
|
pricingHint: "Monats- & Jahrespreis sowie Datum, ab dem das Bundle verkaufbar wird.",
|
|
276
323
|
validFromImmediate: "\u2713 Bundle ist nach Anlage sofort live und verkaufbar.",
|
|
@@ -482,7 +529,7 @@ var bundlesMessages = defineMessages(
|
|
|
482
529
|
bundleKeyHint: "API-stable \xB7 derived from the label",
|
|
483
530
|
errorKeyFormat: "Only A-Z, 0-9, underscore; must start with a letter.",
|
|
484
531
|
errorKeyExists: "This bundle key already exists.",
|
|
485
|
-
descriptionPlaceholder: "e.g. Campaigns, WhatsApp and correspondence
|
|
532
|
+
descriptionPlaceholder: "e.g. Campaigns, WhatsApp and correspondence.",
|
|
486
533
|
sectionPricing: "v1 \xB7 pricing & validity",
|
|
487
534
|
pricingHint: "Monthly & yearly price plus the date from which the bundle becomes sellable.",
|
|
488
535
|
validFromImmediate: "\u2713 The bundle is live and sellable right after creation.",
|
|
@@ -1156,7 +1203,7 @@ var marketingMessages = defineMessages(
|
|
|
1156
1203
|
ctaOverrideLabel: "CTA-Text \xFCberschreiben (optional)",
|
|
1157
1204
|
ctaOverrideHint: "leer lassen f\xFCr Auto-Text",
|
|
1158
1205
|
topFeatureCount: "{count} Eintr\xE4ge",
|
|
1159
|
-
featureLabelPlaceholder: "z. B.
|
|
1206
|
+
featureLabelPlaceholder: "z. B. Erweiterte Berichte",
|
|
1160
1207
|
featureStrongPlaceholder: "Highlight, z. B. bis 100",
|
|
1161
1208
|
moveUp: "Nach oben",
|
|
1162
1209
|
moveDown: "Nach unten",
|
|
@@ -1284,7 +1331,7 @@ var marketingMessages = defineMessages(
|
|
|
1284
1331
|
ctaOverrideLabel: "Override CTA text (optional)",
|
|
1285
1332
|
ctaOverrideHint: "leave empty for the auto text",
|
|
1286
1333
|
topFeatureCount: "{count} entries",
|
|
1287
|
-
featureLabelPlaceholder: "e.g.
|
|
1334
|
+
featureLabelPlaceholder: "e.g. Advanced reporting",
|
|
1288
1335
|
featureStrongPlaceholder: "Highlight, e.g. up to 100",
|
|
1289
1336
|
moveUp: "Move up",
|
|
1290
1337
|
moveDown: "Move down",
|
|
@@ -2777,7 +2824,8 @@ var shellMessages = defineMessages(
|
|
|
2777
2824
|
productionWarning: "Aktionen wirken sich sofort auf alle Mandanten aus.",
|
|
2778
2825
|
subtitle: "SuperAdmin \xB7 Plattform-Verwaltung",
|
|
2779
2826
|
roleBadge: "SUPER ADMIN",
|
|
2780
|
-
logout: "Abmelden"
|
|
2827
|
+
logout: "Abmelden",
|
|
2828
|
+
language: "Sprache"
|
|
2781
2829
|
},
|
|
2782
2830
|
drawer: {
|
|
2783
2831
|
docs: "Doku \xF6ffnen"
|
|
@@ -2845,7 +2893,8 @@ var shellMessages = defineMessages(
|
|
|
2845
2893
|
productionWarning: "Actions take effect immediately for all tenants.",
|
|
2846
2894
|
subtitle: "SuperAdmin \xB7 Platform administration",
|
|
2847
2895
|
roleBadge: "SUPER ADMIN",
|
|
2848
|
-
logout: "Sign out"
|
|
2896
|
+
logout: "Sign out",
|
|
2897
|
+
language: "Language"
|
|
2849
2898
|
},
|
|
2850
2899
|
drawer: {
|
|
2851
2900
|
docs: "Open documentation"
|
|
@@ -3113,22 +3162,69 @@ var SA_MESSAGES = {
|
|
|
3113
3162
|
de: catalogFor("de"),
|
|
3114
3163
|
en: catalogFor("en")
|
|
3115
3164
|
};
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
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
|
+
};
|
|
3119
3195
|
}
|
|
3120
3196
|
|
|
3121
3197
|
// src/vue/use-super-admin-i18n.ts
|
|
3198
|
+
var SA_LOCALE_STORAGE_KEY = "sa:locale";
|
|
3122
3199
|
var SUPER_ADMIN_I18N_KEY = /* @__PURE__ */ Symbol.for(
|
|
3123
3200
|
"@saasicat/ui-vue/SUPER_ADMIN_I18N"
|
|
3124
3201
|
);
|
|
3125
3202
|
function createSuperAdminI18n(options = {}) {
|
|
3126
|
-
const
|
|
3127
|
-
const
|
|
3128
|
-
|
|
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
|
|
3129
3207
|
);
|
|
3130
|
-
const
|
|
3131
|
-
|
|
3208
|
+
const messages = (0, import_vue.computed)(() => catalog.messagesFor(active.value));
|
|
3209
|
+
const intlLocale = (0, import_vue.computed)(() => catalog.intlLocaleFor(active.value));
|
|
3210
|
+
const writable = !(0, import_vue.isReadonly)(locale);
|
|
3211
|
+
return {
|
|
3212
|
+
locale,
|
|
3213
|
+
messages,
|
|
3214
|
+
intlLocale,
|
|
3215
|
+
switcherEnabled: (options.switcher ?? true) && writable && catalog.locales.length > 1,
|
|
3216
|
+
availableLocales: catalog.locales
|
|
3217
|
+
};
|
|
3218
|
+
}
|
|
3219
|
+
function createOwnedLocale(options, catalog) {
|
|
3220
|
+
const initial = options.locale ?? catalog.defaultLocale;
|
|
3221
|
+
if (options.persist === false) return (0, import_vue.ref)(initial);
|
|
3222
|
+
const storage = options.storage ?? defaultKvStore();
|
|
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));
|
|
3227
|
+
return locale;
|
|
3132
3228
|
}
|
|
3133
3229
|
|
|
3134
3230
|
// src/quasar/notify.ts
|
package/dist/quasar/index.d.cts
CHANGED
|
@@ -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 '../
|
|
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-
|
|
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 {
|
package/dist/quasar/index.d.ts
CHANGED
|
@@ -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 '../
|
|
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-
|
|
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 {
|
package/dist/quasar/index.js
CHANGED
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
SUPER_ADMIN_NOTIFY_KEY,
|
|
11
11
|
buildNavigationGuard,
|
|
12
12
|
createSuperAdminI18n
|
|
13
|
-
} from "../chunk-
|
|
13
|
+
} from "../chunk-247RJPU4.js";
|
|
14
14
|
import {
|
|
15
15
|
defaultHttpClient
|
|
16
|
-
} from "../chunk-
|
|
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 } from './
|
|
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
|
|
@@ -182,16 +182,62 @@ interface SuperAdminI18n {
|
|
|
182
182
|
messages: ComputedRef<SaMessages>;
|
|
183
183
|
/** BCP-47 tag for `Intl`/`toLocaleString` formatting in the active locale. */
|
|
184
184
|
intlLocale: ComputedRef<string>;
|
|
185
|
+
/**
|
|
186
|
+
* Whether the shell renders its language switcher. `false` when the app
|
|
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
|
+
*/
|
|
190
|
+
switcherEnabled: boolean;
|
|
191
|
+
/** Locales the switcher offers, in order, with their display names. */
|
|
192
|
+
availableLocales: readonly SaLocaleOption[];
|
|
185
193
|
}
|
|
186
194
|
interface SuperAdminI18nOptions {
|
|
187
195
|
/**
|
|
188
|
-
*
|
|
189
|
-
*
|
|
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).
|
|
190
200
|
*/
|
|
191
201
|
locale?: SaLocale | Ref<SaLocale>;
|
|
192
|
-
/**
|
|
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. */
|
|
193
215
|
overrides?: Partial<Record<SaLocale, SaMessagesOverrides>>;
|
|
216
|
+
/**
|
|
217
|
+
* Remembers the locale picked in the header switcher across reloads,
|
|
218
|
+
* default `true`. Ignored when `locale` is a `Ref`: the app owns that value
|
|
219
|
+
* and persists it wherever it belongs (user profile, its own store).
|
|
220
|
+
*/
|
|
221
|
+
persist?: boolean;
|
|
222
|
+
/**
|
|
223
|
+
* Storage adapter for `persist`. Defaults to `defaultKvStore()`.
|
|
224
|
+
*/
|
|
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;
|
|
232
|
+
/**
|
|
233
|
+
* Renders the language switcher in the shell chrome, default `true`. Set
|
|
234
|
+
* `false` for a deployment that ships one language. A readonly `locale`
|
|
235
|
+
* ref disables it on its own — no need to set this as well.
|
|
236
|
+
*/
|
|
237
|
+
switcher?: boolean;
|
|
194
238
|
}
|
|
239
|
+
/** `KvStore` key holding the locale the user picked in the switcher. */
|
|
240
|
+
declare const SA_LOCALE_STORAGE_KEY = "sa:locale";
|
|
195
241
|
declare const SUPER_ADMIN_I18N_KEY: InjectionKey<SuperAdminI18n>;
|
|
196
242
|
declare function createSuperAdminI18n(options?: SuperAdminI18nOptions): SuperAdminI18n;
|
|
197
243
|
/**
|
|
@@ -207,4 +253,4 @@ declare function useSuperAdminI18n(): SuperAdminI18n;
|
|
|
207
253
|
*/
|
|
208
254
|
declare function useSaMessages<K extends keyof SaMessages>(namespace: K): ComputedRef<SaMessages[K]>;
|
|
209
255
|
|
|
210
|
-
export { type ActionsMap as A, type ExtensionsMap as E, type InstallPlugin as I, type SuperAdminGuardOptions as S, type UiNotify as U, type SuperAdminBrand as a, type SuperAdminEndpoints as b, type SuperAdminLoginAdapter as c, type SuperAdminI18nOptions as d, type SuperAdminI18n as e, type ExtensionLoader as f,
|
|
256
|
+
export { type ActionsMap as A, type ExtensionsMap as E, type InstallPlugin as I, type SuperAdminGuardOptions as S, type UiNotify as U, type SuperAdminBrand as a, type SuperAdminEndpoints as b, type SuperAdminLoginAdapter as c, type SuperAdminI18nOptions as d, type SuperAdminI18n as e, type ExtensionLoader as f, SA_LOCALE_STORAGE_KEY as g, SUPER_ADMIN_ACTIONS_KEY as h, SUPER_ADMIN_BRAND_KEY as i, SUPER_ADMIN_ENDPOINTS_KEY as j, SUPER_ADMIN_EXTENSIONS_KEY as k, SUPER_ADMIN_HTTP_KEY as l, SUPER_ADMIN_I18N_KEY as m, SUPER_ADMIN_LOGIN_ADAPTER_KEY as n, SUPER_ADMIN_MANIFEST_KEY as o, SUPER_ADMIN_NOTIFY_KEY as p, type SuperAdminAuthGuardOptions as q, type SuperAdminLoginResult as r, type SuperAdminManifestGuardOptions as s, type UiNotifyKind as t, type UiNotifyOptions as u, buildNavigationGuard as v, createSuperAdminI18n as w, useSaMessages as x, useSuperAdminI18n as y };
|
|
@@ -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 } from './
|
|
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.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* App-specific branding data that the platform `AdminLayout` and other
|
|
@@ -182,16 +182,62 @@ interface SuperAdminI18n {
|
|
|
182
182
|
messages: ComputedRef<SaMessages>;
|
|
183
183
|
/** BCP-47 tag for `Intl`/`toLocaleString` formatting in the active locale. */
|
|
184
184
|
intlLocale: ComputedRef<string>;
|
|
185
|
+
/**
|
|
186
|
+
* Whether the shell renders its language switcher. `false` when the app
|
|
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
|
+
*/
|
|
190
|
+
switcherEnabled: boolean;
|
|
191
|
+
/** Locales the switcher offers, in order, with their display names. */
|
|
192
|
+
availableLocales: readonly SaLocaleOption[];
|
|
185
193
|
}
|
|
186
194
|
interface SuperAdminI18nOptions {
|
|
187
195
|
/**
|
|
188
|
-
*
|
|
189
|
-
*
|
|
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).
|
|
190
200
|
*/
|
|
191
201
|
locale?: SaLocale | Ref<SaLocale>;
|
|
192
|
-
/**
|
|
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. */
|
|
193
215
|
overrides?: Partial<Record<SaLocale, SaMessagesOverrides>>;
|
|
216
|
+
/**
|
|
217
|
+
* Remembers the locale picked in the header switcher across reloads,
|
|
218
|
+
* default `true`. Ignored when `locale` is a `Ref`: the app owns that value
|
|
219
|
+
* and persists it wherever it belongs (user profile, its own store).
|
|
220
|
+
*/
|
|
221
|
+
persist?: boolean;
|
|
222
|
+
/**
|
|
223
|
+
* Storage adapter for `persist`. Defaults to `defaultKvStore()`.
|
|
224
|
+
*/
|
|
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;
|
|
232
|
+
/**
|
|
233
|
+
* Renders the language switcher in the shell chrome, default `true`. Set
|
|
234
|
+
* `false` for a deployment that ships one language. A readonly `locale`
|
|
235
|
+
* ref disables it on its own — no need to set this as well.
|
|
236
|
+
*/
|
|
237
|
+
switcher?: boolean;
|
|
194
238
|
}
|
|
239
|
+
/** `KvStore` key holding the locale the user picked in the switcher. */
|
|
240
|
+
declare const SA_LOCALE_STORAGE_KEY = "sa:locale";
|
|
195
241
|
declare const SUPER_ADMIN_I18N_KEY: InjectionKey<SuperAdminI18n>;
|
|
196
242
|
declare function createSuperAdminI18n(options?: SuperAdminI18nOptions): SuperAdminI18n;
|
|
197
243
|
/**
|
|
@@ -207,4 +253,4 @@ declare function useSuperAdminI18n(): SuperAdminI18n;
|
|
|
207
253
|
*/
|
|
208
254
|
declare function useSaMessages<K extends keyof SaMessages>(namespace: K): ComputedRef<SaMessages[K]>;
|
|
209
255
|
|
|
210
|
-
export { type ActionsMap as A, type ExtensionsMap as E, type InstallPlugin as I, type SuperAdminGuardOptions as S, type UiNotify as U, type SuperAdminBrand as a, type SuperAdminEndpoints as b, type SuperAdminLoginAdapter as c, type SuperAdminI18nOptions as d, type SuperAdminI18n as e, type ExtensionLoader as f,
|
|
256
|
+
export { type ActionsMap as A, type ExtensionsMap as E, type InstallPlugin as I, type SuperAdminGuardOptions as S, type UiNotify as U, type SuperAdminBrand as a, type SuperAdminEndpoints as b, type SuperAdminLoginAdapter as c, type SuperAdminI18nOptions as d, type SuperAdminI18n as e, type ExtensionLoader as f, SA_LOCALE_STORAGE_KEY as g, SUPER_ADMIN_ACTIONS_KEY as h, SUPER_ADMIN_BRAND_KEY as i, SUPER_ADMIN_ENDPOINTS_KEY as j, SUPER_ADMIN_EXTENSIONS_KEY as k, SUPER_ADMIN_HTTP_KEY as l, SUPER_ADMIN_I18N_KEY as m, SUPER_ADMIN_LOGIN_ADAPTER_KEY as n, SUPER_ADMIN_MANIFEST_KEY as o, SUPER_ADMIN_NOTIFY_KEY as p, type SuperAdminAuthGuardOptions as q, type SuperAdminLoginResult as r, type SuperAdminManifestGuardOptions as s, type UiNotifyKind as t, type UiNotifyOptions as u, buildNavigationGuard as v, createSuperAdminI18n as w, useSaMessages as x, useSuperAdminI18n as y };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saasicat/ui-vue",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "Vue 3 components, resource clients and composables for the SuperAdmin UI shell. Provides boot and manifest loaders, navigation, actions and standard pages.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"src"
|
|
54
54
|
],
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@saasicat/types": "^0.
|
|
56
|
+
"@saasicat/types": "^0.17.0"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"pinia": "^2.0.0 || ^3.0.0",
|
|
@@ -75,10 +75,14 @@
|
|
|
75
75
|
"devDependencies": {
|
|
76
76
|
"@playwright/test": "^1.59.1",
|
|
77
77
|
"@types/node": "^25.6.0",
|
|
78
|
+
"@vitejs/plugin-vue": "^6.0.8",
|
|
79
|
+
"@vue/test-utils": "^2.4.11",
|
|
80
|
+
"jsdom": "^30.0.1",
|
|
78
81
|
"pinia": "^3.0.0",
|
|
79
|
-
"quasar": "^2.
|
|
82
|
+
"quasar": "^2.24.0",
|
|
80
83
|
"tsup": "^8.0.0",
|
|
81
84
|
"typescript": "^6.0.0",
|
|
85
|
+
"vitest": "^4.1.10",
|
|
82
86
|
"vue": "^3.5.0",
|
|
83
87
|
"vue-router": "^5.0.0",
|
|
84
88
|
"vue-tsc": "^3.3.3"
|
|
@@ -102,6 +106,7 @@
|
|
|
102
106
|
"typecheck": "vue-tsc --noEmit -p tsconfig.json",
|
|
103
107
|
"pretest": "pnpm run build",
|
|
104
108
|
"test": "node --test tests/**/*.test.js",
|
|
109
|
+
"test:component": "vitest run --config vitest.config.ts",
|
|
105
110
|
"test:e2e": "playwright test"
|
|
106
111
|
}
|
|
107
112
|
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// Resolves a locale to the three things the shell needs from it: the catalog to
|
|
2
|
+
// render, the tag `Intl` formats with, and the name the switcher shows.
|
|
3
|
+
//
|
|
4
|
+
// The platform ships German and English and stops there. Which of them an app
|
|
5
|
+
// offers, which languages it adds, and what wording it prefers is the app's
|
|
6
|
+
// decision — this module is the single place all three are applied.
|
|
7
|
+
|
|
8
|
+
import { mergeMessages } from './define.js';
|
|
9
|
+
import {
|
|
10
|
+
DEFAULT_SA_LOCALE,
|
|
11
|
+
SA_INTL_LOCALES,
|
|
12
|
+
SA_LOCALES,
|
|
13
|
+
SA_LOCALE_LABELS,
|
|
14
|
+
isSaBuiltinLocale,
|
|
15
|
+
type SaBuiltinLocale,
|
|
16
|
+
type SaLocale,
|
|
17
|
+
} from './locale.js';
|
|
18
|
+
import { SA_MESSAGES, type SaMessages, type SaMessagesOverrides } from './messages.js';
|
|
19
|
+
|
|
20
|
+
/** A language an app brings along, on top of the two the platform ships. */
|
|
21
|
+
export interface SaLocaleDefinition {
|
|
22
|
+
/**
|
|
23
|
+
* Name for the switcher, written in the language itself (`'Français'`) —
|
|
24
|
+
* that way the entry stays readable whatever locale is currently active.
|
|
25
|
+
*/
|
|
26
|
+
label: string;
|
|
27
|
+
/** BCP-47 tag for `Intl`/`toLocaleString`, e.g. `'fr-FR'`. */
|
|
28
|
+
intlLocale: string;
|
|
29
|
+
/**
|
|
30
|
+
* Built-in catalog that fills whatever `messages` leaves out, default
|
|
31
|
+
* `'en'`. A partial translation therefore renders — untranslated keys fall
|
|
32
|
+
* back instead of showing blanks.
|
|
33
|
+
*/
|
|
34
|
+
basedOn?: SaBuiltinLocale;
|
|
35
|
+
/** The translation. Every key is optional; see `basedOn`. */
|
|
36
|
+
messages: SaMessagesOverrides;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface SaCatalogOptions {
|
|
40
|
+
/**
|
|
41
|
+
* Locales offered in the switcher, in the order given. Default: the
|
|
42
|
+
* built-ins plus everything in `additionalLocales`. Narrow it to ship a
|
|
43
|
+
* single language; entries without a catalog are ignored.
|
|
44
|
+
*/
|
|
45
|
+
locales?: readonly SaLocale[];
|
|
46
|
+
/** Languages the app adds, keyed by locale code (`'fr'`, `'pt-BR'`, …). */
|
|
47
|
+
additionalLocales?: Readonly<Record<string, SaLocaleDefinition>>;
|
|
48
|
+
/** Per-locale wording changes layered on top of whatever catalog applies. */
|
|
49
|
+
overrides?: Readonly<Partial<Record<SaLocale, SaMessagesOverrides>>>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** One entry of the switcher. */
|
|
53
|
+
export interface SaLocaleOption {
|
|
54
|
+
code: SaLocale;
|
|
55
|
+
label: string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface SaCatalog {
|
|
59
|
+
/** Locales to offer, in switcher order. Never empty. */
|
|
60
|
+
readonly locales: readonly SaLocaleOption[];
|
|
61
|
+
/**
|
|
62
|
+
* Whether the app offers this locale. Deliberately not "can it be
|
|
63
|
+
* rendered": an app that narrowed to English must not be pushed back into
|
|
64
|
+
* German by a stored pick from before, even though German is still shipped.
|
|
65
|
+
*/
|
|
66
|
+
has(locale: SaLocale): boolean;
|
|
67
|
+
/** Locale to start from when nothing else is known. */
|
|
68
|
+
readonly defaultLocale: SaLocale;
|
|
69
|
+
messagesFor(locale: SaLocale): SaMessages;
|
|
70
|
+
intlLocaleFor(locale: SaLocale): string;
|
|
71
|
+
labelFor(locale: SaLocale): string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Builds the catalog an app runs on. Resolution is cached per locale, so
|
|
76
|
+
* switching back and forth does not re-merge the message tree.
|
|
77
|
+
*/
|
|
78
|
+
export function createSaCatalog(options: SaCatalogOptions = {}): SaCatalog {
|
|
79
|
+
const additional = options.additionalLocales ?? {};
|
|
80
|
+
const known = new Set<string>([...SA_LOCALES, ...Object.keys(additional)]);
|
|
81
|
+
|
|
82
|
+
// An app that lists an unknown code would otherwise get a switcher entry
|
|
83
|
+
// that renders nothing; dropping it here keeps the failure visible in one
|
|
84
|
+
// place instead of at every call site.
|
|
85
|
+
const requested = options.locales?.filter((code) => known.has(code));
|
|
86
|
+
const offered: readonly SaLocale[] =
|
|
87
|
+
requested && requested.length > 0 ? requested : [...SA_LOCALES, ...Object.keys(additional)];
|
|
88
|
+
|
|
89
|
+
const labelFor = (locale: SaLocale): string =>
|
|
90
|
+
additional[locale]?.label ??
|
|
91
|
+
(isSaBuiltinLocale(locale) ? SA_LOCALE_LABELS[locale] : locale);
|
|
92
|
+
|
|
93
|
+
const cache = new Map<SaLocale, SaMessages>();
|
|
94
|
+
const messagesFor = (locale: SaLocale): SaMessages => {
|
|
95
|
+
const hit = cache.get(locale);
|
|
96
|
+
if (hit) return hit;
|
|
97
|
+
const definition = additional[locale];
|
|
98
|
+
const base =
|
|
99
|
+
SA_MESSAGES[definition?.basedOn ?? (isSaBuiltinLocale(locale) ? locale : 'en')];
|
|
100
|
+
const translated = definition ? mergeMessages(base, definition.messages) : base;
|
|
101
|
+
const resolved = mergeMessages(translated, options.overrides?.[locale]);
|
|
102
|
+
cache.set(locale, resolved);
|
|
103
|
+
return resolved;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const offeredSet = new Set<string>(offered);
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
locales: offered.map((code) => ({ code, label: labelFor(code) })),
|
|
110
|
+
has: (locale) => offeredSet.has(locale),
|
|
111
|
+
// The app's first offered locale beats the platform default: an app
|
|
112
|
+
// shipping English only must not start in German.
|
|
113
|
+
defaultLocale: offered.includes(DEFAULT_SA_LOCALE) ? DEFAULT_SA_LOCALE : offered[0],
|
|
114
|
+
messagesFor,
|
|
115
|
+
intlLocaleFor: (locale) =>
|
|
116
|
+
additional[locale]?.intlLocale ??
|
|
117
|
+
(isSaBuiltinLocale(locale) ? SA_INTL_LOCALES[locale] : locale),
|
|
118
|
+
labelFor,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
// grouping and decimal separator follow the active UI locale
|
|
3
3
|
// (de → `12.345,60 €`, en → `€12,345.60`).
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
DEFAULT_SA_LOCALE,
|
|
7
|
+
SA_INTL_LOCALES,
|
|
8
|
+
type SaBuiltinLocale,
|
|
9
|
+
type SaLocale,
|
|
10
|
+
} from './locale.js';
|
|
6
11
|
|
|
7
12
|
const DEFAULT_CURRENCY = 'EUR';
|
|
8
13
|
|
|
@@ -12,7 +17,7 @@ function formatterFor(locale: SaLocale, currency: string, decimals: number): Int
|
|
|
12
17
|
const key = `${locale}:${currency}:${decimals}`;
|
|
13
18
|
let formatter = formatters.get(key);
|
|
14
19
|
if (!formatter) {
|
|
15
|
-
formatter = new Intl.NumberFormat(SA_INTL_LOCALES[locale], {
|
|
20
|
+
formatter = new Intl.NumberFormat(SA_INTL_LOCALES[locale as SaBuiltinLocale] ?? locale, {
|
|
16
21
|
style: 'currency',
|
|
17
22
|
currency,
|
|
18
23
|
minimumFractionDigits: decimals,
|