@burdenoff/fe-libs 2026.910.6 → 2026.910.7

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.
@@ -1 +1 @@
1
- {"version":3,"file":"I18nProvider.d.ts","sourceRoot":"","sources":["../../../../src/shared/providers/shell/I18nProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,MAAM,MAAM,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAWlF,MAAM,WAAW,qBAAqB;IACpC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,qBAAqB,CAAC;CAC/C;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,qBAAqB,CAAC;IACpC,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,CAAC,EAAE,CACD,GAAG,EAAE,MAAM,EACX,gBAAgB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,EAC3D,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,KACrC,MAAM,CAAC;IACZ,uDAAuD;IACvD,SAAS,EAAE,OAAO,CAAC;IACnB,gDAAgD;IAChD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAID;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;AAErF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,SAAS,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;IACrD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,mBAAmB,CAAC;IACxC;;;OAGG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,SAAS,CAAC;CAC9B;AA2FD;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,qBAAqB,GAAG,SAAS,EACvC,QAAQ,EAAE,qBAAqB,GAAG,SAAS,GAC1C,qBAAqB,CAsBvB;AAED,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,aAAoB,EACpB,YAAY,EAAE,kBAAyC,EACvD,UAA+B,EAC/B,SAAS,EACT,iBAAiB,EACjB,wBAA+B,EAC/B,gBAAgB,GACjB,EAAE,iBAAiB,2CA+MnB;AAED,wBAAgB,OAAO,qBAMtB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE9D"}
1
+ {"version":3,"file":"I18nProvider.d.ts","sourceRoot":"","sources":["../../../../src/shared/providers/shell/I18nProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAGf,MAAM,MAAM,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAWlF,MAAM,WAAW,qBAAqB;IACpC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,qBAAqB,CAAC;CAC/C;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,qBAAqB,CAAC;IACpC,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,CAAC,EAAE,CACD,GAAG,EAAE,MAAM,EACX,gBAAgB,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,EAC3D,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,KACrC,MAAM,CAAC;IACZ,uDAAuD;IACvD,SAAS,EAAE,OAAO,CAAC;IACnB,gDAAgD;IAChD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAID;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;AAErF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,SAAS,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;IACrD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,mBAAmB,CAAC;IACxC;;;OAGG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,SAAS,CAAC;CAC9B;AA2FD;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,qBAAqB,GAAG,SAAS,EACvC,QAAQ,EAAE,qBAAqB,GAAG,SAAS,GAC1C,qBAAqB,CAsBvB;AAED,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,aAAoB,EACpB,YAAY,EAAE,kBAAyC,EACvD,UAA+B,EAC/B,SAAS,EACT,iBAAiB,EACjB,wBAA+B,EAC/B,gBAAgB,GACjB,EAAE,iBAAiB,2CAwMnB;AAED,wBAAgB,OAAO,qBAMtB;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE9D"}
@@ -1,7 +1,8 @@
1
- import { createContext as e, use as t, useCallback as n, useEffect as r, useMemo as i, useRef as a, useState as o } from "react";
2
- import { Fragment as s, jsx as c } from "react/jsx-runtime";
1
+ import { interpolate as e } from "./interpolate.js";
2
+ import { createContext as t, use as n, useCallback as r, useEffect as i, useMemo as a, useRef as o, useState as s } from "react";
3
+ import { Fragment as c, jsx as l } from "react/jsx-runtime";
3
4
  //#region src/shared/providers/shell/I18nProvider.tsx
4
- var l = e(null), u = {
5
+ var u = t(null), d = {
5
6
  en: {},
6
7
  es: {},
7
8
  fr: {},
@@ -11,7 +12,7 @@ var l = e(null), u = {
11
12
  ta: {},
12
13
  hi: {},
13
14
  ar: {}
14
- }, d = {
15
+ }, f = {
15
16
  attempted: /* @__PURE__ */ new Set(),
16
17
  translations: {},
17
18
  version: 0,
@@ -19,7 +20,7 @@ var l = e(null), u = {
19
20
  this.attempted.clear(), this.translations = {}, this.version++;
20
21
  }
21
22
  };
22
- function f(e, t, n) {
23
+ function p(e, t, n) {
23
24
  if (typeof window > "u") return n;
24
25
  if (e) {
25
26
  let t = localStorage.getItem(`bf-p-${e}-locale`);
@@ -27,17 +28,17 @@ function f(e, t, n) {
27
28
  }
28
29
  return localStorage.getItem(t) || n;
29
30
  }
30
- function p(e, t) {
31
+ function m(e, t) {
31
32
  if (!e) return;
32
33
  let n = t.split("."), r = e;
33
34
  for (let e of n) if (typeof r == "object" && r && e in r) r = r[e];
34
35
  else return;
35
36
  return typeof r == "string" ? r : void 0;
36
37
  }
37
- function m(e) {
38
+ function h(e) {
38
39
  return typeof e == "object" && !!e;
39
40
  }
40
- function h(e, t) {
41
+ function g(e, t) {
41
42
  if (!e && !t) return {};
42
43
  if (!e) return { ...t ?? {} };
43
44
  if (!t) return { ...e };
@@ -48,103 +49,103 @@ function h(e, t) {
48
49
  n[e] = r;
49
50
  continue;
50
51
  }
51
- n[e] = h(m(t) ? t : void 0, r);
52
+ n[e] = g(h(t) ? t : void 0, r);
52
53
  }
53
54
  return n;
54
55
  }
55
- function g({ children: e, defaultLocale: t = "en", translations: m = u, storageKey: g = "burdenoff-locale", profileId: _, fetchTranslations: v, showChildrenWhileLoading: y = !0, loadingComponent: b }) {
56
- let [x, S] = o(() => f(_, g, t)), [C, w] = o({}), [T, E] = o(!!v), [D, O] = o(null), k = a(/* @__PURE__ */ new Set()), A = a(d.version), j = i(() => {
57
- let e = { ...m };
58
- for (let [t, n] of Object.entries(C)) if (n && Object.keys(n).length > 0) {
56
+ function _({ children: t, defaultLocale: n = "en", translations: h = d, storageKey: _ = "burdenoff-locale", profileId: v, fetchTranslations: y, showChildrenWhileLoading: b = !0, loadingComponent: x }) {
57
+ let [S, C] = s(() => p(v, _, n)), [w, T] = s({}), [E, D] = s(!!y), [O, k] = s(null), A = o(/* @__PURE__ */ new Set()), j = o(f.version), M = a(() => {
58
+ let e = { ...h };
59
+ for (let [t, n] of Object.entries(w)) if (n && Object.keys(n).length > 0) {
59
60
  let r = t;
60
- e[r] = h(m[r], n);
61
+ e[r] = g(h[r], n);
61
62
  }
62
63
  return e;
63
- }, [m, C]), M = n(async (e) => {
64
- if (v) {
65
- if (A.current !== d.version && (k.current.clear(), A.current = d.version), d.attempted.has(e)) {
66
- let t = d.translations[e];
67
- t && Object.keys(t).length > 0 && w((n) => !n[e] || Object.keys(n[e]).length === 0 ? {
64
+ }, [h, w]), N = r(async (e) => {
65
+ if (y) {
66
+ if (j.current !== f.version && (A.current.clear(), j.current = f.version), f.attempted.has(e)) {
67
+ let t = f.translations[e];
68
+ t && Object.keys(t).length > 0 && T((n) => !n[e] || Object.keys(n[e]).length === 0 ? {
68
69
  ...n,
69
70
  [e]: t
70
71
  } : n);
71
72
  return;
72
73
  }
73
- if (!k.current.has(e)) {
74
- k.current.add(e), E(!0), O(null);
74
+ if (!A.current.has(e)) {
75
+ A.current.add(e), D(!0), k(null);
75
76
  try {
76
- let t = await v(e);
77
- t && Object.keys(t).length > 0 && (d.attempted.add(e), d.translations[e] = t), w((n) => ({
77
+ let t = await y(e);
78
+ t && Object.keys(t).length > 0 && (f.attempted.add(e), f.translations[e] = t), T((n) => ({
78
79
  ...n,
79
80
  [e]: t
80
81
  }));
81
82
  } catch (t) {
82
- console.error(`[I18nProvider] Failed to fetch translations for ${e}:`, t), O(t instanceof Error ? t.message : "Failed to fetch translations");
83
+ console.error(`[I18nProvider] Failed to fetch translations for ${e}:`, t), k(t instanceof Error ? t.message : "Failed to fetch translations");
83
84
  } finally {
84
- k.current.delete(e), E(!1);
85
+ A.current.delete(e), D(!1);
85
86
  }
86
87
  }
87
88
  }
88
- }, [v]);
89
- r(() => {
90
- v && (d.attempted.has(x) && d.translations[x] && Object.keys(d.translations[x]).length > 0 || M(x));
89
+ }, [y]);
90
+ i(() => {
91
+ y && (f.attempted.has(S) && f.translations[S] && Object.keys(f.translations[S]).length > 0 || N(S));
91
92
  }, [
92
- v,
93
- x,
94
- M
95
- ]), r(() => {
96
- let e = f(_, g, t);
97
- S(e), document.documentElement.setAttribute("lang", e);
93
+ y,
94
+ S,
95
+ N
96
+ ]), i(() => {
97
+ let e = p(v, _, n);
98
+ C(e), document.documentElement.setAttribute("lang", e);
98
99
  }, [
100
+ v,
99
101
  _,
100
- g,
101
- t
102
+ n
102
103
  ]);
103
- let N = n((e) => {
104
- S(e), localStorage.setItem(g, e), _ && localStorage.setItem(`bf-p-${_}-locale`, e), document.documentElement.setAttribute("lang", e);
105
- }, [g, _]), P = n((e, n, r) => {
106
- let i, a;
107
- if (typeof n == "string") i = n, a = r;
108
- else if (n && typeof n == "object") {
109
- let { defaultValue: e, ...t } = n;
110
- typeof e == "string" ? i = e : typeof e == "number" && (i = String(e)), a = t;
104
+ let P = r((e) => {
105
+ C(e), localStorage.setItem(_, e), v && localStorage.setItem(`bf-p-${v}-locale`, e), document.documentElement.setAttribute("lang", e);
106
+ }, [_, v]), F = r((t, r, i) => {
107
+ let a, o;
108
+ if (typeof r == "string") a = r, o = i;
109
+ else if (r && typeof r == "object") {
110
+ let { defaultValue: e, ...t } = r;
111
+ typeof e == "string" ? a = e : typeof e == "number" && (a = String(e)), o = t;
111
112
  }
112
- let o = p(j[x], e) ?? (x === t ? void 0 : p(j[t], e)) ?? (t === "en" ? void 0 : p(j.en, e)) ?? i ?? e;
113
- return a ? Object.entries(a).reduce((e, [t, n]) => e.replaceAll(`{{${t}}}`, String(n)), o) : o;
113
+ let s = m(M[S], t) ?? (S === n ? void 0 : m(M[n], t)) ?? (n === "en" ? void 0 : m(M.en, t)) ?? a ?? t;
114
+ return o ? e(s, o) : s;
114
115
  }, [
115
- x,
116
- j,
117
- t
118
- ]), F = i(() => ({
119
- locale: x,
120
- translations: j[x] || {},
121
- setLocale: N,
122
- t: P,
123
- isLoading: T,
124
- error: D
116
+ S,
117
+ M,
118
+ n
119
+ ]), I = a(() => ({
120
+ locale: S,
121
+ translations: M[S] || {},
122
+ setLocale: P,
123
+ t: F,
124
+ isLoading: E,
125
+ error: O
125
126
  }), [
126
- x,
127
- j,
128
- N,
127
+ S,
128
+ M,
129
129
  P,
130
- T,
131
- D
130
+ F,
131
+ E,
132
+ O
132
133
  ]);
133
- return T && !y && b ? /* @__PURE__ */ c(s, { children: b }) : /* @__PURE__ */ c(l.Provider, {
134
- value: F,
135
- children: e
134
+ return E && !b && x ? /* @__PURE__ */ l(c, { children: x }) : /* @__PURE__ */ l(u.Provider, {
135
+ value: I,
136
+ children: t
136
137
  });
137
138
  }
138
- function _() {
139
- let e = t(l);
139
+ function v() {
140
+ let e = n(u);
140
141
  if (!e) throw Error("useI18n must be used within an I18nProvider");
141
142
  return e;
142
143
  }
143
- function v() {
144
- d.clear();
144
+ function y() {
145
+ f.clear();
145
146
  }
146
- function y(e) {
147
- return d.attempted.has(e);
147
+ function b(e) {
148
+ return f.attempted.has(e);
148
149
  }
149
150
  //#endregion
150
- export { g as I18nProvider, v as clearTranslationCache, y as isTranslationAttempted, h as mergeTranslationDictionaries, _ as useI18n };
151
+ export { _ as I18nProvider, y as clearTranslationCache, b as isTranslationAttempted, g as mergeTranslationDictionaries, v as useI18n };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Substitute `{{name}}` and `{name}` placeholders in one left-to-right pass.
3
+ *
4
+ * WHY BOTH SPELLINGS
5
+ * `{{name}}` is the house style, but a large amount of already-SEEDED copy uses
6
+ * the single brace: 174 rows in the FluidGrids production dictionary alone (25
7
+ * of them `dashboard.*`) against 512 rows using `{{name}}`. Those strings were
8
+ * authored in MFEs whose local fallback helper interpolates single braces, so
9
+ * they looked correct until the key reached the dictionary and `t()` began
10
+ * returning the stored value instead of the local fallback — at which point the
11
+ * FluidGrids dashboard rendered `{memberLabel} across {count} {workspaceLabel}`
12
+ * verbatim to users (BOFF-7245). Accepting both spellings fixes every such row
13
+ * in every product with no re-seed.
14
+ *
15
+ * WHY ONE REGEX PASS AND NOT CHAINED `replaceAll`
16
+ * Chained replacement re-scans text it has already written. A parameter whose
17
+ * VALUE happens to contain braces — a workspace literally named "{count}", a
18
+ * translated string carrying a placeholder — would be substituted a second time
19
+ * on a later iteration. Matching once and looking each name up leaves inserted
20
+ * values untouched, and it is also why a repeated placeholder works: every
21
+ * occurrence is matched by the same pass, which the old `replace` (first match
22
+ * only) got wrong for "…{{observed}}{{unit}} · threshold {{threshold}}{{unit}}".
23
+ *
24
+ * An unknown name is left exactly as written rather than blanked, so a missing
25
+ * parameter shows up as `{name}` in review instead of silently vanishing, and
26
+ * braces that are not placeholders at all — `{}` in a code sample, `{0}` in an
27
+ * index template — survive untouched.
28
+ */
29
+ export declare function interpolate(template: string, params: Record<string, string | number>): string;
30
+ //# sourceMappingURL=interpolate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interpolate.d.ts","sourceRoot":"","sources":["../../../../src/shared/providers/shell/interpolate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM,CAU7F"}
@@ -0,0 +1,11 @@
1
+ //#region src/shared/providers/shell/interpolate.ts
2
+ function e(e, t) {
3
+ return e.replace(/\{\{(\w+)\}\}|\{(\w+)\}/g, (e, n, r) => {
4
+ let i = n ?? r;
5
+ if (i === void 0) return e;
6
+ let a = t[i];
7
+ return a === void 0 ? e : String(a);
8
+ });
9
+ }
10
+ //#endregion
11
+ export { e as interpolate };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/fe-libs",
3
- "version": "2026.910.6",
3
+ "version": "2026.910.7",
4
4
  "description": "Burdenoff frontend primitives and domain libraries",
5
5
  "type": "module",
6
6
  "bin": {
@@ -307,7 +307,7 @@
307
307
  "format": "prettier --config shared/config/prettier.config.mjs --write \"src/**/*.{ts,tsx}\" \"!src/config/*.config.ts\"",
308
308
  "type:check": "bash scripts/build-limits.sh tsc --noEmit",
309
309
  "test:package-css-exports": "node scripts/validate-package-css-exports.mjs",
310
- "test": "bun test scripts/graphql-schema-drift/__tests__ scripts/a11y-audit/__tests__ src/credentials src/storage src/shared/assistant src/shared/components src/shared/graphql/links/sse-link.test.ts src/shared/config/gatewayUrls.test.ts src/shared/config/authBridgeUrls.test.ts src/shared/config/gatewayFallback.test.ts src/shared/utils/gatewayFetchRewrite.test.ts src/shared/utils/authCookie.test.ts src/shared/providers/AppShellProvider.test.ts src/shared/events/sinks/RybbitSink.test.ts src/shell-native src/shared/native src/chrome/__tests__ src/ui/__tests__",
310
+ "test": "bun test scripts/graphql-schema-drift/__tests__ scripts/a11y-audit/__tests__ src/credentials src/storage src/shared/assistant src/shared/components src/shared/graphql/links/sse-link.test.ts src/shared/config/gatewayUrls.test.ts src/shared/config/authBridgeUrls.test.ts src/shared/config/gatewayFallback.test.ts src/shared/utils/gatewayFetchRewrite.test.ts src/shared/utils/authCookie.test.ts src/shared/providers/AppShellProvider.test.ts src/shared/providers/shell/interpolate.test.ts src/shared/events/sinks/RybbitSink.test.ts src/shell-native src/shared/native src/chrome/__tests__ src/ui/__tests__",
311
311
  "sanity": "bash scripts/build-limits.sh --gate bash -c 'bun run lint:sanity && bun run format && bun run type:check && bun run test && bun run build'",
312
312
  "switch:status": "bun scripts/deps-mode.ts status",
313
313
  "switch:remote": "bun scripts/deps-mode.ts remote",