@sonenta/react-i18next 2.1.0 → 2.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/README.md +43 -0
- package/dist/index.cjs +180 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +90 -2
- package/dist/index.d.ts +90 -2
- package/dist/index.js +179 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -13,6 +13,24 @@ import { i18n } from 'i18next';
|
|
|
13
13
|
* the reactive viewport listener (web) — see `provider.tsx`.
|
|
14
14
|
*/
|
|
15
15
|
type Surface = "desktop" | "mobile" | "tablet";
|
|
16
|
+
/**
|
|
17
|
+
* A11y surfaces (#989 / task 994) — SEMANTIC accessibility variants of a key,
|
|
18
|
+
* delivered through the SAME sparse-overlay engine as device surfaces but
|
|
19
|
+
* applied ORTHOGONALLY to the visible text:
|
|
20
|
+
* - `aria_label` → an element's `aria-label` attribute
|
|
21
|
+
* - `alt_text` → an `<img alt>` (+ optional localized image via `$asset`)
|
|
22
|
+
* - `screen_reader` → verbose screen-reader-only (sr-only) text
|
|
23
|
+
* - `plain_language`→ simplified/clear-language (FALC) alternative rendering
|
|
24
|
+
*
|
|
25
|
+
* Unlike a device {@link Surface} (which replaces the visible `t()` value),
|
|
26
|
+
* a11y surfaces are read per-key via `i18n.aria()` / `alt()` / `a11y()` —
|
|
27
|
+
* EXCEPT `plain_language`, which the cognitive `plainLanguage` toggle layers
|
|
28
|
+
* over the visible `t()` output when enabled.
|
|
29
|
+
*/
|
|
30
|
+
type A11ySurface = "aria_label" | "alt_text" | "screen_reader" | "plain_language";
|
|
31
|
+
/** The fixed V1 a11y surface taxonomy (matches the backend `surfaceKinds`
|
|
32
|
+
* `a11y` set). Used to validate config + drive eager overlay loading. */
|
|
33
|
+
declare const A11Y_SURFACES: readonly A11ySurface[];
|
|
16
34
|
/** Min-width (px) thresholds that map a viewport width to a surface. A width
|
|
17
35
|
* `< mobile` → `mobile`; `< tablet` → `tablet`; otherwise `desktop`. Mirrors
|
|
18
36
|
* the common mobile-first breakpoint ladder. */
|
|
@@ -227,6 +245,23 @@ interface SonentaConfig {
|
|
|
227
245
|
* own `useWindowDimensions`. Ignored when `surface` is unset.
|
|
228
246
|
*/
|
|
229
247
|
surfaceBreakpoints?: SurfaceBreakpoints | boolean;
|
|
248
|
+
/**
|
|
249
|
+
* A11y surfaces (#989 / task 994) to eagerly load alongside the base
|
|
250
|
+
* bundles, so `i18n.aria()` / `alt()` / `a11y()` resolve synchronously in
|
|
251
|
+
* render. Each is a sparse `{ns}.{surface}.json` overlay applied
|
|
252
|
+
* ORTHOGONALLY to the visible text (NOT a `t()` replacement). Omit to
|
|
253
|
+
* disable a11y resolution. Include `"plain_language"` to power the
|
|
254
|
+
* {@link SonentaConfig.plainLanguage} toggle.
|
|
255
|
+
*/
|
|
256
|
+
a11ySurfaces?: A11ySurface[];
|
|
257
|
+
/**
|
|
258
|
+
* Start with the cognitive simplified-language ("plain language" / FALC)
|
|
259
|
+
* mode ON — when enabled, `t()` returns the `plain_language` overlay value
|
|
260
|
+
* for keys that have one (else the base text). Toggle at runtime via
|
|
261
|
+
* `i18n.setPlainLanguage(on)`. No effect unless `plain_language` is loaded
|
|
262
|
+
* (it is auto-included when this is `true`, or list it in `a11ySurfaces`).
|
|
263
|
+
*/
|
|
264
|
+
plainLanguage?: boolean;
|
|
230
265
|
/**
|
|
231
266
|
* Deployment environment. Drives where the SDK fetches translations from:
|
|
232
267
|
*
|
|
@@ -342,6 +377,43 @@ interface I18nInstance {
|
|
|
342
377
|
* asset (e.g. an icon/image ref) for the host to render.
|
|
343
378
|
*/
|
|
344
379
|
asset: (key: string, namespace?: Namespace) => AssetRef | undefined;
|
|
380
|
+
/**
|
|
381
|
+
* A11y (#989 / task 994) — the accessible NAME for a key (`aria_label`
|
|
382
|
+
* overlay), falling back to the visible `t(key)` text when no a11y override
|
|
383
|
+
* exists. Spread onto an element as `aria-label`. Requires `aria_label` in
|
|
384
|
+
* {@link SonentaConfig.a11ySurfaces}.
|
|
385
|
+
*/
|
|
386
|
+
aria: (key: string, namespace?: Namespace) => string;
|
|
387
|
+
/**
|
|
388
|
+
* A11y — the image alternative text for a key (`alt_text` overlay), falling
|
|
389
|
+
* back to the visible `t(key)` text. Pair with {@link I18nInstance.a11yAsset}
|
|
390
|
+
* for a localized image. Requires `alt_text` in `a11ySurfaces`.
|
|
391
|
+
*/
|
|
392
|
+
alt: (key: string, namespace?: Namespace) => string;
|
|
393
|
+
/**
|
|
394
|
+
* A11y — resolve an arbitrary a11y `surface` overlay for a key, or
|
|
395
|
+
* `undefined` when no override exists (use for `screen_reader` /
|
|
396
|
+
* `plain_language`, which should be OMITTED rather than fall back to the
|
|
397
|
+
* visible text). `aria` / `alt` are convenience wrappers that fall back.
|
|
398
|
+
*/
|
|
399
|
+
a11y: (key: string, surface: A11ySurface, namespace?: Namespace) => string | undefined;
|
|
400
|
+
/**
|
|
401
|
+
* A11y — the localized-image `$asset` ref carried by a key's `alt_text`
|
|
402
|
+
* overlay, or `undefined`. Lets the host swap the IMAGE per locale, not just
|
|
403
|
+
* its alt text.
|
|
404
|
+
*/
|
|
405
|
+
a11yAsset: (key: string, namespace?: Namespace) => AssetRef | undefined;
|
|
406
|
+
/**
|
|
407
|
+
* A11y — whether the cognitive simplified-language ("plain language") mode is
|
|
408
|
+
* ON. When `true`, `t()` returns the `plain_language` overlay value for keys
|
|
409
|
+
* that have one (else the base text).
|
|
410
|
+
*/
|
|
411
|
+
plainLanguage: boolean;
|
|
412
|
+
/**
|
|
413
|
+
* A11y — toggle simplified-language mode and re-render. Loads the
|
|
414
|
+
* `plain_language` overlays on first enable if not already configured.
|
|
415
|
+
*/
|
|
416
|
+
setPlainLanguage: (on: boolean) => Promise<void>;
|
|
345
417
|
/**
|
|
346
418
|
* Text direction of a locale (defaults to the active locale) — i18next
|
|
347
419
|
* parity. Sourced from the language catalog's `rtl` (variant → base
|
|
@@ -383,6 +455,22 @@ interface TranslationFunction {
|
|
|
383
455
|
/** Native form: `t('key', { defaultValue, ...interpolation })`. */
|
|
384
456
|
(key: string, options?: TranslationOptions): string;
|
|
385
457
|
}
|
|
458
|
+
/**
|
|
459
|
+
* The `t` returned by {@link useTranslation} — a {@link TranslationFunction}
|
|
460
|
+
* augmented with a11y accessors (#989 / task 994) so a host can write
|
|
461
|
+
* `t.aria(key)` / `t.alt(key)` / `t.a11y(key, surface)` right next to `t(key)`.
|
|
462
|
+
* They honor the hook's `defaultNamespace` and delegate to the engine.
|
|
463
|
+
*/
|
|
464
|
+
interface A11yTranslationFunction extends TranslationFunction {
|
|
465
|
+
/** Accessible name for `key` (`aria_label`), falling back to the visible
|
|
466
|
+
* text. Spread onto an element as `aria-label`. */
|
|
467
|
+
aria: (key: string, namespace?: Namespace) => string;
|
|
468
|
+
/** Image alt text for `key` (`alt_text`), falling back to the visible text. */
|
|
469
|
+
alt: (key: string, namespace?: Namespace) => string;
|
|
470
|
+
/** Resolve an arbitrary a11y `surface` overlay for `key`, or `undefined`
|
|
471
|
+
* when no override exists (e.g. `screen_reader` / `plain_language`). */
|
|
472
|
+
a11y: (key: string, surface: A11ySurface, namespace?: Namespace) => string | undefined;
|
|
473
|
+
}
|
|
386
474
|
|
|
387
475
|
interface SonentaProviderProps extends SonentaConfig {
|
|
388
476
|
children: ReactNode;
|
|
@@ -390,7 +478,7 @@ interface SonentaProviderProps extends SonentaConfig {
|
|
|
390
478
|
declare function SonentaProvider({ children, ...config }: SonentaProviderProps): react_jsx_runtime.JSX.Element;
|
|
391
479
|
|
|
392
480
|
interface UseTranslationResult {
|
|
393
|
-
t:
|
|
481
|
+
t: A11yTranslationFunction;
|
|
394
482
|
i18n: I18nInstance;
|
|
395
483
|
}
|
|
396
484
|
/** React hook — returns `{ t, i18n }`. Optional `defaultNamespace` lets you
|
|
@@ -537,4 +625,4 @@ declare class KeyRegistry {
|
|
|
537
625
|
/** Process-wide singleton — there is exactly one on-screen registry. */
|
|
538
626
|
declare const keyRegistry: KeyRegistry;
|
|
539
627
|
|
|
540
|
-
export { type AssetRef, DEFAULT_SURFACE_BREAKPOINTS, type DeclaredKey, type I18nInstance, type LanguageMeta, type Locale, type MissingHandlerMode, type MissingKeyEvent, type Namespace, type SonentaConfig, type SonentaPlugin, type SonentaPluginContext, SonentaProvider, type Surface, type SurfaceBreakpoints, Trans, type TranslationFunction, type TranslationOptions, type Transport, type SonentaConfig as VerbumiaConfig, type SonentaPlugin as VerbumiaPlugin, type SonentaPluginContext as VerbumiaPluginContext, SonentaProvider as VerbumiaProvider, defaultTransport, getI18n, getI18nSafe, keyRegistry, logTransport, surfaceForWidth, t, useTranslation };
|
|
628
|
+
export { A11Y_SURFACES, type A11ySurface, type AssetRef, DEFAULT_SURFACE_BREAKPOINTS, type DeclaredKey, type I18nInstance, type LanguageMeta, type Locale, type MissingHandlerMode, type MissingKeyEvent, type Namespace, type SonentaConfig, type SonentaPlugin, type SonentaPluginContext, SonentaProvider, type Surface, type SurfaceBreakpoints, Trans, type TranslationFunction, type TranslationOptions, type Transport, type SonentaConfig as VerbumiaConfig, type SonentaPlugin as VerbumiaPlugin, type SonentaPluginContext as VerbumiaPluginContext, SonentaProvider as VerbumiaProvider, defaultTransport, getI18n, getI18nSafe, keyRegistry, logTransport, surfaceForWidth, t, useTranslation };
|
package/dist/index.d.ts
CHANGED
|
@@ -13,6 +13,24 @@ import { i18n } from 'i18next';
|
|
|
13
13
|
* the reactive viewport listener (web) — see `provider.tsx`.
|
|
14
14
|
*/
|
|
15
15
|
type Surface = "desktop" | "mobile" | "tablet";
|
|
16
|
+
/**
|
|
17
|
+
* A11y surfaces (#989 / task 994) — SEMANTIC accessibility variants of a key,
|
|
18
|
+
* delivered through the SAME sparse-overlay engine as device surfaces but
|
|
19
|
+
* applied ORTHOGONALLY to the visible text:
|
|
20
|
+
* - `aria_label` → an element's `aria-label` attribute
|
|
21
|
+
* - `alt_text` → an `<img alt>` (+ optional localized image via `$asset`)
|
|
22
|
+
* - `screen_reader` → verbose screen-reader-only (sr-only) text
|
|
23
|
+
* - `plain_language`→ simplified/clear-language (FALC) alternative rendering
|
|
24
|
+
*
|
|
25
|
+
* Unlike a device {@link Surface} (which replaces the visible `t()` value),
|
|
26
|
+
* a11y surfaces are read per-key via `i18n.aria()` / `alt()` / `a11y()` —
|
|
27
|
+
* EXCEPT `plain_language`, which the cognitive `plainLanguage` toggle layers
|
|
28
|
+
* over the visible `t()` output when enabled.
|
|
29
|
+
*/
|
|
30
|
+
type A11ySurface = "aria_label" | "alt_text" | "screen_reader" | "plain_language";
|
|
31
|
+
/** The fixed V1 a11y surface taxonomy (matches the backend `surfaceKinds`
|
|
32
|
+
* `a11y` set). Used to validate config + drive eager overlay loading. */
|
|
33
|
+
declare const A11Y_SURFACES: readonly A11ySurface[];
|
|
16
34
|
/** Min-width (px) thresholds that map a viewport width to a surface. A width
|
|
17
35
|
* `< mobile` → `mobile`; `< tablet` → `tablet`; otherwise `desktop`. Mirrors
|
|
18
36
|
* the common mobile-first breakpoint ladder. */
|
|
@@ -227,6 +245,23 @@ interface SonentaConfig {
|
|
|
227
245
|
* own `useWindowDimensions`. Ignored when `surface` is unset.
|
|
228
246
|
*/
|
|
229
247
|
surfaceBreakpoints?: SurfaceBreakpoints | boolean;
|
|
248
|
+
/**
|
|
249
|
+
* A11y surfaces (#989 / task 994) to eagerly load alongside the base
|
|
250
|
+
* bundles, so `i18n.aria()` / `alt()` / `a11y()` resolve synchronously in
|
|
251
|
+
* render. Each is a sparse `{ns}.{surface}.json` overlay applied
|
|
252
|
+
* ORTHOGONALLY to the visible text (NOT a `t()` replacement). Omit to
|
|
253
|
+
* disable a11y resolution. Include `"plain_language"` to power the
|
|
254
|
+
* {@link SonentaConfig.plainLanguage} toggle.
|
|
255
|
+
*/
|
|
256
|
+
a11ySurfaces?: A11ySurface[];
|
|
257
|
+
/**
|
|
258
|
+
* Start with the cognitive simplified-language ("plain language" / FALC)
|
|
259
|
+
* mode ON — when enabled, `t()` returns the `plain_language` overlay value
|
|
260
|
+
* for keys that have one (else the base text). Toggle at runtime via
|
|
261
|
+
* `i18n.setPlainLanguage(on)`. No effect unless `plain_language` is loaded
|
|
262
|
+
* (it is auto-included when this is `true`, or list it in `a11ySurfaces`).
|
|
263
|
+
*/
|
|
264
|
+
plainLanguage?: boolean;
|
|
230
265
|
/**
|
|
231
266
|
* Deployment environment. Drives where the SDK fetches translations from:
|
|
232
267
|
*
|
|
@@ -342,6 +377,43 @@ interface I18nInstance {
|
|
|
342
377
|
* asset (e.g. an icon/image ref) for the host to render.
|
|
343
378
|
*/
|
|
344
379
|
asset: (key: string, namespace?: Namespace) => AssetRef | undefined;
|
|
380
|
+
/**
|
|
381
|
+
* A11y (#989 / task 994) — the accessible NAME for a key (`aria_label`
|
|
382
|
+
* overlay), falling back to the visible `t(key)` text when no a11y override
|
|
383
|
+
* exists. Spread onto an element as `aria-label`. Requires `aria_label` in
|
|
384
|
+
* {@link SonentaConfig.a11ySurfaces}.
|
|
385
|
+
*/
|
|
386
|
+
aria: (key: string, namespace?: Namespace) => string;
|
|
387
|
+
/**
|
|
388
|
+
* A11y — the image alternative text for a key (`alt_text` overlay), falling
|
|
389
|
+
* back to the visible `t(key)` text. Pair with {@link I18nInstance.a11yAsset}
|
|
390
|
+
* for a localized image. Requires `alt_text` in `a11ySurfaces`.
|
|
391
|
+
*/
|
|
392
|
+
alt: (key: string, namespace?: Namespace) => string;
|
|
393
|
+
/**
|
|
394
|
+
* A11y — resolve an arbitrary a11y `surface` overlay for a key, or
|
|
395
|
+
* `undefined` when no override exists (use for `screen_reader` /
|
|
396
|
+
* `plain_language`, which should be OMITTED rather than fall back to the
|
|
397
|
+
* visible text). `aria` / `alt` are convenience wrappers that fall back.
|
|
398
|
+
*/
|
|
399
|
+
a11y: (key: string, surface: A11ySurface, namespace?: Namespace) => string | undefined;
|
|
400
|
+
/**
|
|
401
|
+
* A11y — the localized-image `$asset` ref carried by a key's `alt_text`
|
|
402
|
+
* overlay, or `undefined`. Lets the host swap the IMAGE per locale, not just
|
|
403
|
+
* its alt text.
|
|
404
|
+
*/
|
|
405
|
+
a11yAsset: (key: string, namespace?: Namespace) => AssetRef | undefined;
|
|
406
|
+
/**
|
|
407
|
+
* A11y — whether the cognitive simplified-language ("plain language") mode is
|
|
408
|
+
* ON. When `true`, `t()` returns the `plain_language` overlay value for keys
|
|
409
|
+
* that have one (else the base text).
|
|
410
|
+
*/
|
|
411
|
+
plainLanguage: boolean;
|
|
412
|
+
/**
|
|
413
|
+
* A11y — toggle simplified-language mode and re-render. Loads the
|
|
414
|
+
* `plain_language` overlays on first enable if not already configured.
|
|
415
|
+
*/
|
|
416
|
+
setPlainLanguage: (on: boolean) => Promise<void>;
|
|
345
417
|
/**
|
|
346
418
|
* Text direction of a locale (defaults to the active locale) — i18next
|
|
347
419
|
* parity. Sourced from the language catalog's `rtl` (variant → base
|
|
@@ -383,6 +455,22 @@ interface TranslationFunction {
|
|
|
383
455
|
/** Native form: `t('key', { defaultValue, ...interpolation })`. */
|
|
384
456
|
(key: string, options?: TranslationOptions): string;
|
|
385
457
|
}
|
|
458
|
+
/**
|
|
459
|
+
* The `t` returned by {@link useTranslation} — a {@link TranslationFunction}
|
|
460
|
+
* augmented with a11y accessors (#989 / task 994) so a host can write
|
|
461
|
+
* `t.aria(key)` / `t.alt(key)` / `t.a11y(key, surface)` right next to `t(key)`.
|
|
462
|
+
* They honor the hook's `defaultNamespace` and delegate to the engine.
|
|
463
|
+
*/
|
|
464
|
+
interface A11yTranslationFunction extends TranslationFunction {
|
|
465
|
+
/** Accessible name for `key` (`aria_label`), falling back to the visible
|
|
466
|
+
* text. Spread onto an element as `aria-label`. */
|
|
467
|
+
aria: (key: string, namespace?: Namespace) => string;
|
|
468
|
+
/** Image alt text for `key` (`alt_text`), falling back to the visible text. */
|
|
469
|
+
alt: (key: string, namespace?: Namespace) => string;
|
|
470
|
+
/** Resolve an arbitrary a11y `surface` overlay for `key`, or `undefined`
|
|
471
|
+
* when no override exists (e.g. `screen_reader` / `plain_language`). */
|
|
472
|
+
a11y: (key: string, surface: A11ySurface, namespace?: Namespace) => string | undefined;
|
|
473
|
+
}
|
|
386
474
|
|
|
387
475
|
interface SonentaProviderProps extends SonentaConfig {
|
|
388
476
|
children: ReactNode;
|
|
@@ -390,7 +478,7 @@ interface SonentaProviderProps extends SonentaConfig {
|
|
|
390
478
|
declare function SonentaProvider({ children, ...config }: SonentaProviderProps): react_jsx_runtime.JSX.Element;
|
|
391
479
|
|
|
392
480
|
interface UseTranslationResult {
|
|
393
|
-
t:
|
|
481
|
+
t: A11yTranslationFunction;
|
|
394
482
|
i18n: I18nInstance;
|
|
395
483
|
}
|
|
396
484
|
/** React hook — returns `{ t, i18n }`. Optional `defaultNamespace` lets you
|
|
@@ -537,4 +625,4 @@ declare class KeyRegistry {
|
|
|
537
625
|
/** Process-wide singleton — there is exactly one on-screen registry. */
|
|
538
626
|
declare const keyRegistry: KeyRegistry;
|
|
539
627
|
|
|
540
|
-
export { type AssetRef, DEFAULT_SURFACE_BREAKPOINTS, type DeclaredKey, type I18nInstance, type LanguageMeta, type Locale, type MissingHandlerMode, type MissingKeyEvent, type Namespace, type SonentaConfig, type SonentaPlugin, type SonentaPluginContext, SonentaProvider, type Surface, type SurfaceBreakpoints, Trans, type TranslationFunction, type TranslationOptions, type Transport, type SonentaConfig as VerbumiaConfig, type SonentaPlugin as VerbumiaPlugin, type SonentaPluginContext as VerbumiaPluginContext, SonentaProvider as VerbumiaProvider, defaultTransport, getI18n, getI18nSafe, keyRegistry, logTransport, surfaceForWidth, t, useTranslation };
|
|
628
|
+
export { A11Y_SURFACES, type A11ySurface, type AssetRef, DEFAULT_SURFACE_BREAKPOINTS, type DeclaredKey, type I18nInstance, type LanguageMeta, type Locale, type MissingHandlerMode, type MissingKeyEvent, type Namespace, type SonentaConfig, type SonentaPlugin, type SonentaPluginContext, SonentaProvider, type Surface, type SurfaceBreakpoints, Trans, type TranslationFunction, type TranslationOptions, type Transport, type SonentaConfig as VerbumiaConfig, type SonentaPlugin as VerbumiaPlugin, type SonentaPluginContext as VerbumiaPluginContext, SonentaProvider as VerbumiaProvider, defaultTransport, getI18n, getI18nSafe, keyRegistry, logTransport, surfaceForWidth, t, useTranslation };
|
package/dist/index.js
CHANGED
|
@@ -210,7 +210,7 @@ function flattenPlurals(tree, locale) {
|
|
|
210
210
|
|
|
211
211
|
// src/transport.ts
|
|
212
212
|
var SDK_LIB = "@sonenta/react-i18next";
|
|
213
|
-
var SDK_VER = true ? "2.
|
|
213
|
+
var SDK_VER = true ? "2.2.0" : "0.0.0-dev";
|
|
214
214
|
function defaultTransport(opts) {
|
|
215
215
|
return async (batch) => {
|
|
216
216
|
if (!batch.length) return;
|
|
@@ -416,6 +416,14 @@ var SonentaI18n = class {
|
|
|
416
416
|
// Resolved asset refs (#911 minimal v1), keyed `${locale}/${ns}/${keyPath}`
|
|
417
417
|
// for the CURRENT composition (base assets, then overlay assets override).
|
|
418
418
|
_assets = /* @__PURE__ */ new Map();
|
|
419
|
+
// A11y surfaces (#989 / task 994). Each configured a11y surface S is loaded
|
|
420
|
+
// as its OWN i18next namespace `${ns}__${S}` (sparse `{ns}.{S}.json`), so the
|
|
421
|
+
// accessors resolve through i18next's native locale-fallback + nested-key
|
|
422
|
+
// logic without touching the visible-text bundle. `_a11yAssets` carries the
|
|
423
|
+
// `alt_text` `$asset` refs, keyed `${locale}/${ns}/${keyPath}#${surface}`.
|
|
424
|
+
_a11ySurfaces = /* @__PURE__ */ new Set();
|
|
425
|
+
_plainLanguage = false;
|
|
426
|
+
_a11yAssets = /* @__PURE__ */ new Map();
|
|
419
427
|
_missing;
|
|
420
428
|
_listeners = /* @__PURE__ */ new Set();
|
|
421
429
|
// Stable snapshot reference for useSyncExternalStore. Rebuilt ONLY in _notify
|
|
@@ -443,6 +451,9 @@ var SonentaI18n = class {
|
|
|
443
451
|
this.locale = config.defaultLocale;
|
|
444
452
|
this.fallbackLng = config.fallbackLng;
|
|
445
453
|
this._surface = config.surface;
|
|
454
|
+
for (const s of config.a11ySurfaces ?? []) this._a11ySurfaces.add(s);
|
|
455
|
+
this._plainLanguage = config.plainLanguage === true;
|
|
456
|
+
if (this._plainLanguage) this._a11ySurfaces.add("plain_language");
|
|
446
457
|
let keySeparator = ".";
|
|
447
458
|
if (config.keySeparator !== void 0) {
|
|
448
459
|
keySeparator = config.keySeparator;
|
|
@@ -627,6 +638,12 @@ var SonentaI18n = class {
|
|
|
627
638
|
surface: this._surface,
|
|
628
639
|
setSurface: this.setSurface,
|
|
629
640
|
asset: this.asset,
|
|
641
|
+
aria: this.aria,
|
|
642
|
+
alt: this.alt,
|
|
643
|
+
a11y: this.a11y,
|
|
644
|
+
a11yAsset: this.a11yAsset,
|
|
645
|
+
plainLanguage: this._plainLanguage,
|
|
646
|
+
setPlainLanguage: this.setPlainLanguage,
|
|
630
647
|
dir: this.dir,
|
|
631
648
|
nativeName: this.nativeName,
|
|
632
649
|
languageMeta: this.languageMeta,
|
|
@@ -868,9 +885,96 @@ var SonentaI18n = class {
|
|
|
868
885
|
}
|
|
869
886
|
return void 0;
|
|
870
887
|
};
|
|
888
|
+
// ---- A11y (#989 / task 994) ----
|
|
889
|
+
/** Split a possibly-`ns:key` string into `{ ns, bareKey }`, honoring the
|
|
890
|
+
* configured nsSeparator (mirrors {@link asset}). */
|
|
891
|
+
_splitKey(key, namespace) {
|
|
892
|
+
let ns = namespace ?? this.defaultNamespace;
|
|
893
|
+
let bareKey = key;
|
|
894
|
+
if (typeof this._nsSeparator === "string" && this._nsSeparator) {
|
|
895
|
+
const idx = key.indexOf(this._nsSeparator);
|
|
896
|
+
if (idx > 0) {
|
|
897
|
+
ns = key.slice(0, idx);
|
|
898
|
+
bareKey = key.slice(idx + this._nsSeparator.length);
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
return { ns, bareKey };
|
|
902
|
+
}
|
|
903
|
+
/** Resolve an a11y `surface` override for `key`, or `undefined` when none
|
|
904
|
+
* exists (the namespace is sparse). Goes through i18next so the locale
|
|
905
|
+
* fallback chain + nested keys + plurals apply. */
|
|
906
|
+
a11y = (key, surface, namespace) => {
|
|
907
|
+
if (!this._a11ySurfaces.has(surface)) return void 0;
|
|
908
|
+
const { ns, bareKey } = this._splitKey(key, namespace);
|
|
909
|
+
const a11yNs = this._a11yNs(ns, surface);
|
|
910
|
+
if (!this._i18next.exists(bareKey, { ns: a11yNs })) return void 0;
|
|
911
|
+
return this._i18next.t(bareKey, { ns: a11yNs });
|
|
912
|
+
};
|
|
913
|
+
/** Accessible name for `key` (`aria_label` overlay) — falls back to the
|
|
914
|
+
* visible `t(key)` text when no override exists. Spread as `aria-label`. */
|
|
915
|
+
aria = (key, namespace) => {
|
|
916
|
+
const v = this.a11y(key, "aria_label", namespace);
|
|
917
|
+
if (v !== void 0) return v;
|
|
918
|
+
const { ns, bareKey } = this._splitKey(key, namespace);
|
|
919
|
+
return this._i18next.t(bareKey, { ns });
|
|
920
|
+
};
|
|
921
|
+
/** Image alt text for `key` (`alt_text` overlay) — falls back to the visible
|
|
922
|
+
* `t(key)` text. Pair with {@link a11yAsset} for a localized image. */
|
|
923
|
+
alt = (key, namespace) => {
|
|
924
|
+
const v = this.a11y(key, "alt_text", namespace);
|
|
925
|
+
if (v !== void 0) return v;
|
|
926
|
+
const { ns, bareKey } = this._splitKey(key, namespace);
|
|
927
|
+
return this._i18next.t(bareKey, { ns });
|
|
928
|
+
};
|
|
929
|
+
/** Localized-image `$asset` ref from a key's `alt_text` overlay, or
|
|
930
|
+
* `undefined`. Walks the locale fallback chain like `t()` would. */
|
|
931
|
+
a11yAsset = (key, namespace) => {
|
|
932
|
+
const { ns, bareKey } = this._splitKey(key, namespace);
|
|
933
|
+
for (const loc of this._resolutionChain(this.locale)) {
|
|
934
|
+
const ref = this._a11yAssets.get(`${loc}/${ns}/${bareKey}#alt_text`);
|
|
935
|
+
if (ref) return ref;
|
|
936
|
+
}
|
|
937
|
+
return void 0;
|
|
938
|
+
};
|
|
939
|
+
get plainLanguage() {
|
|
940
|
+
return this._plainLanguage;
|
|
941
|
+
}
|
|
942
|
+
/** Toggle simplified-language ("plain language" / FALC) mode (#989). When
|
|
943
|
+
* on, `t()` returns the `plain_language` overlay value for keys that have
|
|
944
|
+
* one. Loads the `plain_language` overlays on first enable if they were not
|
|
945
|
+
* configured, then re-renders. No-op when unchanged. */
|
|
946
|
+
setPlainLanguage = async (on) => {
|
|
947
|
+
if (on === this._plainLanguage) return;
|
|
948
|
+
this._plainLanguage = on;
|
|
949
|
+
if (on && !this._a11ySurfaces.has("plain_language")) {
|
|
950
|
+
this._a11ySurfaces.add("plain_language");
|
|
951
|
+
const targets = [];
|
|
952
|
+
for (const k of this._attempted) {
|
|
953
|
+
const parts = k.split("/");
|
|
954
|
+
const locale = parts[1];
|
|
955
|
+
const ns = parts[2];
|
|
956
|
+
if (locale && ns) targets.push({ locale, ns });
|
|
957
|
+
}
|
|
958
|
+
await Promise.all(
|
|
959
|
+
targets.map((t2) => this._loadA11yOverlays(t2.locale, t2.ns))
|
|
960
|
+
);
|
|
961
|
+
}
|
|
962
|
+
this._notify();
|
|
963
|
+
this._signalLoaded();
|
|
964
|
+
};
|
|
871
965
|
// ---- Translation ----
|
|
872
966
|
t = (key, optionsOrDefault, maybeOptions) => {
|
|
873
967
|
const options = typeof optionsOrDefault === "string" ? { ...maybeOptions ?? {}, defaultValue: optionsOrDefault } : optionsOrDefault;
|
|
968
|
+
if (this._plainLanguage && this._a11ySurfaces.has("plain_language")) {
|
|
969
|
+
const { ns, bareKey } = this._splitKey(key);
|
|
970
|
+
const plainNs = this._a11yNs(ns, "plain_language");
|
|
971
|
+
if (this._i18next.exists(bareKey, { ...options ?? {}, ns: plainNs })) {
|
|
972
|
+
return this._i18next.t(bareKey, {
|
|
973
|
+
...options ?? {},
|
|
974
|
+
ns: plainNs
|
|
975
|
+
});
|
|
976
|
+
}
|
|
977
|
+
}
|
|
874
978
|
const literal = this._probeLiteral(key);
|
|
875
979
|
if (literal !== void 0) {
|
|
876
980
|
const interpolator = this._i18next.services?.interpolator;
|
|
@@ -1021,6 +1125,67 @@ var SonentaI18n = class {
|
|
|
1021
1125
|
this._attempted.add(cacheKey);
|
|
1022
1126
|
}
|
|
1023
1127
|
await this._composeBundle(locale, ns, fetchImpl, opts.bust);
|
|
1128
|
+
await this._loadA11yOverlays(locale, ns, fetchImpl, opts.bust);
|
|
1129
|
+
}
|
|
1130
|
+
/**
|
|
1131
|
+
* Load every configured a11y surface overlay (#989 / task 994) for
|
|
1132
|
+
* (locale, ns) into a DEDICATED i18next namespace `${ns}__${surface}`, so
|
|
1133
|
+
* `aria()` / `alt()` / `a11y()` resolve them through i18next (locale
|
|
1134
|
+
* fallback + nested keys + plurals) WITHOUT polluting the visible-text
|
|
1135
|
+
* bundle. Sparse + best-effort: an absent overlay registers `{}` and the
|
|
1136
|
+
* accessor reports "no override".
|
|
1137
|
+
*/
|
|
1138
|
+
async _loadA11yOverlays(locale, ns, fetchImpl = fetch, bust = false) {
|
|
1139
|
+
if (this._a11ySurfaces.size === 0) return;
|
|
1140
|
+
await Promise.all(
|
|
1141
|
+
[...this._a11ySurfaces].map(async (surface) => {
|
|
1142
|
+
const overlay = await this._loadOverlay(
|
|
1143
|
+
locale,
|
|
1144
|
+
ns,
|
|
1145
|
+
surface,
|
|
1146
|
+
fetchImpl,
|
|
1147
|
+
bust
|
|
1148
|
+
);
|
|
1149
|
+
const tree = this._unwrapA11y(overlay, locale, ns, surface);
|
|
1150
|
+
this._i18next.addResourceBundle(
|
|
1151
|
+
locale,
|
|
1152
|
+
this._a11yNs(ns, surface),
|
|
1153
|
+
flattenPlurals(tree, locale),
|
|
1154
|
+
false,
|
|
1155
|
+
true
|
|
1156
|
+
);
|
|
1157
|
+
})
|
|
1158
|
+
);
|
|
1159
|
+
}
|
|
1160
|
+
/** i18next namespace that backs an a11y surface overlay for `ns`. */
|
|
1161
|
+
_a11yNs(ns, surface) {
|
|
1162
|
+
return `${ns}__${surface}`;
|
|
1163
|
+
}
|
|
1164
|
+
/** Like {@link _unwrapAssets} but records `$asset` refs into `_a11yAssets`
|
|
1165
|
+
* (keyed with the `#${surface}` suffix) instead of the visible-text
|
|
1166
|
+
* `_assets`, so `alt_text` images don't collide with device-surface assets. */
|
|
1167
|
+
_unwrapA11y(tree, locale, ns, surface) {
|
|
1168
|
+
const sep = typeof this._i18next.options.keySeparator === "string" ? this._i18next.options.keySeparator : ".";
|
|
1169
|
+
const walk = (node, path) => {
|
|
1170
|
+
if (!node || typeof node !== "object") return node;
|
|
1171
|
+
const obj = node;
|
|
1172
|
+
if (Object.prototype.hasOwnProperty.call(obj, "$value")) {
|
|
1173
|
+
const a = obj.$asset;
|
|
1174
|
+
if (a && typeof a.kind === "string" && typeof a.ref === "string") {
|
|
1175
|
+
this._a11yAssets.set(
|
|
1176
|
+
`${locale}/${ns}/${path.join(sep)}#${surface}`,
|
|
1177
|
+
{ kind: a.kind, ref: a.ref }
|
|
1178
|
+
);
|
|
1179
|
+
}
|
|
1180
|
+
return obj.$value;
|
|
1181
|
+
}
|
|
1182
|
+
const out = {};
|
|
1183
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
1184
|
+
out[k] = walk(v, [...path, k]);
|
|
1185
|
+
}
|
|
1186
|
+
return out;
|
|
1187
|
+
};
|
|
1188
|
+
return walk(tree, []);
|
|
1024
1189
|
}
|
|
1025
1190
|
/**
|
|
1026
1191
|
* Compose the i18next bundle for (locale, ns) as base ⊕ surface overlay
|
|
@@ -1148,6 +1313,12 @@ function t(key, optionsOrDefault, maybeOptions) {
|
|
|
1148
1313
|
}
|
|
1149
1314
|
|
|
1150
1315
|
// src/surface.ts
|
|
1316
|
+
var A11Y_SURFACES = [
|
|
1317
|
+
"aria_label",
|
|
1318
|
+
"alt_text",
|
|
1319
|
+
"screen_reader",
|
|
1320
|
+
"plain_language"
|
|
1321
|
+
];
|
|
1151
1322
|
var DEFAULT_SURFACE_BREAKPOINTS = {
|
|
1152
1323
|
mobile: 640,
|
|
1153
1324
|
tablet: 1024
|
|
@@ -1231,7 +1402,12 @@ function useTranslation(defaultNamespace) {
|
|
|
1231
1402
|
);
|
|
1232
1403
|
return i18n.t(fullKey, optionsOrDefault, maybeOptions);
|
|
1233
1404
|
};
|
|
1234
|
-
|
|
1405
|
+
const withNs = (key) => defaultNamespace && !key.includes(":") ? `${defaultNamespace}:${key}` : key;
|
|
1406
|
+
const aug = fn;
|
|
1407
|
+
aug.aria = (key, namespace) => i18n.aria(withNs(key), namespace);
|
|
1408
|
+
aug.alt = (key, namespace) => i18n.alt(withNs(key), namespace);
|
|
1409
|
+
aug.a11y = (key, surface, namespace) => i18n.a11y(withNs(key), surface, namespace);
|
|
1410
|
+
return aug;
|
|
1235
1411
|
}, [i18n, defaultNamespace]);
|
|
1236
1412
|
useEffect2(() => {
|
|
1237
1413
|
keyRegistry._set(tokenRef.current, renderedRef.current);
|
|
@@ -1283,6 +1459,7 @@ function splitOnComponents(text, components) {
|
|
|
1283
1459
|
return out;
|
|
1284
1460
|
}
|
|
1285
1461
|
export {
|
|
1462
|
+
A11Y_SURFACES,
|
|
1286
1463
|
DEFAULT_SURFACE_BREAKPOINTS,
|
|
1287
1464
|
SonentaProvider,
|
|
1288
1465
|
Trans,
|