langsys-js-react 0.6.6 → 0.7.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/adapters.ts","../src/hooks.ts","../src/components/Translate.tsx","../src/components/Phrase.tsx","../src/components/DontTranslate.tsx","../src/index.ts"],"names":["VanillaTranslate","useRef","useEffect","VanillaPhrase","createElement","_LangsysApp"],"mappings":"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","file":"index.mjs","sourcesContent":["import { useSyncExternalStore } from 'react';\nimport { createSignal, type Signal } from 'langsys-js-typescript';\n\n/**\n * Subscribe a React component to a base-SDK `Signal<T>` and return its current\n * value, re-rendering whenever the signal changes.\n *\n * This is the React mirror of Svelte's `$store` auto-subscription. Where the\n * Svelte wrapper adapts a native store *into* the SDK (`writable` → `Signal`),\n * the React wrapper adapts the SDK's signals *out* to the render cycle. It is\n * built on `useSyncExternalStore`, so it is concurrent-safe and SSR-safe — the\n * server snapshot reads the same `.get()`, which the base SDK seeds from\n * `initialTranslations` during SSR.\n *\n * The base SDK's signals are stable between changes (every `set` replaces the\n * value, so `.get()` returns a fresh reference only after a real change). That\n * is exactly the identity contract `useSyncExternalStore` requires — no tearing,\n * no render loops.\n *\n * `signal` must be stable across renders: a module-level singleton (the SDK's\n * `t` / `currentlyLoadedLocale` / `sTranslations`) or one created once with\n * `useState(() => createLocaleStore(...))`. Passing a freshly-created signal on\n * every render would resubscribe on every render.\n */\nexport function useSignal<T>(signal: Signal<T>): T {\n return useSyncExternalStore(signal.subscribe, signal.get, signal.get);\n}\n\n/**\n * Create a reactive `Signal<string>` to hold the user's selected locale — the\n * React analog of Svelte's `writable('en-US')`.\n *\n * Pass the result as `UserLocaleStore` to `LangsysApp.init`, read it reactively\n * with `useSignal(store)` (or use the all-in-one `useLocaleStore` hook), and\n * switch locale with `store.set('fr-FR')`. The base SDK only ever reads and\n * subscribes to it — it never writes.\n *\n * Locale identifiers are canonicalized to BCP 47 by the base SDK (v0.3.0+), so\n * `'en-us'` still works on input — but `currentlyLoadedLocale` always emits the\n * canonical form (`'en-US'`), so prefer canonical casing to keep comparisons\n * against it straightforward.\n */\nexport function createLocaleStore(initial = 'en-US'): Signal<string> {\n return createSignal<string>(initial);\n}\n","import { useState } from 'react';\nimport { currentlyLoadedLocale, sTranslations, tSignal } from 'langsys-js-typescript';\nimport type { Signal, TFunction, iCategories } from 'langsys-js-typescript';\nimport { createLocaleStore, useSignal } from './adapters.js';\n\n/**\n * The current translation function, re-rendering the calling component whenever\n * translations or the loaded locale change. This is the React analog of Svelte's\n * `$t` store read.\n *\n * const t = useT();\n * return <h1>{t('Welcome to my app', 'UI')}</h1>;\n *\n * The phrase is both the lookup key and the base-language default. Signature:\n * `t(phrase, category?, params?)`. Placeholder names in the phrase are\n * type-checked against the params object at the call site.\n */\nexport function useT(): TFunction {\n return useSignal(tSignal);\n}\n\n/**\n * The locale whose translations are currently loaded. This lags the\n * user-selected locale (`UserLocaleStore`) until the fetch for the new locale\n * settles, which makes it the right value to gate \"translations are ready\" UI on.\n */\nexport function useCurrentLocale(): string {\n return useSignal(currentlyLoadedLocale);\n}\n\n/**\n * The raw translation catalog. Rarely needed in app code — prefer `useT()`.\n * Exposed for advanced cases (inspecting which categories/phrases are loaded).\n */\nexport function useTranslations(): iCategories {\n return useSignal(sTranslations);\n}\n\n/**\n * All-in-one convenience for the user-locale store. Creates one stable\n * `Signal<string>` (the React analog of Svelte's `writable`), subscribes the\n * component to it, and returns `[locale, setLocale, store]`.\n *\n * const [locale, setLocale, store] = useLocaleStore('en-US');\n * useEffect(() => {\n * LangsysApp.init({ projectid, key, UserLocaleStore: store });\n * }, [store]);\n *\n * <select value={locale} onChange={(e) => setLocale(e.target.value)}>...\n *\n * The store is created lazily once and never re-created across renders, so it is\n * safe to pass to `LangsysApp.init` and to depend on in effects.\n */\nexport function useLocaleStore(initial = 'en-US'): [string, (locale: string) => void, Signal<string>] {\n const [store] = useState(() => createLocaleStore(initial));\n const locale = useSignal(store);\n return [locale, store.set, store];\n}\n","import { createElement, useEffect, useRef } from 'react';\nimport type { ReactNode } from 'react';\nimport { Translate as VanillaTranslate, type ParamPrimitive } from 'langsys-js-typescript';\n\n/**\n * Props for the React `Translate` component. Mirrors the Svelte component's\n * props 1:1, with Svelte's `class` renamed to React's idiomatic `className`.\n */\nexport interface TranslateProps {\n /** Optional category under which tokens are registered. Helps translators disambiguate. */\n category?: string;\n /** Optional stable id for the content block. If omitted, the SDK hashes category + tokens. */\n custom_id?: string;\n /** Optional human-readable label shown in the Translation Manager. */\n label?: string;\n /**\n * Interpolation params. Write placeholders as `%key%` in the markup (a bare\n * `{key}` in JSX is a JS expression; the SDK normalizes `%key%` to canonical\n * `{key}` at capture). Applied to content-block text nodes, translatable\n * attributes, `<option>` text, and single-token content — including\n * untranslated fallbacks. Number/Date values get CLDR locale formatting.\n */\n params?: Record<string, ParamPrimitive>;\n /** Host element tag. Defaults to a `<translate>` custom element. */\n tag?: string;\n /** Class applied to the host element. */\n className?: string;\n children?: ReactNode;\n}\n\n/**\n * React wrapper around the vanilla `Translate` DOM class from\n * `langsys-js-typescript`. It renders a host element, then on mount lets the\n * vanilla class walk and tokenize the rendered children (text nodes plus\n * translatable attributes), register the content block, and re-translate on\n * locale change. On unmount it tears the instance down.\n *\n * This is the React analog of the Svelte `<Translate>` component — pure\n * mount/destroy glue. The DOM walking, content-block registration, attribute\n * harvesting, and re-translation lifecycle all live in the base SDK.\n *\n * Like the Svelte component, this lets the SDK mutate the rendered DOM in place,\n * so keep the children static: prose, marketing copy, CMS-rendered HTML — the\n * content-block use case. For dynamic per-string values that React owns and\n * re-renders, use `useT()` instead.\n */\nexport function Translate({\n category = '',\n custom_id = '',\n label = '',\n params,\n tag = 'translate',\n className,\n children,\n}: TranslateProps) {\n const hostRef = useRef<HTMLElement | null>(null);\n const instanceRef = useRef<VanillaTranslate>(undefined);\n\n useEffect(() => {\n const host = hostRef.current;\n if (!host) return;\n const instance = new VanillaTranslate(host, { category, custom_id, label, params });\n instanceRef.current = instance;\n return () => {\n instance.destroy();\n instanceRef.current = undefined;\n };\n // Recreate only when the identity props change; param changes flow through setParams below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [category, custom_id, label]);\n\n // Re-render on changed params after mount, mirroring <Phrase>.\n useEffect(() => {\n instanceRef.current?.setParams(params);\n });\n\n return createElement(tag, { ref: hostRef, className }, children);\n}\n\nexport default Translate;\n","import { createElement, useEffect, useRef } from 'react';\nimport type { ReactNode } from 'react';\nimport { Phrase as VanillaPhrase, PHRASE_MARKER_ATTR, type ParamPrimitive } from 'langsys-js-typescript';\n\n/**\n * Props for the React `Phrase` component. Mirrors the Svelte component's props,\n * with Svelte's `class` renamed to React's idiomatic `className`.\n */\nexport interface PhraseProps {\n /** Category the phrase registers under (disambiguation for translators). */\n category?: string;\n /** Interpolation params. Write placeholders as `%n%` / `%name%` in the markup (a bare `{n}` in JSX is an expression). */\n params?: Record<string, ParamPrimitive>;\n /** Host element tag. Defaults to `<span>`. */\n tag?: string;\n /** Class applied to the host element. */\n className?: string;\n children?: ReactNode;\n}\n\n/**\n * React wrapper around the vanilla `Phrase` rich-text handler.\n *\n * Use it to keep a markup-bearing run as ONE translatable phrase — e.g. so a\n * count variable stays next to the noun it pluralizes:\n *\n * <Phrase category=\"ProductCard\" params={{ n: reviewCount }}>\n * Based on %n% <strong>reviews</strong>\n * </Phrase>\n *\n * Write placeholders as `%n%` (not bare `{n}`): in JSX a literal `{n}` is a JS\n * expression React evaluates before the SDK sees the text. `%n%` passes through\n * as literal text and the SDK normalizes it to canonical `{n}` at capture.\n *\n * The inline markup never reaches the translator — it's replaced with neutral\n * tokens and the real elements are reconstituted at render (see richtext.ts in\n * the base SDK). The host carries `data-ls-phrase` so a wrapping `<Translate>`\n * skips it and lets this handler own it.\n *\n * Keep children static (literal markup): the handler takes over the rendered\n * subtree. For values React owns and re-renders, pass them through `params`.\n */\nexport function Phrase({ category = '', params = {}, tag = 'span', className, children }: PhraseProps) {\n const hostRef = useRef<HTMLElement | null>(null);\n const instanceRef = useRef<VanillaPhrase>(undefined);\n\n useEffect(() => {\n const host = hostRef.current;\n if (!host) return;\n const instance = new VanillaPhrase(host, { category, params });\n instanceRef.current = instance;\n return () => {\n instance.destroy();\n instanceRef.current = undefined;\n };\n // Recreate only when the category changes; param changes flow through setParams below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [category]);\n\n // Re-render on a changed count/param after mount.\n useEffect(() => {\n instanceRef.current?.setParams(params);\n });\n\n return createElement(tag, { ref: hostRef, className, [PHRASE_MARKER_ATTR]: '' }, children);\n}\n\nexport default Phrase;\n","import { createElement } from 'react';\nimport type { ReactNode } from 'react';\n\n/**\n * Props for the React `DontTranslate` component. Mirrors the Svelte component,\n * with Svelte's `class` renamed to React's idiomatic `className`.\n */\nexport interface DontTranslateProps {\n /** Host element tag. Defaults to `<span>`. */\n tag?: string;\n /** Class applied to the host element. */\n className?: string;\n children?: ReactNode;\n}\n\n/**\n * Marks a region as never-translated, preserved verbatim:\n *\n * Built with <DontTranslate>Kangen®</DontTranslate> on{' '}\n * <DontTranslate>langsys.dev</DontTranslate>\n *\n * The host carries the standard `translate=\"no\"` attribute, which both the\n * tokenizer and the renderer in the base SDK already honor — so its content is\n * never tokenized, registered, or replaced. Pure presentational glue; no\n * vanilla handler needed.\n *\n * `data-ls-dont-translate` is a **wrapper-level hook only** — a styling and\n * debugging handle. The base SDK has never matched on it (verified against\n * every published version from 0.1.0 to 0.6.2); exclusion rests entirely on\n * `translate=\"no\"`. Don't remove it — consumers may select on it — but don't\n * describe it as SDK-honored either. The SDK's exclusion set is\n * `translate=\"no\"` (case-insensitive) and PHP's `data-notrans` alias.\n */\nexport function DontTranslate({ tag = 'span', className, children }: DontTranslateProps) {\n return createElement(\n tag,\n { translate: 'no', 'data-ls-dont-translate': '', className },\n children,\n );\n}\n\nexport default DontTranslate;\n","/**\n * langsys-js-react — idiomatic React binding over `langsys-js-typescript`.\n *\n * Public API:\n * - `LangsysApp` — `init` accepts a `Signal<string>` (make one with\n * `createLocaleStore`) for the user locale; every other method delegates.\n * - Hooks — `useT`, `useCurrentLocale`, `useTranslations`, `useLocaleStore`,\n * and the low-level `useSignal`. These are the reactive layer; in components\n * prefer them over the raw signals.\n * - `createLocaleStore` — make the user-locale store (React analog of Svelte's\n * `writable`).\n * - `Translate` — React component wrapping the vanilla DOM `Translate` class.\n * - Raw signals `t` / `currentlyLoadedLocale` / `sTranslations` — re-exported\n * for advanced/direct subscription outside React's render cycle.\n */\n\nimport {\n LangsysApp as _LangsysApp,\n type ExtractParamKeys,\n type ParamPrimitive,\n type ParamsFor,\n type Signal,\n type TArgs,\n type TFunction,\n type TranslationParams,\n type iCategories,\n type iContentBlock,\n type iCountry,\n type iCountryDialCode,\n type iCountryList,\n type iCurrency,\n type iCurrencyList,\n type iLangsysInitConfig as iVanillaInitConfig,\n type iLangsysResponse,\n type iLanguageName,\n type iLocaleData,\n type iLocaleDefault,\n type iLocaleFlat,\n type iProject,\n type iTranslations,\n} from 'langsys-js-typescript';\n\n// Reactive primitives (raw signals) — re-exported for advanced/direct\n// subscription. `tSignal` is exposed under the friendlier name `t`. In\n// components, prefer the hooks (`useT`, `useCurrentLocale`, …).\nexport { currentlyLoadedLocale, createSignal, sTranslations, tSignal as t } from 'langsys-js-typescript';\n\n// Locale canonicalization (BCP 47) — the SDK canonicalizes all locale input\n// (v0.3.0+); re-exported so consumers can normalize their own values the same\n// way before comparing against `useCurrentLocale()` / `detectPreferredLocale()`.\nexport { canonicalizeLocale } from 'langsys-js-typescript';\n\n// API client (vanilla — no React concerns)\nexport { LangsysAppAPI } from 'langsys-js-typescript';\n\n// Hooks + adapters (the React-idiomatic reactive layer)\nexport { createLocaleStore, useSignal } from './adapters.js';\nexport { useCurrentLocale, useLocaleStore, useT, useTranslations } from './hooks.js';\n\n// Components\nexport { Translate, type TranslateProps } from './components/Translate.js';\nexport { Phrase, type PhraseProps } from './components/Phrase.js';\nexport { DontTranslate, type DontTranslateProps } from './components/DontTranslate.js';\n\n// Type re-exports — these are framework-agnostic, so consumers can rely on them\n// directly without reaching into `langsys-js-typescript`.\nexport type {\n ExtractParamKeys,\n ParamPrimitive,\n ParamsFor,\n Signal,\n TArgs,\n TFunction,\n TranslationParams,\n iCategories,\n iContentBlock,\n iCountry,\n iCountryDialCode,\n iCountryList,\n iCurrency,\n iCurrencyList,\n iLangsysResponse,\n iLanguageName,\n iLocaleData,\n iLocaleDefault,\n iLocaleFlat,\n iProject,\n iTranslations,\n};\n\n/**\n * React-flavored init config. Identical to the base SDK's config except\n * `UserLocaleStore` is typed as a `Signal<string>` — create one with\n * `createLocaleStore()` (or get one from the `useLocaleStore` hook). The base\n * SDK only reads and subscribes to it.\n */\nexport interface iLangsysInitConfig extends Omit<iVanillaInitConfig, 'UserLocaleStore'> {\n UserLocaleStore: Signal<string>;\n}\n\n/**\n * React SDK entry point. Delegates everything to the underlying\n * `langsys-js-typescript` singleton. Because React's locale store is already a\n * `Signal` (unlike Svelte's `Writable`, which needs adapting), `init` is a\n * straight passthrough — the React-native concerns live in the hooks and the\n * `<Translate>` component, not here.\n */\nclass LangsysAppReact {\n /** Initialize Langsys. Pass a `Signal<string>` (from `createLocaleStore`) as `UserLocaleStore`. */\n public init(config: iLangsysInitConfig): Promise<iLangsysResponse> {\n return _LangsysApp.init(config);\n }\n\n public get Translations() {\n return _LangsysApp.Translations;\n }\n\n public get translationsLoadingPromise() {\n return _LangsysApp.translationsLoadingPromise;\n }\n\n /** Current translation function. Reads fresh state on every call (not reactive on its own — use `useT()` in components). */\n public get t(): TFunction {\n return _LangsysApp.t;\n }\n\n public get debug() {\n return _LangsysApp.debug;\n }\n\n public refresh() {\n return _LangsysApp.refresh();\n }\n\n public getCountries(inLocale?: string) {\n return _LangsysApp.getCountries(inLocale);\n }\n public getCountryName(forCountryCode: string, inLocale?: string) {\n return _LangsysApp.getCountryName(forCountryCode, inLocale);\n }\n public getCurrencies(inLocale?: string) {\n return _LangsysApp.getCurrencies(inLocale);\n }\n public getCurrencyName(forCurrencyCode: string, inLocale?: string) {\n return _LangsysApp.getCurrencyName(forCurrencyCode, inLocale);\n }\n public getDialCodes(inLocale?: string) {\n return _LangsysApp.getDialCodes(inLocale);\n }\n\n public getLocales(inLocale?: string) {\n return _LangsysApp.getLocales(inLocale);\n }\n public getLocalesFlat(inLocale?: string) {\n return _LangsysApp.getLocalesFlat(inLocale);\n }\n public getLocalesData(inLocale?: string, forceRefresh?: boolean) {\n return _LangsysApp.getLocalesData(inLocale, forceRefresh);\n }\n public getLocalesFormat(format: '' | 'flat' | 'data' = '', inLocale?: string) {\n return _LangsysApp.getLocalesFormat(format, inLocale);\n }\n public getLocaleName(forLocale: string, shortName?: boolean, inLocale?: string) {\n return _LangsysApp.getLocaleName(forLocale, shortName, inLocale);\n }\n public getLocaleNameWithLookup(forLocale: string, shortName?: boolean, inLocale?: string) {\n return _LangsysApp.getLocaleNameWithLookup(forLocale, shortName, inLocale);\n }\n\n /** @deprecated use `getLocaleNameWithLookup` or `getLocaleName` */\n public getLanguageName(forLocale: string, shortName?: boolean, inLocale?: string) {\n return _LangsysApp.getLanguageName(forLocale, shortName, inLocale);\n }\n\n public detectPreferredLocale(acceptLanguageHeader?: string | null, supportedLocales?: string[]) {\n return _LangsysApp.detectPreferredLocale(acceptLanguageHeader, supportedLocales);\n }\n}\n\nexport const LangsysApp = new LangsysAppReact();\n"]}
1
+ {"version":3,"sources":["../src/components/LangsysProvider.tsx","../src/app.ts","../src/adapters.ts","../src/hooks.ts","../src/components/DontTranslate.tsx","../src/block-nodes.ts","../src/components/unit-category.ts","../src/components/Translate.tsx","../src/components/Phrase.tsx"],"names":["LangsysApp","_LangsysApp","useContext","useSyncExternalStore","useState","createElement","kids","createContext","useMemo","useEffect","VanillaTranslate","useRef","renderBlock","currentRequestScope","host","warnUnnamed","registerBlock","warnUnrenderedBlock","VanillaPhrase","warnUnregistered"],"mappings":"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","file":"index.mjs","sourcesContent":["import { createContext, createElement, useContext, useInsertionEffect, useState, useSyncExternalStore } from 'react';\nimport type { ReactNode } from 'react';\nimport { LangsysApp, scopeFromSeed, type RequestScope, type RequestSeed } from 'langsys-js-typescript';\n\n/**\n * The request scope a `<LangsysProvider>` rebuilt from its seed, for the renders that must match\n * the server's HTML: the server render itself and the client's hydration render.\n */\nexport const SeedScope = createContext<RequestScope | null>(null);\n\nconst noSubscription = () => () => {};\n\n/**\n * True during a server render and the client's hydration render, false once hydrated. React\n * uses a store's server snapshot for exactly those two renders, so this is how a component\n * knows to read the request's scope rather than the page's state, with no environment check.\n */\nexport function useServerSnapshotWindow(): boolean {\n return useSyncExternalStore(\n noSubscription,\n () => false,\n () => true,\n );\n}\n\n/** Run `fn` inside the seed's scope while the server snapshot is in use; otherwise as-is. */\nexport function useSeedScopeRunner(): <T>(fn: () => T) => T {\n const scope = useContext(SeedScope);\n const inWindow = useServerSnapshotWindow();\n return scope && inWindow ? (fn) => scope.run(fn) : (fn) => fn();\n}\n\nexport interface LangsysProviderProps {\n /** The request's seed, from `scope.seed()` in a server component, passed down as a prop. */\n seed: RequestSeed | null | undefined;\n children?: ReactNode;\n}\n\n/**\n * Renders a request in its own locale and catalog where the framework renders client\n * components separately from the code that opened the request's scope — Next.js's App Router,\n * where server components and client components use separate copies of the SDK.\n *\n * // app/layout.tsx (a server component)\n * const scope = await createRequestScope({ locale, url }); // from langsys-js-react/server\n * return <LangsysProvider seed={scope.seed()}>{children}</LangsysProvider>;\n *\n * On the server, the provider rebuilds the request's scope from the seed with the core's\n * `scopeFromSeed` and hands it down: `useT()`, `useCurrentLocale()`, `useTranslations()`,\n * `<Translate>` and `<Phrase>` render from it. In the browser it seeds the SDK with the same\n * catalog before any child's effect runs, and the hydration render reads the same scope, so the\n * client's first render matches the server's HTML.\n *\n * Content a client component misses during the server render is registered by the browser after\n * hydration. Under the `server` SSR strategy those misses are not sent from the server: the\n * provider's side of the render has no after-response hook.\n */\nexport function LangsysProvider({ seed, children }: LangsysProviderProps) {\n const [scope] = useState<RequestScope | null>(() => (seed ? scopeFromSeed(seed) : null));\n\n // Browser only (insertion effects never run on a server), and before any child's effect.\n useInsertionEffect(() => {\n if (seed) LangsysApp.seedCatalog(seed.catalog, seed.locale, seed);\n // The seed is the request's; it is applied once.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return createElement(SeedScope.Provider, { value: scope }, children);\n}\n","/**\n * The entry point and its locale store, in a module that imports no React, so the main entry and\n * `langsys-js-react/server` export the same `LangsysApp` and `createLocaleStore`. A server\n * process, a Next Server Component included, initializes the SDK through the server entry\n * without loading React's hooks.\n */\nimport {\n LangsysApp as _LangsysApp,\n createSignal,\n type Signal,\n type iLangsysInitConfig as iVanillaInitConfig,\n type iLangsysResponse,\n} from 'langsys-js-typescript';\n\n/**\n * React-flavored init config. Identical to the base SDK's config except\n * `UserLocaleStore` is typed as a `Signal<string>` — create one with\n * `createLocaleStore()` (or get one from the `useLocaleStore` hook). The base\n * SDK only reads and subscribes to it.\n */\nexport interface iLangsysInitConfig extends Omit<iVanillaInitConfig, 'UserLocaleStore'> {\n UserLocaleStore: Signal<string>;\n}\n\n/**\n * React SDK entry point — the core singleton itself, re-exported **by\n * reference**, with `init` typed to take the React-flavoured config.\n *\n * There is no wrapper and no list of delegated methods, so every public member\n * of the core is reachable here the moment it exists, and identity is\n * preserved: `LangsysApp` here **is** the core's `LangsysApp`. This binding\n * overrides no behaviour, so the only thing it needs to express is a type.\n *\n * Destructuring behaves exactly as on the core. `const { t } = LangsysApp` is\n * safe — `t` is a getter returning a closure. Prototype methods are not:\n * `const { refresh } = LangsysApp` detaches the receiver and the call throws.\n * Call methods on `LangsysApp` itself.\n *\n * The type narrows `init` to require a `Signal<string>` for `UserLocaleStore`.\n * The core accepts the broader `LocaleSource`, which `Signal<string>`\n * satisfies. Because the type is `Omit<typeof _LangsysApp, 'init'> & {…}` —\n * keyof-mapped — it does not expose the core's private members: calling one is\n * a compile error.\n *\n * Pinned by `src/surface.test.ts`.\n */\nexport const LangsysApp: Omit<typeof _LangsysApp, 'init'> & {\n init(config: iLangsysInitConfig): Promise<iLangsysResponse>;\n} = _LangsysApp;\n\n/**\n * Create a reactive `Signal<string>` to hold the user's selected locale — the\n * React analog of Svelte's `writable('en-US')`.\n *\n * Pass the result as `UserLocaleStore` to `LangsysApp.init`, read it reactively\n * with `useSignal(store)` (or use the all-in-one `useLocaleStore` hook), and\n * switch locale with `store.set('fr-FR')`. The base SDK only ever reads and\n * subscribes to it — it never writes.\n *\n * Locale identifiers are canonicalized to BCP 47 by the base SDK (v0.3.0+), so\n * `'en-us'` still works on input — but `currentlyLoadedLocale` always emits the\n * canonical form (`'en-us'` — lowercase, per WIRE-3), so compare against the\n * lowercase form. Verified against the core, not assumed: `canonicalizeLocale`\n * lowercases both subtags, so a consumer testing `=== 'en-US'` never matches.\n */\nexport function createLocaleStore(initial = 'en-US'): Signal<string> {\n return createSignal<string>(initial);\n}\n","import { useContext, useSyncExternalStore } from 'react';\nimport type { Signal } from 'langsys-js-typescript';\nimport { SeedScope } from './components/LangsysProvider.js';\n\n/**\n * Subscribe a React component to a base-SDK `Signal<T>` and return its current\n * value, re-rendering whenever the signal changes.\n *\n * This is the React mirror of Svelte's `$store` auto-subscription. Where the\n * Svelte wrapper adapts a native store *into* the SDK (`writable` → `Signal`),\n * the React wrapper adapts the SDK's signals *out* to the render cycle. It is\n * built on `useSyncExternalStore`, so it is concurrent-safe: a render never\n * observes two different values of the same signal (no tearing). On the\n * server the snapshot reads the value for the current request: inside a core\n * request scope the signals answer from the scope, and under a\n * `<LangsysProvider seed>` the server snapshot — used for the server render and\n * the hydration render — reads through the scope the provider rebuilt.\n *\n * The base SDK's signals are stable between changes (every `set` replaces the\n * value, so `.get()` returns a fresh reference only after a real change). That\n * is exactly the identity contract `useSyncExternalStore` requires — no tearing,\n * no render loops.\n *\n * `signal` must be stable across renders: a module-level singleton (the SDK's\n * `t` / `currentlyLoadedLocale` / `sTranslations`) or one created once with\n * `useState(() => createLocaleStore(...))`. Passing a freshly-created signal on\n * every render would resubscribe on every render.\n */\nexport function useSignal<T>(signal: Signal<T>): T {\n const scope = useContext(SeedScope);\n return useSyncExternalStore(signal.subscribe, signal.get, scope ? () => scope.run(signal.get) : signal.get);\n}\n\n// Lives in app.ts, which imports no React, so the server entry exports the same function.\nexport { createLocaleStore } from './app.js';\n","import { useContext, useEffect, useMemo, useState, useSyncExternalStore } from 'react';\nimport {\n currentlyLoadedLocale,\n notifyNavigation,\n renderServerMessage,\n sTranslations,\n tSignal,\n writeEnabled,\n} from 'langsys-js-typescript';\nimport type { ServerMessage, Signal, TFunction, iCategories } from 'langsys-js-typescript';\nimport { createLocaleStore, useSignal } from './adapters.js';\nimport { SeedScope, useSeedScopeRunner } from './components/LangsysProvider.js';\n\n/**\n * The current translation function, re-rendering the calling component whenever\n * translations or the loaded locale change. This is the React analog of Svelte's\n * `$t` store read.\n *\n * const t = useT();\n * return <h1>{t('Welcome to my app', 'UI')}</h1>;\n *\n * The phrase is both the lookup key and the base-language default. Signature:\n * `t(phrase, category?, params?)`. Placeholder names in the phrase are\n * type-checked against the params object at the call site.\n */\nexport function useT(): TFunction {\n // Under a <LangsysProvider>, the server and hydration renders use the scope's own `t`, which\n // looks phrases up in the request's catalog whenever it is called.\n const scope = useContext(SeedScope);\n return useSyncExternalStore(tSignal.subscribe, tSignal.get, scope ? () => scope.t : tSignal.get);\n}\n\n/**\n * The locale whose translations are currently loaded. This lags the\n * user-selected locale (`UserLocaleStore`) until the fetch for the new locale\n * settles, which makes it the right value to gate \"translations are ready\" UI on.\n */\nexport function useCurrentLocale(): string {\n return useSignal(currentlyLoadedLocale);\n}\n\n/**\n * The raw translation catalog. Rarely needed in app code — prefer `useT()`.\n * Exposed for advanced cases (inspecting which categories/phrases are loaded).\n */\nexport function useTranslations(): iCategories {\n return useSignal(sTranslations);\n}\n\n/**\n * All-in-one convenience for the user-locale store. Creates one stable\n * `Signal<string>` (the React analog of Svelte's `writable`), subscribes the\n * component to it, and returns `[locale, setLocale, store]`.\n *\n * const [locale, setLocale, store] = useLocaleStore('en-US');\n * useEffect(() => {\n * LangsysApp.init({ projectid, key, UserLocaleStore: store });\n * }, [store]);\n *\n * <select value={locale} onChange={(e) => setLocale(e.target.value)}>...\n *\n * The store is created lazily once and never re-created across renders, so it is\n * safe to pass to `LangsysApp.init` and to depend on in effects.\n */\nexport function useLocaleStore(initial = 'en-US'): [string, (locale: string) => void, Signal<string>] {\n const [store] = useState(() => createLocaleStore(initial));\n const locale = useSignal(store);\n return [locale, store.set, store];\n}\n\n/**\n * Stable server snapshot for `useWriteEnabled`. Must be module-level so its\n * identity never changes across renders.\n */\nconst writeEnabledServerSnapshot = (): undefined => undefined;\n\n/**\n * Whether the current session may register content, as decided by the server.\n *\n * Tri-state, and the three states are genuinely distinct:\n * - `undefined` — authorization hasn't landed yet. Not the same as read-only.\n * - `false` — read-only session; the SDK may report the page URL instead,\n * subject to the key's auto-discovery permission. A read-only\n * key with discovery disallowed reports nothing at all.\n * - `true` — this session registers content directly.\n *\n * Don't collapse it to a boolean and don't default `undefined` to `false`: the\n * same key can be write-enabled from one IP and read-only from another, so only\n * the server can answer, and \"not yet known\" is a real state to render for.\n *\n * Unlike the other hooks this does *not* go through `useSignal`. `writeEnabled`\n * is browser-authoritative — it is only ever written client-side and stays\n * `undefined` during SSR. Reusing `useSignal` would pass `signal.get` as the\n * server snapshot, and `getServerSnapshot` is used both on the server *and* for\n * the hydration render on the client. If authorization resolved before\n * hydration, that render would disagree with the server HTML and React would\n * throw the markup away. Pinning the server snapshot to `undefined` keeps the\n * hydration pass matching the server; the real value arrives right after.\n */\nexport function useWriteEnabled(): boolean | undefined {\n return useSyncExternalStore(writeEnabled.subscribe, writeEnabled.get, writeEnabledServerSnapshot);\n}\n\n/**\n * Tell the SDK the route changed, whenever `location` changes. Call it once, anywhere under\n * your router, with the router's current location:\n *\n * // React Router\n * useNotifyNavigation(useLocation().key);\n * // Next.js App Router\n * useNotifyNavigation(usePathname() + '?' + useSearchParams());\n *\n * Why it exists: content that stays mounted across a route change — a persistent layout, a\n * header — is never re-rendered by React when only the route changes, because React skips\n * a subtree whose element is unchanged. Nothing then calls back into the SDK, so the new\n * page is never credited with that content. `notifyNavigation()` makes every mounted\n * translated node look itself up again at the new URL. This hook only times that call; the\n * SDK decides everything else (spec HINT-13).\n *\n * This package cannot know which router an app uses, so it takes the router's location as a\n * plain value instead of importing any router. Calling `notifyNavigation` directly from a\n * router's own after-navigation hook is equivalent.\n */\nexport function useNotifyNavigation(location: unknown): void {\n useEffect(() => {\n notifyNavigation();\n }, [location]);\n}\n\n/**\n * A function that renders server message entries, re-rendering the calling component whenever\n * translations or the loaded locale change:\n *\n * const render = useRenderServerMessage();\n * const entries = resolveServerMessages(responseBody);\n * return <ul>{entries.map((e, i) => <li key={i}>{render(e)}</li>)}</ul>;\n *\n * It is the SDK's `renderServerMessage` and decides nothing itself: the entry's template is\n * looked up under the messages category (`messagesCategory` in `init`, `Errors` by default) and\n * filled from its params, and the entry's `message` is shown when the catalog has no\n * translation for it (spec MSG-5). The returned function changes identity exactly when a\n * lookup could give a different answer, so it can be depended on in memos and effects.\n */\nexport function useRenderServerMessage(): (entry: ServerMessage, category?: string) => string {\n const t = useT();\n // `t` is the dependency on purpose: it changes whenever the catalog or locale does, which\n // is when a render must be redone. The core reads the current catalog itself.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const inSeedScope = useSeedScopeRunner();\n return useMemo(\n () => (entry: ServerMessage, category?: string) => inSeedScope(() => renderServerMessage(entry, category)),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [t],\n );\n}\n","import { createElement } from 'react';\nimport type { ReactNode } from 'react';\n\n/**\n * Props for the React `DontTranslate` component. Mirrors the Svelte component,\n * with Svelte's `class` renamed to React's idiomatic `className`.\n */\nexport interface DontTranslateProps {\n /** Host element tag. Defaults to `<span>`. */\n tag?: string;\n /** Class applied to the host element. */\n className?: string;\n children?: ReactNode;\n}\n\n/**\n * Marks a region as never-translated, preserved verbatim:\n *\n * Built with <DontTranslate>Kangen®</DontTranslate> on{' '}\n * <DontTranslate>langsys.dev</DontTranslate>\n *\n * The host carries the standard `translate=\"no\"` attribute, which both the\n * tokenizer and the renderer in the base SDK already honor — so its content is\n * never tokenized, registered, or replaced. Pure presentational glue; no\n * vanilla handler needed. Inside `<Translate>` / `<Phrase>` the block mapping reads it as the host\n * element it renders (`toBlockNodes`), so the unit around it stays on the core's tree path, and the\n * build transform marks a value inside it rather than replacing it (VAR-3).\n *\n * `data-ls-dont-translate` is a **wrapper-level hook only** — a styling and\n * debugging handle. The base SDK has never matched on it (verified against\n * every published version from 0.1.0 to 0.6.2); exclusion rests entirely on\n * `translate=\"no\"`. Don't remove it — consumers may select on it — but don't\n * describe it as SDK-honored either. The SDK's exclusion set is\n * `translate=\"no\"` (case-insensitive) and PHP's `data-notrans` alias.\n */\nexport function DontTranslate({ tag = 'span', className, children }: DontTranslateProps) {\n return createElement(\n tag,\n { translate: 'no', 'data-ls-dont-translate': '', className },\n children,\n );\n}\n\nexport default DontTranslate;\n","/**\n * React children to the core's `BlockNode[]`, for rendering `<Translate>` / `<Phrase>` content\n * through the core's non-DOM block path.\n *\n * What is mapped is exactly what the client's DOM walk would see: host elements with their\n * attributes, strings and numbers. Fragments, arrays and conditional `null` / `false` flatten\n * away, as they do in the DOM. `<DontTranslate>` is this package's own and renders one host\n * element from its props, so it is mapped as that element. A portal renders outside the host on\n * both sides, so it is kept for rendering but excluded from the nodes. A child whose DOM is\n * unknown until React renders it — any other function or class component, a provider, `lazy`,\n * `Suspense` — or whose content is an HTML string (`dangerouslySetInnerHTML`) makes the block\n * unmappable: it is not server-rendered, and its source is served as it is (fleet rule).\n *\n * `elements[i]` is the React element that the `i`th element node of `nodes`, counted in document\n * order, came from. That is what the core's `source` back-reference on a translated element\n * holds: the binding clones that element, with its handlers, refs and key, into the translated\n * position, which a translation may have moved.\n */\nimport * as React from 'react';\nimport { Children, Fragment, cloneElement, createElement, isValidElement, type ReactElement, type ReactNode, type ReactPortal, type Usable } from 'react';\nimport { isTranslationExcluded, type BlockNode, type RenderedNode } from 'langsys-js-typescript';\nimport { NON_TRANSLATABLE_ELEMENTS } from 'langsys-js-typescript/pure';\nimport { DontTranslate, type DontTranslateProps } from './components/DontTranslate.js';\n\n/**\n * `portals` are those at the unit's own level, which the component renders beside the translated\n * nodes; `nested[i]` holds the ones `elements[i]` held, which `toReactNodes` puts back as that\n * element's children, so React's tree, along which a portal's events bubble and context reaches\n * it, keeps the portal under the element that held it.\n */\nexport type Mapped =\n | { ok: true; nodes: BlockNode[]; elements: ReactElement[]; portals: ReactPortal[]; nested: ReactPortal[][] }\n | { ok: false; reason: string };\n\nconst PORTAL = Symbol.for('react.portal');\n\n/** React prop names to DOM attribute names, for the props that differ. */\nconst PROP_TO_ATTR: Record<string, string> = { className: 'class', htmlFor: 'for' };\n\n/**\n * A prop's value as the attribute the core reads: `true` is a bare attribute (`''`); a function,\n * an object (a style and the like, which carries no translatable text), `false` and nothing have\n * none.\n */\nfunction attrValue(value: unknown): string | undefined {\n if (typeof value === 'function' || typeof value === 'object' || value === undefined || value === false) return undefined;\n return value === true ? '' : String(value);\n}\n\nfunction attrsOf(props: Record<string, unknown>): Record<string, string> | undefined {\n const out: Record<string, string> = {};\n for (const [name, value] of Object.entries(props)) {\n if (name === 'children' || name === 'key' || name === 'ref') continue;\n const attr = attrValue(value);\n if (attr !== undefined) out[PROP_TO_ATTR[name] ?? name] = attr;\n }\n return Object.keys(out).length ? out : undefined;\n}\n\nconst CONTEXT = Symbol.for('react.context');\n\n/**\n * React 19's `use`, read off the module so the binding loads under React 18, which has none and\n * renders neither a promise nor a context as a child: there such a value stays a node, for React.\n */\nconst read = (React as { use?: <T>(usable: Usable<T>) => T }).use;\n\n/** A context object, which React 19 renders as its current value. */\nfunction isContext(node: unknown): node is React.Context<unknown> {\n return typeof node === 'object' && node !== null && (node as { $$typeof?: symbol }).$$typeof === CONTEXT;\n}\n\n/** A value React 19 renders by reading it, as `use` does: a thenable, or a context. */\nfunction isUsable(node: unknown): node is Usable<unknown> {\n if (typeof node !== 'object' || node === null) return false;\n return typeof (node as PromiseLike<unknown>).then === 'function' || (node as { $$typeof?: symbol }).$$typeof === CONTEXT;\n}\n\n/** A value the core's params take (its `ParamPrimitive`): text, a number, a boolean, a date (from any realm). */\nfunction isParamValue(value: unknown): boolean {\n return typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' || isDate(value);\n}\n\n/** A date, from any realm. */\nfunction isDate(value: unknown): boolean {\n return Object.prototype.toString.call(value) === '[object Date]';\n}\n\n/**\n * Each one-shot list's items (a generator, an iterator: its own iterator), as first read, since a\n * unit renders again (hydration, a locale change) with the same props. A list that can be read again\n * (a `Set`, a `Map`) is read again at each render, as React reads one.\n */\nconst oneShotItems = new WeakMap<Iterable<ReactNode>, ReactNode[]>();\n\nfunction itemsOf(list: Iterable<ReactNode>): ReactNode[] {\n if ((list[Symbol.iterator]() as unknown) !== list) return Array.from(list);\n let items = oneShotItems.get(list);\n if (!items) oneShotItems.set(list, (items = Array.from(list)));\n return items;\n}\n\n/** A child React renders as a list: an iterable that is neither text nor an element (a `Set`, a generator). */\nfunction isIterable(node: unknown): node is Iterable<ReactNode> {\n return typeof node === 'object' && node !== null && !isValidElement(node) && typeof (node as Iterable<ReactNode>)[Symbol.iterator] === 'function';\n}\n\nfunction isPortal(node: unknown): node is ReactPortal {\n return typeof node === 'object' && node !== null && (node as { $$typeof?: symbol }).$$typeof === PORTAL;\n}\n\nexport function toBlockNodes(children: ReactNode): Mapped {\n const elements: ReactElement[] = [];\n const portals: ReactPortal[] = [];\n const nested: ReactPortal[][] = [];\n let failure: string | undefined;\n\n /** Flatten one level of React children into nodes, numbering elements in document order; `parent` is the index of the element holding it. */\n function mapLevel(level: ReactNode, parent: number | null): BlockNode[] {\n const out: BlockNode[] = [];\n const visit = (node: ReactNode): void => {\n if (failure || node === null || node === undefined || typeof node === 'boolean') return;\n if (typeof node === 'string' || typeof node === 'number' || typeof node === 'bigint') {\n out.push({ text: String(node) });\n return;\n }\n if (Array.isArray(node)) return node.forEach(visit);\n if (isPortal(node)) {\n if (parent === null) portals.push(node);\n else nested[parent].push(node);\n return;\n }\n if (!isValidElement(node)) {\n failure = `an unsupported child (${typeof node})`;\n return;\n }\n const props = node.props as Record<string, unknown>;\n if (node.type === DontTranslate) return visit(DontTranslate(props as DontTranslateProps));\n if (typeof node.type !== 'string') {\n failure = 'a component, provider, lazy or Suspense child, whose DOM is unknown until React renders it';\n return;\n }\n if (props.dangerouslySetInnerHTML) {\n failure = 'dangerouslySetInnerHTML, an HTML string rather than a tree';\n return;\n }\n const index = elements.push(node) - 1;\n nested[index] = [];\n const kids = mapLevel(props.children as ReactNode, index);\n const attrs = attrsOf(props);\n out.push({ tag: node.type, ...(attrs ? { attrs } : {}), ...(kids.length ? { children: kids } : {}) });\n };\n Children.toArray(withoutFragments(level)).forEach(visit);\n return out;\n }\n\n const nodes = mapLevel(children, null);\n return failure ? { ok: false, reason: failure } : { ok: true, nodes, elements, portals, nested };\n}\n\n/** DOM attribute names back to React prop names, for the ones that differ. */\nconst ATTR_TO_PROP: Record<string, string> = { class: 'className', for: 'htmlFor' };\n\n/** `text` as a pattern that matches its characters literally. */\nconst literally = (text: string) => text.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n/**\n * The prop an attribute the core hands back sets on the original element. The core reads names as\n * HTML does, ignoring case, so `tabindex` is the element's own `tabIndex`; an attribute the\n * element does not have (one the core adds) keeps its name.\n */\nfunction propFor(attr: string, props: Record<string, unknown>): string {\n const same = new RegExp(`^${literally(attr)}$`, 'i');\n return ATTR_TO_PROP[attr] ?? Object.keys(props).find((name) => same.test(name)) ?? attr;\n}\n\n/**\n * A rendered block back to React: each element is the original React element it renders\n * (`elements[source]`), cloned so its handlers, refs and key survive, with the attributes the\n * translation changed or the core added set on it, and its translated children, then the portals\n * it held (`nested`). Comments are another host's markers and render nothing here.\n */\nexport function toReactNodes(\n nodes: readonly RenderedNode[],\n elements: readonly ReactElement[],\n nested: ReadonlyArray<readonly ReactPortal[] | undefined> = [],\n): ReactNode[] {\n return nodes.flatMap((node): ReactNode[] => {\n if ('text' in node) return [node.text];\n if ('comment' in node) return [];\n const original = elements[node.source];\n const originalProps = original.props as Record<string, unknown>;\n const changed: Record<string, unknown> = {};\n for (const [attr, value] of Object.entries(node.attrs)) {\n if (value === true) continue; // a bare attribute: the original prop already renders it\n const prop = propFor(attr, originalProps);\n // Compared as `attrsOf` handed it over, so a boolean prop (`disabled`, sent as `''`) stays the prop it is.\n if ((attrValue(originalProps[prop]) ?? '') !== value) changed[prop] = value;\n }\n const kids = [...toReactNodes(node.children, elements, nested), ...(nested[node.source] ?? [])];\n return [kids.length ? cloneElement(original, changed, ...kids) : cloneElement(original, { ...changed, children: undefined } as Partial<unknown>)];\n });\n}\n\n/**\n * Whether children carry a value from a variable that no build step turned into a placeholder\n * (spec VAR-7). Literal JSX text reaches React as one string per run, so a text run split across\n * adjacent children — two pieces, strings or numbers, that are not whitespace-only — holds an\n * interpolation (`Hello {name}` arrives as `['Hello ', 'Ana']`). A fragment's children are read as\n * part of the run around them, as React renders them. Checked at every level of host elements and\n * `<DontTranslate>`. A value that is the only text of its element (`<b>{name}</b>`, `<b>{count}</b>`)\n * cannot be told from literal text at runtime; only the build transform recovers it, and the value\n * marker it writes (VAR-3) holds its value alone, so it never reads as split.\n *\n * With `skipExcluded`, for a `<Phrase>`, a subtree the core shows as written (`<DontTranslate>`,\n * an element its `isTranslationExcluded` excludes, or code and notation, `NON_TRANSLATABLE_ELEMENTS`)\n * is not read: the phrase keys it as one empty markup pair whatever it holds (TOK-1), so a value\n * inside it never enters the phrase. A `<Translate>` block stores that subtree in its content, so\n * there it still counts.\n */\nexport function hasRuntimeValues(children: ReactNode, skipExcluded = false): boolean {\n let run: Array<string | number | bigint> = [];\n const flush = () => {\n const hit = run.filter((p) => String(p).trim() !== '').length > 1;\n run = [];\n return hit;\n };\n for (const c of [...inRun(children), null]) {\n if (typeof c === 'string' || typeof c === 'number' || typeof c === 'bigint') {\n run.push(c);\n continue;\n }\n if (flush()) return true;\n if (!isValidElement(c)) continue;\n const node = c.type === DontTranslate ? DontTranslate(c.props as DontTranslateProps) : c;\n if (typeof node.type !== 'string') continue;\n const props = node.props as Record<string, unknown>;\n if (skipExcluded && opaqueInPhrase(node.type, props)) continue;\n if (hasRuntimeValues(props.children as ReactNode, skipExcluded)) return true;\n }\n return false;\n}\n\n/**\n * Children with each fragment replaced by its children as a nested array, so `Children.toArray`\n * flattens them into the level and keys every element by its place in the whole level: an element\n * from a fragment never shares a key with one beside the fragment.\n */\nfunction withoutFragments(node: ReactNode): ReactNode {\n // React 19 renders a context as its current value: read it as React reads it.\n if (read && isContext(node)) return withoutFragments(read(node) as ReactNode);\n if (Array.isArray(node)) return node.map(withoutFragments);\n if (isIterable(node)) return Array.from(node, withoutFragments);\n if (isValidElement(node) && node.type === Fragment) return [withoutFragments((node.props as { children?: ReactNode }).children)];\n return node;\n}\n\n/** A level of children as React renders it: arrays and fragments flattened, so a fragment's text joins the run around it. */\nfunction inRun(level: ReactNode): ReactNode[] {\n return Children.toArray(withoutFragments(level));\n}\n\n/** Whether the core keys an element as one empty pair in a phrase: its exclusion, or code and notation. */\nfunction opaqueInPhrase(tag: string, props: Record<string, unknown>): boolean {\n return NON_TRANSLATABLE_ELEMENTS.includes(tag) || isTranslationExcluded(attributeReader(tag, attrsOf(props)));\n}\n\n/** A mapped element's attributes (`attrsOf`, as the tree path hands them to the core), in the shape the core's exclusion reads. */\nfunction attributeReader(tagName: string, attrs: Record<string, string> | undefined) {\n const valueOf = (name: string) => Object.entries(attrs ?? {}).find(([key]) => key === name)?.[1];\n return { tagName, getAttribute: (name: string) => valueOf(name) ?? null, hasAttribute: (name: string) => valueOf(name) !== undefined };\n}\n\n/**\n * Children and params as React would render the values the build transform made params: the\n * transform cannot tell a value's type, so `Click {icon} to go` becomes `Click %icon% to go` with\n * `icon` a param, and the value decides here. A value the core's params take (text, a number, a\n * boolean, a date) stays a param: a boolean stays a boolean, which the core formats and a select\n * branches on, as in `t()`. Null and undefined, which React renders as nothing, fill their\n * placeholder with nothing, and a bigint, which the core's params do not take, is its digits. On\n * React 19 a promise or a context is read as React reads one in place (`use`), and its value decides\n * the same way. Anything else (an element, a portal, a list, a function) is put back where its\n * `%name%` placeholder stands, for React to render as it renders it; a one-shot list (a generator)\n * is read once, and its items kept for the unit's next render, while a `Set` is read at each. Text inside host elements, fragments and\n * `<DontTranslate>` is searched, as the transform rewrites it; a node param with no placeholder is\n * dropped. A restored node is wrapped in a fragment keyed by its place in the run, so it never\n * shares a key with the unit's other elements and needs none of its own. A node's placeholder is\n * found as the core reads placeholders, left to right (`%a%b%b%` is `%a%`, `b`, `%b%`), in either\n * spelling: `%name%`, or the stored form `{name}`, which the transform writes where `%name%` would\n * be misread. A host element's prop that is exactly a node's placeholder is given the value itself,\n * which React writes as it writes any attribute value; a node's placeholder in an attribute's text is\n * filled as JavaScript writes the value into a string (`String(value)`), the param the core fills the\n * attribute with. Children\n * with nothing to put back are returned as they are.\n */\nexport function withNodeParams<P extends Readonly<Record<string, unknown>>>(\n children: ReactNode,\n given: P,\n): { children: ReactNode; params: P } {\n const nodes: Record<string, ReactNode> = {};\n const rest: Record<string, unknown> = {};\n /** The node values, by the placeholder (either spelling) that stands for one: a prop that is exactly one takes the value. */\n const props: Record<string, unknown> = Object.create(null);\n for (const [name, param] of Object.entries(given)) {\n // A promise or a context is read as React reads one in place (`use`), and its value taken as given.\n const value = read && isUsable(param) ? read(param) : param;\n if (value === null || value === undefined) rest[name] = '';\n else if (typeof value === 'bigint') rest[name] = String(value);\n else if (isParamValue(value)) rest[name] = value;\n else {\n nodes[name] = isIterable(value) && !Array.isArray(value) ? itemsOf(value) : (value as ReactNode);\n props[`%${name}%`] = props[`{${name}}`] = value;\n }\n }\n const names = Object.keys(nodes);\n if (!names.length) return { children, params: rest as P };\n // Placeholders as the core reads them, left to right: a node's in either spelling, `%name%` or the\n // stored form `{name}`, and any other `%name%`, which is read first and so is left as text.\n const alternatives = names.map(literally).join('|');\n const split = new RegExp(`%(${alternatives})%|(%[A-Za-z_][A-Za-z0-9_]*%)|\\\\{(${alternatives})\\\\}`);\n\n /** The node values an attribute holds in its text, which the core fills as text. */\n const inText = new Set<string>();\n /** A host element's props that are exactly one node value's placeholder. */\n const ownProps = (element: Record<string, unknown>): Record<string, unknown> | undefined => {\n let out: Record<string, unknown> | undefined;\n for (const [prop, value] of Object.entries(element)) {\n if (prop === 'children' || typeof value !== 'string') continue;\n if (value in props) (out ??= {})[prop] = props[value];\n else {\n for (const match of value.matchAll(new RegExp(split.source, 'g'))) {\n const name = match[1] ?? match[3];\n if (name !== undefined) inText.add(name);\n }\n }\n }\n return out;\n };\n\n const visit = (node: ReactNode): ReactNode => {\n if (typeof node === 'string') {\n const parts = node.split(new RegExp(split.source, 'g'));\n // Each match leaves the text before it, then a node's name in whichever spelling matched,\n // or another placeholder, which stays text.\n const out: ReactNode[] = [];\n let text = '';\n for (let i = 0; i < parts.length; i += 4) {\n text += parts[i] + (parts[i + 2] ?? '');\n const name = parts[i + 1] ?? parts[i + 3];\n if (name === undefined) continue;\n if (text) out.push(text);\n text = '';\n out.push(createElement(Fragment, { key: i + 1 }, nodes[name]));\n }\n if (out.length === 0) return node;\n if (text) out.push(text);\n return out;\n }\n if (Array.isArray(node)) {\n const kids = node.map(visit);\n return kids.some((kid, i) => kid !== node[i]) ? kids : node;\n }\n if (!isValidElement(node)) return node;\n if (typeof node.type !== 'string' && node.type !== Fragment && node.type !== DontTranslate) return node;\n const attrs = typeof node.type === 'string' ? ownProps(node.props as Record<string, unknown>) : undefined;\n const own = (node.props as { children?: ReactNode }).children;\n if (own === undefined) return attrs ? cloneElement(node, attrs) : node;\n const kids = Array.isArray(own) ? own.map(visit) : [visit(own)];\n const same = Array.isArray(own) ? kids.every((kid, i) => kid === own[i]) : kids[0] === own;\n return same && !attrs ? node : cloneElement(node, attrs, ...kids);\n };\n const rendered = visit(children);\n // An attribute's text is a string: a node value there fills it as JavaScript writes the value into one.\n for (const name of inText) rest[name] = String(props[`%${name}%`]);\n return { children: rendered, params: rest as P };\n}\n","import { createContext, useContext, useMemo } from 'react';\n\n/**\n * The category a `<Translate>` or `<Phrase>` renders and registers under, and the one its content\n * was registered under before it moved (MOVE-1). `previousCategory` is absent (or null) when the\n * content did not move and `''` when it had no category before.\n */\nexport interface UnitCategory {\n category: string;\n previousCategory?: string | null;\n}\n\n/**\n * What a block that falls back to the core's DOM class (it holds a component, so its DOM is unknown\n * until React renders it) hands to the units inside it: its own resolved category and previous\n * category. A unit nested in it moved with it (MOVE-4), as a host nested in a block does in the\n * core's own walk, which reads the enclosing block's options the same way.\n */\nexport const BlockCategory = createContext<UnitCategory | undefined>(undefined);\n\n/**\n * A unit's category and previous category, given what it names itself.\n *\n * A unit that names no category (the prop is absent) takes the enclosing block's category and,\n * unless it names a previous category of its own, the block's previous category (MOVE-4). One that\n * names its own category, `''` included, takes neither: it moved only if it names its own previous\n * category. A unit outside any block, naming none, has no category (`''`). The result is stable between renders with the same inputs, so it can\n * be provided to the units below without re-rendering them.\n */\nexport function useUnitCategory(named: string | undefined, namedPrevious: string | null | undefined): UnitCategory {\n const block = useContext(BlockCategory);\n const outerCategory = block?.category;\n const outerPrevious = block?.previousCategory;\n return useMemo(() => {\n if (named !== undefined || !block) return { category: named ?? '', previousCategory: namedPrevious };\n return { category: block.category, previousCategory: namedPrevious ?? block.previousCategory };\n // `block` is read through its two fields, so a new object with the same values changes nothing.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [named, namedPrevious, block !== undefined, outerCategory, outerPrevious]);\n}\n","import { createElement, useEffect, useRef } from 'react';\nimport type { ReactNode } from 'react';\nimport {\n CONTENT_BLOCK_MARKER_ATTR,\n Translate as VanillaTranslate,\n currentRequestScope,\n registerBlock,\n renderBlock,\n warnUnrenderedBlock,\n warnUnregistered,\n type BlockOptions,\n type ParamPrimitive,\n} from 'langsys-js-typescript';\nimport { hasRuntimeValues, toBlockNodes, toReactNodes, withNodeParams } from '../block-nodes.js';\nimport { useT } from '../hooks.js';\nimport { useSeedScopeRunner } from './LangsysProvider.js';\nimport { BlockCategory, useUnitCategory } from './unit-category.js';\n\n/**\n * Props for the React `Translate` component. Mirrors the Svelte component's\n * props 1:1, with Svelte's `class` renamed to React's idiomatic `className`.\n */\nexport interface TranslateProps {\n /** Optional category under which tokens are registered. Helps translators disambiguate. */\n category?: string;\n /**\n * The category this content was registered under before it moved to `category` (MOVE-1):\n * `''` for none, absent for no move. Its translations follow it instead of being made, and\n * charged for, again; until the catalog holds it under `category`, the previous category's\n * entry renders and the host says so (MOVE-4, MOVE-5). Never part of its identity (MOVE-2),\n * and sent only on the registration a miss triggers (MOVE-3), so once the catalog has it the\n * prop does nothing and can be deleted whenever convenient.\n */\n previousCategory?: string | null;\n /** Optional stable id for the content block. If omitted, the SDK hashes category + tokens. */\n custom_id?: string;\n /** Optional human-readable label shown in the Translation Manager. */\n label?: string;\n /**\n * Interpolation params. Write placeholders as `%key%` in the markup (a bare\n * `{key}` in JSX is a JS expression; the SDK normalizes `%key%` to canonical\n * `{key}` at capture). Applied to content-block text nodes, translatable\n * attributes, `<option>` text, and single-token content — including\n * untranslated fallbacks. Number/Date values get CLDR locale formatting.\n *\n * A bare `{key}` doesn't just break interpolation — JSX evaluates it before\n * the walker runs, so the *value* is captured as part of the phrase and each\n * distinct value hashes to its own content block. A `<Translate>` around a\n * live counter registers a new block per tick while rendering correctly in\n * the base locale the whole time. `%key%` yields one stable id for all\n * values.\n */\n params?: Record<string, ParamPrimitive>;\n /** Host element tag. Defaults to a `<translate>` custom element. */\n tag?: string;\n /** Class applied to the host element. */\n className?: string;\n children?: ReactNode;\n /**\n * Set by the build transform when the block would store a value it left as written (inside\n * MathML or SVG, `<script>` or `<style>`, or an element that holds text only): the block\n * registers nothing (VAR-7) and renders what the catalog holds.\n */\n 'data-ls-unnamed'?: string;\n}\n\n/**\n * Translates a block of static content: prose, markup, CMS copy.\n *\n * Content made of host elements, text and numbers renders through the core's `renderBlock`: the\n * translated tree, the block's id and its markers come back as data, and this component renders\n * them as React elements — the originals, cloned with their handlers, refs and keys, in the\n * places the translation puts them. The same call runs on a server (inside a request scope) and\n * in the browser (over the seeded catalog), so the first client render matches the server's HTML,\n * and a locale change re-renders it. Registration goes through the core's `registerBlock`; no DOM\n * class ever walks text nodes React owns.\n *\n * Content whose DOM is unknown until React renders it — a component, `lazy`, `Suspense`, or\n * `dangerouslySetInnerHTML` — is rendered as it is, with an explicit `custom_id` stamped, and the\n * core's DOM `Translate` class translates it after mount. On a server the core warns once per\n * reason that such a block was served as source.\n */\nexport function Translate({\n category: named,\n previousCategory: namedPrevious,\n custom_id = '',\n label = '',\n params: given,\n tag = 'translate',\n className,\n children: content,\n 'data-ls-unnamed': unmarked,\n}: TranslateProps) {\n // Inside a block that falls back, the block's category and previous category unless this unit\n // names its own (MOVE-4).\n const unit = useUnitCategory(named, namedPrevious);\n const { category, previousCategory } = unit;\n // A param that is an element or a list renders in its place, not as text.\n const { children, params } = given ? withNodeParams(content, given) : { children: content, params: given };\n const t = useT(); // changes with the locale, the catalog and a route change (HINT-13)\n const hostRef = useRef<HTMLElement | null>(null);\n const instanceRef = useRef<VanillaTranslate>(undefined);\n const mapped = toBlockNodes(children);\n // `id` is the app's own id for the block: rendered and registered under it (MARK-1).\n // A value the build transform did not name (it is not enabled, or the value is a conditional),\n // or one it left as written, has no name, so the unit registers nothing (VAR-7); what the\n // catalog already holds still renders.\n const unnamedValues = unmarked !== undefined || hasRuntimeValues(children);\n const options: BlockOptions = {\n category,\n ...(previousCategory === undefined || previousCategory === null ? {} : { previousCategory }),\n params,\n label,\n ...(custom_id ? { id: custom_id } : {}),\n ...(unnamedValues ? { register: false } : {}),\n };\n // Under a <LangsysProvider>, the server and hydration renders read the request's scope.\n const inSeedScope = useSeedScopeRunner();\n const rendered = mapped.ok ? inSeedScope(() => renderBlock(mapped.nodes, options)) : null;\n const scope = currentRequestScope();\n\n const register = (host?: Element) => {\n if (!mapped.ok || !rendered || rendered.shape === 'empty') return;\n // With a value the transform did not name, `options` carries `register: false`: the call\n // registers nothing and still claims the host.\n if (unnamedValues) warnUnnamed(unmarked !== undefined);\n // `host` claims the element for this component, so an enclosing <Translate> that fell back\n // to the core's DOM class leaves it alone instead of taking it over with its own params\n // (MARK-2), and lets the core check the block's ancestors for a resolved marker (GATE-10).\n // The promise is left unhandled on purpose: it rejects only under `requireCredentials`\n // with no credentials (WIRE-4), React has no lifecycle that takes a promise, and an\n // unhandled rejection is how the core surfaces that. Inside a request scope it never rejects.\n void registerBlock(mapped.nodes, { ...options, host });\n };\n if (scope) {\n // A server render: the scope holds the registration for close().\n register();\n if (!mapped.ok) warnUnrenderedBlock(mapped.reason);\n }\n\n const blockKey = rendered ? `${category}\\u0000${custom_id}\\u0000${rendered.customId}` : null;\n useEffect(() => {\n register(hostRef.current ?? undefined);\n // Registration is one-shot per call: it runs again whenever `t` changes (a locale, a\n // catalog or a route change), the block's identity does, or a new `tag` replaces the host,\n // which only this call can claim.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [t, blockKey, tag]);\n\n // Unmappable content only: the core's DOM class walks and translates it after mount.\n useEffect(() => {\n const host = hostRef.current;\n if (mapped.ok || !host) return;\n if (unnamedValues) warnUnnamed(unmarked !== undefined);\n const instance = new VanillaTranslate(host, {\n category,\n ...(previousCategory === undefined || previousCategory === null ? {} : { previousCategory }),\n custom_id,\n label,\n params,\n ...(unnamedValues ? { register: false } : {}),\n });\n instanceRef.current = instance;\n return () => {\n instance.destroy();\n instanceRef.current = undefined;\n };\n // A new `tag` replaces the host element, so the instance moves to the new one.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [mapped.ok, category, previousCategory, custom_id, label, tag]);\n\n useEffect(() => {\n instanceRef.current?.setParams(params);\n });\n\n if (mapped.ok && rendered) {\n return createElement(\n tag,\n { ref: hostRef, className, ...rendered.hostAttrs },\n ...toReactNodes(rendered.nodes, mapped.elements, mapped.nested),\n ...mapped.portals,\n );\n }\n // An explicit `custom_id` is the block's identity as the app gave it, so the host carries it\n // from the first render — on a server too (spec MARK-1). A list `withNodeParams` rebuilt from the\n // unit's own children goes back as separate children, as JSX passed them, so React does not check\n // it for keys as it would a list.\n // The units inside it take its category and previous category (MOVE-4).\n return createElement(\n tag,\n { ref: hostRef, className, ...(custom_id ? { [CONTENT_BLOCK_MARKER_ATTR]: custom_id } : {}) },\n createElement(\n BlockCategory.Provider,\n { value: unit },\n ...(children !== content && Array.isArray(children) ? children : [children]),\n ),\n );\n}\n\n/** The core's once-per-reason debug notice for a unit it did not register (VAR-7). */\nfunction warnUnnamed(unmarked: boolean): void {\n warnUnregistered(\n unmarked\n ? 'a value the build transform left as written: inside MathML or SVG, <script> or <style>, or an element that holds text only'\n : 'a value the build transform did not name: it is not enabled (langsys-js-react/vite, /babel or /next), or the value is a conditional, which it leaves as written',\n );\n}\n\nexport default Translate;\n","import { createElement, useEffect, useRef } from 'react';\nimport type { ReactNode } from 'react';\nimport {\n PHRASE_MARKER_ATTR,\n Phrase as VanillaPhrase,\n currentRequestScope,\n registerBlock,\n renderBlock,\n warnUnrenderedBlock,\n warnUnregistered,\n type BlockNode,\n type ParamPrimitive,\n} from 'langsys-js-typescript';\nimport { hasRuntimeValues, toBlockNodes, toReactNodes, withNodeParams } from '../block-nodes.js';\nimport { useT } from '../hooks.js';\nimport { useSeedScopeRunner } from './LangsysProvider.js';\nimport { BlockCategory, useUnitCategory } from './unit-category.js';\n\n/**\n * Props for the React `Phrase` component. Mirrors the Svelte component's props,\n * with Svelte's `class` renamed to React's idiomatic `className`.\n */\nexport interface PhraseProps {\n /** Category the phrase registers under (disambiguation for translators). */\n category?: string;\n /**\n * The category this content was registered under before it moved to `category` (MOVE-1):\n * `''` for none, absent for no move. Its translations follow it instead of being made, and\n * charged for, again; until the catalog holds it under `category`, the previous category's\n * entry renders and the host says so (MOVE-4, MOVE-5). Never part of its identity (MOVE-2),\n * and sent only on the registration a miss triggers (MOVE-3), so once the catalog has it the\n * prop does nothing and can be deleted whenever convenient.\n */\n previousCategory?: string | null;\n /**\n * Interpolation params. Write placeholders as `%n%` / `%name%` in the markup.\n * A bare `{n}` in JSX is an expression React evaluates before the SDK sees the\n * text, so the *value* lands in the captured phrase and each distinct value\n * becomes its own phrase to translate. `%n%` yields one stable phrase.\n */\n params?: Record<string, ParamPrimitive>;\n /** Host element tag. Defaults to `<span>`. */\n tag?: string;\n /** Class applied to the host element. */\n className?: string;\n children?: ReactNode;\n /**\n * Set by the build transform when every value of the phrase is marked (it holds a marker of its\n * own) and one in its translated text stands where no marker can (in a translated `<svg>`, or an\n * element that holds text only), so it is left as written: the phrase registers nothing (VAR-7)\n * and renders what the catalog holds.\n */\n 'data-ls-unnamed'?: string;\n}\n\n/**\n * React wrapper around the vanilla `Phrase` rich-text handler.\n *\n * Use it to keep a markup-bearing run as ONE translatable phrase — e.g. so a\n * count variable stays next to the noun it pluralizes:\n *\n * <Phrase category=\"ProductCard\" params={{ n: reviewCount }}>\n * Based on %n% <strong>reviews</strong>\n * </Phrase>\n *\n * Write placeholders as `%n%` (not bare `{n}`): in JSX a literal `{n}` is a JS\n * expression React evaluates before the SDK sees the text. `%n%` passes through\n * as literal text and the SDK normalizes it to canonical `{n}` at capture.\n *\n * The cost of getting this wrong is not a broken placeholder, it's catalog\n * churn. `<Phrase>` keys on the encoded phrase string, so the substituted value\n * becomes part of the key — a new phrase per distinct value, none reusable,\n * with the base locale rendering correctly throughout. Measured against the\n * shipped `encodeRichText`:\n *\n * {n} via JSX \"Based on 0 {m0o}reviews{m0c}\" (and 1, 2, … each new)\n * %n% placeholder \"Based on {n} {m0o}reviews{m0c}\" (stable for all values)\n *\n * The inline markup never reaches the translator — it's replaced with neutral\n * tokens and the real elements are reconstituted at render (see richtext.ts in\n * the base SDK). The host carries `data-ls-phrase` so a wrapping `<Translate>`\n * skips it and lets this handler own it.\n *\n * Keep children static (literal markup): the handler takes over the rendered\n * subtree. For values React owns and re-renders, pass them through `params`.\n */\nexport function Phrase({\n category: named,\n previousCategory: namedPrevious,\n params: given = {},\n tag = 'span',\n className,\n children: content,\n 'data-ls-unnamed': unmarked,\n}: PhraseProps) {\n // Inside a block that falls back, the block's category and previous category unless this unit\n // names its own (MOVE-4).\n const inherited = useUnitCategory(named, namedPrevious);\n const { category, previousCategory } = inherited;\n // A param that is an element or a list renders in its place, not as text.\n const { children, params } = withNodeParams(content, given ?? {});\n const t = useT(); // changes with the locale, the catalog and a route change (HINT-13)\n const hostRef = useRef<HTMLElement | null>(null);\n const instanceRef = useRef<VanillaPhrase>(undefined);\n const mapped = toBlockNodes(children);\n // The phrase host itself is the unit: the core renders it as one rich phrase, whose inline\n // elements a translation may reorder (MARK-4). Its elements' `source` indices count from 1.\n const unit: BlockNode[] | null = mapped.ok\n ? [{ tag, attrs: { [PHRASE_MARKER_ATTR]: '' }, children: mapped.nodes }]\n : null;\n // A value the build transform did not name (it is not enabled, or the value is a conditional)\n // has no name, so the unit registers nothing (VAR-7); what the catalog already holds still\n // renders. One inside a subtree that is not translated is not read: the phrase keys that\n // subtree as one empty pair (TOK-1).\n const unnamedValues = unmarked !== undefined || hasRuntimeValues(children, true);\n const moved = previousCategory === undefined || previousCategory === null ? {} : { previousCategory };\n const options = { category, ...moved, params, ...(unnamedValues ? { register: false } : {}) };\n // Under a <LangsysProvider>, the server and hydration renders read the request's scope.\n const inSeedScope = useSeedScopeRunner();\n const rendered = unit ? inSeedScope(() => renderBlock(unit, options)) : null;\n const scope = currentRequestScope();\n\n const register = (host?: Element) => {\n if (!unit) return;\n // With a value the transform did not name, `options` carries `register: false`: the call\n // registers nothing and still claims the host.\n if (unnamedValues) warnUnnamed(unmarked !== undefined);\n // `host` claims the element for this component, so an enclosing <Translate> that fell back\n // to the core's DOM class leaves it alone (MARK-2), and lets the core check the phrase's\n // ancestors for a resolved marker (GATE-10), walking from its parent: the phrase element's\n // own marker says it rendered a translation.\n // The promise is left unhandled on purpose, as in <Translate>: it rejects only under\n // `requireCredentials` with no credentials (WIRE-4), and that is how the core surfaces it.\n void registerBlock(unit, { ...options, host });\n };\n if (scope) {\n register();\n if (!mapped.ok) warnUnrenderedBlock(mapped.reason);\n }\n\n useEffect(() => {\n register(hostRef.current ?? undefined);\n // Registration is one-shot per call: it runs again whenever `t` changes.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [t, category, rendered ? JSON.stringify(unit) : null]);\n\n // Unmappable content only: the core's DOM class translates it after mount.\n useEffect(() => {\n const host = hostRef.current;\n if (mapped.ok || !host) return;\n if (unnamedValues) warnUnnamed(unmarked !== undefined);\n const instance = new VanillaPhrase(host, {\n category,\n ...moved,\n params,\n ...(unnamedValues ? { register: false } : {}),\n });\n instanceRef.current = instance;\n return () => {\n instance.destroy();\n instanceRef.current = undefined;\n };\n // A new `tag` replaces the host element, so the instance moves to the new one.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [mapped.ok, category, previousCategory, tag]);\n\n useEffect(() => {\n instanceRef.current?.setParams(params);\n });\n\n const host = rendered?.nodes[0];\n if (mapped.ok && host && 'tag' in host) {\n const { class: _class, ...hostAttrs } = host.attrs;\n return createElement(\n tag,\n { ref: hostRef, className, ...hostAttrs },\n ...toReactNodes(host.children, [createElement(tag), ...mapped.elements], [[], ...mapped.nested]),\n ...mapped.portals,\n );\n }\n // A list `withNodeParams` rebuilt from the unit's own children goes back as separate children, as\n // JSX passed them, so React does not check it for keys as it would a list.\n // The units inside it take its category and previous category (MOVE-4).\n return createElement(\n tag,\n { ref: hostRef, className, [PHRASE_MARKER_ATTR]: '' },\n createElement(\n BlockCategory.Provider,\n { value: inherited },\n ...(children !== content && Array.isArray(children) ? children : [children]),\n ),\n );\n}\n\n/** The core's once-per-reason debug notice for a unit it did not register (VAR-7). */\nfunction warnUnnamed(unmarked: boolean): void {\n warnUnregistered(\n unmarked\n ? 'a value the build transform left as written in a phrase whose values are all marked: in a translated <svg>, or an element that holds text only'\n : 'a value the build transform did not name: it is not enabled (langsys-js-react/vite, /babel or /next), or the value is a conditional, which it leaves as written',\n );\n}\n\nexport default Phrase;\n"]}
@@ -0,0 +1,8 @@
1
+ interface LoaderContext {
2
+ resourcePath: string;
3
+ async(): (err: Error | null, code?: string, map?: unknown) => void;
4
+ emitWarning?(warning: Error): void;
5
+ }
6
+ declare function langsysLoader(this: LoaderContext, source: string, map?: unknown): void;
7
+
8
+ export { langsysLoader as default };
@@ -0,0 +1,8 @@
1
+ interface LoaderContext {
2
+ resourcePath: string;
3
+ async(): (err: Error | null, code?: string, map?: unknown) => void;
4
+ emitWarning?(warning: Error): void;
5
+ }
6
+ declare function langsysLoader(this: LoaderContext, source: string, map?: unknown): void;
7
+
8
+ export { langsysLoader as default };