@cosmicdrift/kumiko-renderer 0.130.0 → 0.130.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-renderer",
3
- "version": "0.130.0",
3
+ "version": "0.130.2",
4
4
  "description": "Platform-agnostic React renderer for Kumiko screens. Contains the shared logic — primitives-contract, hooks, KumikoScreen, navigation & SSE abstractions — that any platform-specific renderer (web, native) composes. No DOM, no EventSource, no react-dom.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -15,8 +15,8 @@
15
15
  }
16
16
  },
17
17
  "dependencies": {
18
- "@cosmicdrift/kumiko-framework": "0.130.0",
19
- "@cosmicdrift/kumiko-headless": "0.130.0",
18
+ "@cosmicdrift/kumiko-framework": "0.130.2",
19
+ "@cosmicdrift/kumiko-headless": "0.130.2",
20
20
  "react": "^19.2.6"
21
21
  },
22
22
  "devDependencies": {
@@ -6,6 +6,7 @@ import {
6
6
  createStaticLocaleResolver,
7
7
  LocaleProvider,
8
8
  type TranslationsByLocale,
9
+ translationsByLocaleFromKeys,
9
10
  useLocale,
10
11
  useTranslation,
11
12
  } from "../i18n";
@@ -146,6 +147,23 @@ describe("useTranslation — referential stability", () => {
146
147
  expect((Probe as unknown as { lastT?: unknown }).lastT).toBe(firstT);
147
148
  });
148
149
  });
150
+ describe("translationsByLocaleFromKeys", () => {
151
+ test("pivots key-first source to locale-first bundles losslessly", () => {
152
+ const source = {
153
+ "app:nav.home": { de: "Start", en: "Home" },
154
+ "app:nav.settings": { de: "Einstellungen", en: "Settings" },
155
+ };
156
+ const byLocale = translationsByLocaleFromKeys(source);
157
+ expect(byLocale["de"]).toEqual({
158
+ "app:nav.home": "Start",
159
+ "app:nav.settings": "Einstellungen",
160
+ });
161
+ expect(byLocale["en"]).toEqual({
162
+ "app:nav.home": "Home",
163
+ "app:nav.settings": "Settings",
164
+ });
165
+ });
166
+ });
149
167
  describe("useLocale", () => {
150
168
  test("returns the resolver", () => {
151
169
  const resolver = createStaticLocaleResolver({ locale: "de" });
@@ -48,6 +48,7 @@ export const kumikoDefaultTranslations: TranslationsByLocale = {
48
48
  // Nav — Sidebar Tree (Toggle-aria-Labels).
49
49
  "kumiko.nav.expand": "Aufklappen",
50
50
  "kumiko.nav.collapse": "Zuklappen",
51
+ "kumiko.nav.search": "Navigation durchsuchen…",
51
52
 
52
53
  // Dialog — Confirm-Buttons + Close-aria-Label.
53
54
  "kumiko.dialog.confirm": "Bestätigen",
@@ -151,6 +152,7 @@ export const kumikoDefaultTranslations: TranslationsByLocale = {
151
152
 
152
153
  "kumiko.nav.expand": "Expand",
153
154
  "kumiko.nav.collapse": "Collapse",
155
+ "kumiko.nav.search": "Search navigation…",
154
156
 
155
157
  "kumiko.dialog.confirm": "Confirm",
156
158
  "kumiko.dialog.cancel": "Cancel",
package/src/i18n.tsx CHANGED
@@ -32,6 +32,22 @@ export type TranslationBundle = Readonly<Record<string, string>>;
32
32
  /** Map von Locale-Code (BCP-47, z.B. `"de"`, `"en-US"`) → Bundle. */
33
33
  export type TranslationsByLocale = Readonly<Record<string, TranslationBundle>>;
34
34
 
35
+ /** Key-first shape for `r.translations({ keys })` — each key maps locale → string. */
36
+ export type TranslationsByKey = Readonly<Record<string, Readonly<Record<string, string>>>>;
37
+
38
+ /** Pivot key-first server translations to locale-first client bundles. */
39
+ export function translationsByLocaleFromKeys(source: TranslationsByKey): TranslationsByLocale {
40
+ const out: Record<string, Record<string, string>> = {};
41
+ for (const [key, byLocale] of Object.entries(source)) {
42
+ for (const [locale, value] of Object.entries(byLocale)) {
43
+ const bucket = out[locale] ?? {};
44
+ bucket[key] = value;
45
+ out[locale] = bucket;
46
+ }
47
+ }
48
+ return out;
49
+ }
50
+
35
51
  /** Merged zwei TranslationsByLocale-Maps — der override gewinnt pro Key,
36
52
  * die Locales werden zusammengeführt. Standard-Baustein für Client-
37
53
  * Plugins, die App-Overrides über ihre Default-Bundles legen. */
package/src/index.ts CHANGED
@@ -77,12 +77,14 @@ export { useStore, useStoreSelector } from "./hooks/use-store";
77
77
  export type {
78
78
  LocaleProviderProps,
79
79
  TranslationBundle,
80
+ TranslationsByKey,
80
81
  TranslationsByLocale,
81
82
  } from "./i18n";
82
83
  export {
83
84
  createStaticLocaleResolver,
84
85
  LocaleProvider,
85
86
  mergeTranslations,
87
+ translationsByLocaleFromKeys,
86
88
  useLocale,
87
89
  useTranslation,
88
90
  } from "./i18n";