@nifrajs/web-solid 5.1.0 → 5.2.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/dist/i18n.d.ts CHANGED
@@ -3,12 +3,15 @@
3
3
  * `Formatter` (a `createMemo`, so switching locale rebuilds it) and provides it; `useT()` reads it.
4
4
  * Both `locale` + `messages` are serializable, so a loader returns them, the page renders with the
5
5
  * negotiated catalog on the server, and the client rebuilds the same formatter on hydrate (no
6
- * mismatch). Imports only `solid-js` + `@nifrajs/i18n`; no JSX (`createComponent`).
6
+ * mismatch). In an app that registers its locale routing (`i18n` in `backend/framework.ts`), `locale`
7
+ * defaults to the page's and `useLocale()` names it. No JSX (`createComponent`).
7
8
  */
8
9
  import { type Formatter, type FormatterOptions, type MessageKey, type RegisteredMessages, type Translation } from "@nifrajs/i18n";
9
- import { type JSX } from "solid-js";
10
+ import { type Accessor, type JSX } from "solid-js";
10
11
  export interface I18nProviderProps extends FormatterOptions {
11
- readonly locale: string;
12
+ /** The locale to format in. Default: the page's locale tag, in an app that registers its locale
13
+ * routing. */
14
+ readonly locale?: string;
12
15
  /** The catalog for `locale`, checked against the registered catalog type when one is declared. */
13
16
  readonly messages: Translation;
14
17
  readonly children?: JSX.Element;
@@ -20,6 +23,12 @@ export declare function I18nProvider(props: I18nProviderProps): JSX.Element;
20
23
  /** Read the current {@link Formatter} (`{ locale, t, get, n, d }`). Throws if no `<I18nProvider>` is above.
21
24
  * nifra switches locale by re-navigating, which re-runs the consuming component with the new catalog. */
22
25
  export declare function useT(): Formatter;
26
+ /**
27
+ * The page's locale key (`ur`, the URL segment), in an app that registers its locale routing (`i18n`
28
+ * in `backend/framework.ts`): from the request on the server, from the URL after each navigation.
29
+ * Without one, the nearest `<I18nProvider>`'s locale; with neither, reading it throws.
30
+ */
31
+ export declare function useLocale(): Accessor<string>;
23
32
  /** Tag handlers for {@link rich}, by tag name: each receives its tag's content as one node. */
24
33
  export type RichTags = Readonly<Record<string, (content: JSX.Element) => JSX.Element>>;
25
34
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,kBAAkB,EACvB,KAAK,WAAW,EACjB,MAAM,eAAe,CAAA;AAEtB,OAAO,EAKL,KAAK,GAAG,EAET,MAAM,UAAU,CAAA;AAKjB,MAAM,WAAW,iBAAkB,SAAQ,gBAAgB;IACzD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,kGAAkG;IAClG,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAA;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;CAChC;AAED;;sDAEsD;AACtD,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,GAAG,CAAC,OAAO,CAelE;AAED;yGACyG;AACzG,wBAAgB,IAAI,IAAI,SAAS,CAMhC;AAED,+FAA+F;AAC/F,MAAM,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC,CAAA;AAStF;;;;;;GAMG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,MAAM,GAAG,kBAAkB,EACxD,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,EACvB,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC,EAClB,IAAI,CAAC,EAAE,QAAQ,EACf,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACvC,GAAG,CAAC,OAAO,CAEb"}
1
+ {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,kBAAkB,EACvB,KAAK,WAAW,EACjB,MAAM,eAAe,CAAA;AAGtB,OAAO,EACL,KAAK,QAAQ,EAIb,KAAK,GAAG,EAET,MAAM,UAAU,CAAA;AAMjB,MAAM,WAAW,iBAAkB,SAAQ,gBAAgB;IACzD;kBACc;IACd,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,kGAAkG;IAClG,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAA;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;CAChC;AAED;;sDAEsD;AACtD,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,GAAG,CAAC,OAAO,CAsBlE;AAED;yGACyG;AACzG,wBAAgB,IAAI,IAAI,SAAS,CAMhC;AAED;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,QAAQ,CAAC,MAAM,CAAC,CAY5C;AAED,+FAA+F;AAC/F,MAAM,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,KAAK,GAAG,CAAC,OAAO,CAAC,CAAC,CAAA;AAStF;;;;;;GAMG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,MAAM,GAAG,kBAAkB,EACxD,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,EACvB,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC,EAClB,IAAI,CAAC,EAAE,QAAQ,EACf,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACvC,GAAG,CAAC,OAAO,CAEb"}
package/dist/i18n.js CHANGED
@@ -3,23 +3,33 @@
3
3
  * `Formatter` (a `createMemo`, so switching locale rebuilds it) and provides it; `useT()` reads it.
4
4
  * Both `locale` + `messages` are serializable, so a loader returns them, the page renders with the
5
5
  * negotiated catalog on the server, and the client rebuilds the same formatter on hydrate (no
6
- * mismatch). Imports only `solid-js` + `@nifrajs/i18n`; no JSX (`createComponent`).
6
+ * mismatch). In an app that registers its locale routing (`i18n` in `backend/framework.ts`), `locale`
7
+ * defaults to the page's and `useLocale()` names it. No JSX (`createComponent`).
7
8
  */
8
9
  import { createFormatter, } from "@nifrajs/i18n";
9
10
  import { renderRich } from "@nifrajs/i18n/rich";
11
+ import { localeOfProps } from "@nifrajs/web/client";
10
12
  import { createComponent, createContext, createMemo, useContext, } from "solid-js";
11
13
  import { Dynamic } from "solid-js/web";
14
+ import { RenderPropsContext } from "./router.js";
12
15
  const I18nContext = createContext();
13
16
  /** Provide a {@link Formatter} (built from `locale` + `messages`, with the optional `fallback`,
14
17
  * `onMissing`, `timeZone` and `numberingSystem` of `createFormatter`) to the subtree. Memoized
15
18
  * on those props, so switching locale rebuilds it. */
16
19
  export function I18nProvider(props) {
17
- const formatter = createMemo(() => createFormatter(props.locale, props.messages, {
18
- fallback: props.fallback,
19
- onMissing: props.onMissing,
20
- timeZone: props.timeZone,
21
- numberingSystem: props.numberingSystem,
22
- }));
20
+ const renderProps = useContext(RenderPropsContext);
21
+ const formatter = createMemo(() => {
22
+ const locale = props.locale ?? localeOfProps(renderProps)?.lang;
23
+ if (locale === undefined) {
24
+ throw new Error("[nifra/web-solid] <I18nProvider> needs a `locale`, or an app that registers its locale routing (export `i18n` from backend/framework.ts)");
25
+ }
26
+ return createFormatter(locale, props.messages, {
27
+ fallback: props.fallback,
28
+ onMissing: props.onMissing,
29
+ timeZone: props.timeZone,
30
+ numberingSystem: props.numberingSystem,
31
+ });
32
+ });
23
33
  return createComponent(I18nContext.Provider, {
24
34
  value: formatter,
25
35
  get children() {
@@ -36,6 +46,22 @@ export function useT() {
36
46
  }
37
47
  return formatter();
38
48
  }
49
+ /**
50
+ * The page's locale key (`ur`, the URL segment), in an app that registers its locale routing (`i18n`
51
+ * in `backend/framework.ts`): from the request on the server, from the URL after each navigation.
52
+ * Without one, the nearest `<I18nProvider>`'s locale; with neither, reading it throws.
53
+ */
54
+ export function useLocale() {
55
+ const renderProps = useContext(RenderPropsContext);
56
+ const formatter = useContext(I18nContext);
57
+ return createMemo(() => {
58
+ const locale = localeOfProps(renderProps)?.key ?? formatter?.().locale;
59
+ if (locale === undefined) {
60
+ throw new Error("[nifra/web-solid] useLocale() needs an app that registers its locale routing (export `i18n` from backend/framework.ts), or an <I18nProvider> above it");
61
+ }
62
+ return locale;
63
+ });
64
+ }
39
65
  const join = (chunks) => chunks.length === 0 ? undefined : chunks.length === 1 ? chunks[0] : [...chunks];
40
66
  const SOLID_RICH = {
41
67
  join,
package/dist/i18n.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.js","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EACL,eAAe,GAMhB,MAAM,eAAe,CAAA;AACtB,OAAO,EAAsC,UAAU,EAAE,MAAM,oBAAoB,CAAA;AACnF,OAAO,EAEL,eAAe,EACf,aAAa,EACb,UAAU,EAEV,UAAU,GACX,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,MAAM,WAAW,GAAG,aAAa,EAAuB,CAAA;AASxD;;sDAEsD;AACtD,MAAM,UAAU,YAAY,CAAC,KAAwB;IACnD,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE,CAChC,eAAe,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,EAAE;QAC5C,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,eAAe,EAAE,KAAK,CAAC,eAAe;KACvC,CAAC,CACH,CAAA;IACD,OAAO,eAAe,CAAC,WAAW,CAAC,QAAQ,EAAE;QAC3C,KAAK,EAAE,SAAS;QAChB,IAAI,QAAQ;YACV,OAAO,KAAK,CAAC,QAAQ,CAAA;QACvB,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAED;yGACyG;AACzG,MAAM,UAAU,IAAI;IAClB,MAAM,SAAS,GAAG,UAAU,CAAC,WAAW,CAAC,CAAA;IACzC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAA;IACnF,CAAC;IACD,OAAO,SAAS,EAAE,CAAA;AACpB,CAAC;AAKD,MAAM,IAAI,GAAG,CAAC,MAA+B,EAAe,EAAE,CAC5D,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAA;AACjF,MAAM,UAAU,GAA8B;IAC5C,IAAI;IACJ,SAAS,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;CAC/D,CAAA;AAED;;;;;;GAMG;AACH,MAAM,UAAU,IAAI,CAClB,SAAuB,EACvB,GAAkB,EAClB,IAAe,EACf,IAAwC;IAExC,OAAO,UAAU,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;AAC3D,CAAC"}
1
+ {"version":3,"file":"i18n.js","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EACL,eAAe,GAMhB,MAAM,eAAe,CAAA;AACtB,OAAO,EAAsC,UAAU,EAAE,MAAM,oBAAoB,CAAA;AACnF,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAEL,eAAe,EACf,aAAa,EACb,UAAU,EAEV,UAAU,GACX,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAEhD,MAAM,WAAW,GAAG,aAAa,EAAuB,CAAA;AAWxD;;sDAEsD;AACtD,MAAM,UAAU,YAAY,CAAC,KAAwB;IACnD,MAAM,WAAW,GAAG,UAAU,CAAC,kBAAkB,CAAC,CAAA;IAClD,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;QAChC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,aAAa,CAAC,WAAW,CAAC,EAAE,IAAI,CAAA;QAC/D,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CACb,0IAA0I,CAC3I,CAAA;QACH,CAAC;QACD,OAAO,eAAe,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,EAAE;YAC7C,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,eAAe,EAAE,KAAK,CAAC,eAAe;SACvC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IACF,OAAO,eAAe,CAAC,WAAW,CAAC,QAAQ,EAAE;QAC3C,KAAK,EAAE,SAAS;QAChB,IAAI,QAAQ;YACV,OAAO,KAAK,CAAC,QAAQ,CAAA;QACvB,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAED;yGACyG;AACzG,MAAM,UAAU,IAAI;IAClB,MAAM,SAAS,GAAG,UAAU,CAAC,WAAW,CAAC,CAAA;IACzC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAA;IACnF,CAAC;IACD,OAAO,SAAS,EAAE,CAAA;AACpB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS;IACvB,MAAM,WAAW,GAAG,UAAU,CAAC,kBAAkB,CAAC,CAAA;IAClD,MAAM,SAAS,GAAG,UAAU,CAAC,WAAW,CAAC,CAAA;IACzC,OAAO,UAAU,CAAC,GAAG,EAAE;QACrB,MAAM,MAAM,GAAG,aAAa,CAAC,WAAW,CAAC,EAAE,GAAG,IAAI,SAAS,EAAE,EAAE,CAAC,MAAM,CAAA;QACtE,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CACb,uJAAuJ,CACxJ,CAAA;QACH,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC,CAAC,CAAA;AACJ,CAAC;AAKD,MAAM,IAAI,GAAG,CAAC,MAA+B,EAAe,EAAE,CAC5D,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAA;AACjF,MAAM,UAAU,GAA8B;IAC5C,IAAI;IACJ,SAAS,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;CAC/D,CAAA;AAED;;;;;;GAMG;AACH,MAAM,UAAU,IAAI,CAClB,SAAuB,EACvB,GAAkB,EAClB,IAAe,EACf,IAAwC;IAExC,OAAO,UAAU,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;AAC3D,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,KAAK,CAAA;AAGpC;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,KAAK,GAAG,KAAK,GAAG,SAAS,CA0BjE"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,KAAK,CAAA;AAGpC;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,KAAK,GAAG,KAAK,GAAG,SAAS,CA0BjE"}
package/dist/plugin.js CHANGED
@@ -6,7 +6,7 @@
6
6
  import { transformAsync } from "@babel/core";
7
7
  // @ts-expect-error - no type declarations published
8
8
  import presetTypeScript from "@babel/preset-typescript";
9
- import { devServerCompile, normalizeFilePath, rewriteSsrImports } from "@nifrajs/web/plugins/kit";
9
+ import { devServerCompile, normalizeFilePath, readSource, rewriteSsrImports, } from "@nifrajs/web/plugins/kit";
10
10
  // @ts-expect-error - no type declarations published
11
11
  import presetSolid from "babel-preset-solid";
12
12
  import solidRefreshBunHot, { SOLID_HOT_MODULE } from "./refresh-babel.js";
@@ -28,7 +28,7 @@ export function solidBunPlugin(generate) {
28
28
  // cache); strip it before reading the file off disk.
29
29
  build.onLoad({ filter: /\.tsx(\?|$)/ }, async (args) => {
30
30
  const path = normalizeFilePath(args.path);
31
- const source = await Bun.file(path).text();
31
+ const source = await readSource(build, path);
32
32
  const result = await transformAsync(source, {
33
33
  filename: path,
34
34
  // babel applies presets last→first: strip TS first, then Solid transforms JSX.
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,oDAAoD;AACpD,OAAO,gBAAgB,MAAM,0BAA0B,CAAA;AACvD,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,UAAU,EACV,iBAAiB,GAClB,MAAM,0BAA0B,CAAA;AACjC,oDAAoD;AACpD,OAAO,WAAW,MAAM,oBAAoB,CAAA;AAE5C,OAAO,kBAAkB,EAAE,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAEzE;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,QAAuB;IACpD,OAAO;QACL,IAAI,EAAE,eAAe,QAAQ,EAAE;QAC/B,KAAK,CAAC,KAAK;YACT,MAAM,OAAO,GACX,QAAQ,KAAK,KAAK,IAAI,gBAAgB,EAAE,CAAC,CAAC,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;YACjF,0FAA0F;YAC1F,qDAAqD;YACrD,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;gBACrD,MAAM,IAAI,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;gBACzC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;gBAC5C,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE;oBAC1C,QAAQ,EAAE,IAAI;oBACd,+EAA+E;oBAC/E,OAAO,EAAE;wBACP,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;wBAC7C,CAAC,gBAAgB,EAAE,EAAE,qBAAqB,EAAE,IAAI,EAAE,CAAC;qBACpD;oBACD,GAAG,CAAC,OAAO,KAAK,SAAS;wBACvB,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,OAAO,CAAC,KAAK,EAAE,EAAE,eAAe,CAAC,EAAE,kBAAkB,CAAC,EAAE;wBAC7E,CAAC,CAAC,EAAE,CAAC;iBACR,CAAC,CAAA;gBACF,OAAO,EAAE,QAAQ,EAAE,iBAAiB,CAAC,MAAM,EAAE,IAAI,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAA;YAC1F,CAAC,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,eAAe,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAW,CAAA;AAE/D;;;;;;;;;;;;;;GAcG;AACH,SAAS,iBAAiB,CAAC,KAAwC;IAGjE,MAAM,OAAO,GAAG,GAAG,CAAC,WAAW,CAAC,eAAe,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACjE,KAAK,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,iBAAiB,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAA;IACzE,sGAAsG;IACtG,MAAM,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,eAAe,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,CAAA;IAClG,KAAK,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,IAAI,MAAM,CAAC,IAAI,gBAAgB,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAA;IAC1F,IAAI,KAAmC,CAAA;IACvC,OAAO;QACL,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,qBAAqB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;KAC9E,CAAA;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nifrajs/web-solid",
3
- "version": "5.1.0",
3
+ "version": "5.2.0",
4
4
  "description": "Solid render adapter for @nifrajs/web - SSR + hydration, with the Solid Babel build plugin (@nifrajs/web-solid/plugin).",
5
5
  "keywords": [
6
6
  "bun",
@@ -108,7 +108,8 @@
108
108
  },
109
109
  "files": [
110
110
  "dist",
111
- "src"
111
+ "src",
112
+ "CHANGELOG.md"
112
113
  ],
113
114
  "sideEffects": false,
114
115
  "scripts": {
@@ -121,10 +122,10 @@
121
122
  "dependencies": {
122
123
  "@babel/core": "^7.26.0",
123
124
  "@babel/preset-typescript": "^7.26.0",
124
- "@nifrajs/core": "5.1.0",
125
- "@nifrajs/i18n": "5.1.0",
126
- "@nifrajs/image": "5.1.0",
127
- "@nifrajs/web": "5.1.0",
125
+ "@nifrajs/core": "5.2.0",
126
+ "@nifrajs/i18n": "5.2.0",
127
+ "@nifrajs/image": "5.2.0",
128
+ "@nifrajs/web": "5.2.0",
128
129
  "babel-preset-solid": "^1.9.3",
129
130
  "solid-refresh": "^0.7.8"
130
131
  },
package/src/i18n.ts CHANGED
@@ -3,7 +3,8 @@
3
3
  * `Formatter` (a `createMemo`, so switching locale rebuilds it) and provides it; `useT()` reads it.
4
4
  * Both `locale` + `messages` are serializable, so a loader returns them, the page renders with the
5
5
  * negotiated catalog on the server, and the client rebuilds the same formatter on hydrate (no
6
- * mismatch). Imports only `solid-js` + `@nifrajs/i18n`; no JSX (`createComponent`).
6
+ * mismatch). In an app that registers its locale routing (`i18n` in `backend/framework.ts`), `locale`
7
+ * defaults to the page's and `useLocale()` names it. No JSX (`createComponent`).
7
8
  */
8
9
  import {
9
10
  createFormatter,
@@ -14,6 +15,7 @@ import {
14
15
  type Translation,
15
16
  } from "@nifrajs/i18n"
16
17
  import { type RichChunks, type RichRenderer, renderRich } from "@nifrajs/i18n/rich"
18
+ import { localeOfProps } from "@nifrajs/web/client"
17
19
  import {
18
20
  type Accessor,
19
21
  createComponent,
@@ -23,11 +25,14 @@ import {
23
25
  useContext,
24
26
  } from "solid-js"
25
27
  import { Dynamic } from "solid-js/web"
28
+ import { RenderPropsContext } from "./router.ts"
26
29
 
27
30
  const I18nContext = createContext<Accessor<Formatter>>()
28
31
 
29
32
  export interface I18nProviderProps extends FormatterOptions {
30
- readonly locale: string
33
+ /** The locale to format in. Default: the page's locale tag, in an app that registers its locale
34
+ * routing. */
35
+ readonly locale?: string
31
36
  /** The catalog for `locale`, checked against the registered catalog type when one is declared. */
32
37
  readonly messages: Translation
33
38
  readonly children?: JSX.Element
@@ -37,14 +42,21 @@ export interface I18nProviderProps extends FormatterOptions {
37
42
  * `onMissing`, `timeZone` and `numberingSystem` of `createFormatter`) to the subtree. Memoized
38
43
  * on those props, so switching locale rebuilds it. */
39
44
  export function I18nProvider(props: I18nProviderProps): JSX.Element {
40
- const formatter = createMemo(() =>
41
- createFormatter(props.locale, props.messages, {
45
+ const renderProps = useContext(RenderPropsContext)
46
+ const formatter = createMemo(() => {
47
+ const locale = props.locale ?? localeOfProps(renderProps)?.lang
48
+ if (locale === undefined) {
49
+ throw new Error(
50
+ "[nifra/web-solid] <I18nProvider> needs a `locale`, or an app that registers its locale routing (export `i18n` from backend/framework.ts)",
51
+ )
52
+ }
53
+ return createFormatter(locale, props.messages, {
42
54
  fallback: props.fallback,
43
55
  onMissing: props.onMissing,
44
56
  timeZone: props.timeZone,
45
57
  numberingSystem: props.numberingSystem,
46
- }),
47
- )
58
+ })
59
+ })
48
60
  return createComponent(I18nContext.Provider, {
49
61
  value: formatter,
50
62
  get children() {
@@ -63,6 +75,25 @@ export function useT(): Formatter {
63
75
  return formatter()
64
76
  }
65
77
 
78
+ /**
79
+ * The page's locale key (`ur`, the URL segment), in an app that registers its locale routing (`i18n`
80
+ * in `backend/framework.ts`): from the request on the server, from the URL after each navigation.
81
+ * Without one, the nearest `<I18nProvider>`'s locale; with neither, reading it throws.
82
+ */
83
+ export function useLocale(): Accessor<string> {
84
+ const renderProps = useContext(RenderPropsContext)
85
+ const formatter = useContext(I18nContext)
86
+ return createMemo(() => {
87
+ const locale = localeOfProps(renderProps)?.key ?? formatter?.().locale
88
+ if (locale === undefined) {
89
+ throw new Error(
90
+ "[nifra/web-solid] useLocale() needs an app that registers its locale routing (export `i18n` from backend/framework.ts), or an <I18nProvider> above it",
91
+ )
92
+ }
93
+ return locale
94
+ })
95
+ }
96
+
66
97
  /** Tag handlers for {@link rich}, by tag name: each receives its tag's content as one node. */
67
98
  export type RichTags = Readonly<Record<string, (content: JSX.Element) => JSX.Element>>
68
99
 
package/src/plugin.ts CHANGED
@@ -6,7 +6,12 @@
6
6
  import { transformAsync } from "@babel/core"
7
7
  // @ts-expect-error - no type declarations published
8
8
  import presetTypeScript from "@babel/preset-typescript"
9
- import { devServerCompile, normalizeFilePath, rewriteSsrImports } from "@nifrajs/web/plugins/kit"
9
+ import {
10
+ devServerCompile,
11
+ normalizeFilePath,
12
+ readSource,
13
+ rewriteSsrImports,
14
+ } from "@nifrajs/web/plugins/kit"
10
15
  // @ts-expect-error - no type declarations published
11
16
  import presetSolid from "babel-preset-solid"
12
17
  import type { BunPlugin } from "bun"
@@ -31,7 +36,7 @@ export function solidBunPlugin(generate: "dom" | "ssr"): BunPlugin {
31
36
  // cache); strip it before reading the file off disk.
32
37
  build.onLoad({ filter: /\.tsx(\?|$)/ }, async (args) => {
33
38
  const path = normalizeFilePath(args.path)
34
- const source = await Bun.file(path).text()
39
+ const source = await readSource(build, path)
35
40
  const result = await transformAsync(source, {
36
41
  filename: path,
37
42
  // babel applies presets last→first: strip TS first, then Solid transforms JSX.