@iveri/contracts 0.17.0 → 0.18.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.
Files changed (90) hide show
  1. package/README.md +25 -1
  2. package/dist/cjs/api/localization/bundle.type.d.ts +41 -0
  3. package/dist/cjs/api/localization/bundle.type.d.ts.map +1 -0
  4. package/dist/cjs/api/localization/bundle.type.js +3 -0
  5. package/dist/cjs/api/localization/bundle.type.js.map +1 -0
  6. package/dist/cjs/api/localization/index.d.ts +10 -0
  7. package/dist/cjs/api/localization/index.d.ts.map +1 -0
  8. package/dist/cjs/api/localization/index.js +26 -0
  9. package/dist/cjs/api/localization/index.js.map +1 -0
  10. package/dist/cjs/api/localization/locale.type.d.ts +67 -0
  11. package/dist/cjs/api/localization/locale.type.d.ts.map +1 -0
  12. package/dist/cjs/api/localization/locale.type.js +3 -0
  13. package/dist/cjs/api/localization/locale.type.js.map +1 -0
  14. package/dist/cjs/api/localization/message.type.d.ts +90 -0
  15. package/dist/cjs/api/localization/message.type.d.ts.map +1 -0
  16. package/dist/cjs/api/localization/message.type.js +3 -0
  17. package/dist/cjs/api/localization/message.type.js.map +1 -0
  18. package/dist/cjs/api/localization/namespace.type.d.ts +67 -0
  19. package/dist/cjs/api/localization/namespace.type.d.ts.map +1 -0
  20. package/dist/cjs/api/localization/namespace.type.js +3 -0
  21. package/dist/cjs/api/localization/namespace.type.js.map +1 -0
  22. package/dist/cjs/api/localization/release.type.d.ts +74 -0
  23. package/dist/cjs/api/localization/release.type.d.ts.map +1 -0
  24. package/dist/cjs/api/localization/release.type.js +3 -0
  25. package/dist/cjs/api/localization/release.type.js.map +1 -0
  26. package/dist/cjs/api/localization/render.type.d.ts +50 -0
  27. package/dist/cjs/api/localization/render.type.d.ts.map +1 -0
  28. package/dist/cjs/api/localization/render.type.js +3 -0
  29. package/dist/cjs/api/localization/render.type.js.map +1 -0
  30. package/dist/cjs/api/localization/translation-status.enum.d.ts +29 -0
  31. package/dist/cjs/api/localization/translation-status.enum.d.ts.map +1 -0
  32. package/dist/cjs/api/localization/translation-status.enum.js +33 -0
  33. package/dist/cjs/api/localization/translation-status.enum.js.map +1 -0
  34. package/dist/cjs/api/localization/translation.type.d.ts +74 -0
  35. package/dist/cjs/api/localization/translation.type.d.ts.map +1 -0
  36. package/dist/cjs/api/localization/translation.type.js +3 -0
  37. package/dist/cjs/api/localization/translation.type.js.map +1 -0
  38. package/dist/cjs/api/localization/variable-type.enum.d.ts +39 -0
  39. package/dist/cjs/api/localization/variable-type.enum.d.ts.map +1 -0
  40. package/dist/cjs/api/localization/variable-type.enum.js +43 -0
  41. package/dist/cjs/api/localization/variable-type.enum.js.map +1 -0
  42. package/dist/cjs/enum/user-permission.enum.d.ts +44 -1
  43. package/dist/cjs/enum/user-permission.enum.d.ts.map +1 -1
  44. package/dist/cjs/enum/user-permission.enum.js +50 -0
  45. package/dist/cjs/enum/user-permission.enum.js.map +1 -1
  46. package/dist/esm/api/localization/bundle.type.d.ts +41 -0
  47. package/dist/esm/api/localization/bundle.type.d.ts.map +1 -0
  48. package/dist/esm/api/localization/bundle.type.js +2 -0
  49. package/dist/esm/api/localization/bundle.type.js.map +1 -0
  50. package/dist/esm/api/localization/index.d.ts +10 -0
  51. package/dist/esm/api/localization/index.d.ts.map +1 -0
  52. package/dist/esm/api/localization/index.js +10 -0
  53. package/dist/esm/api/localization/index.js.map +1 -0
  54. package/dist/esm/api/localization/locale.type.d.ts +67 -0
  55. package/dist/esm/api/localization/locale.type.d.ts.map +1 -0
  56. package/dist/esm/api/localization/locale.type.js +2 -0
  57. package/dist/esm/api/localization/locale.type.js.map +1 -0
  58. package/dist/esm/api/localization/message.type.d.ts +90 -0
  59. package/dist/esm/api/localization/message.type.d.ts.map +1 -0
  60. package/dist/esm/api/localization/message.type.js +2 -0
  61. package/dist/esm/api/localization/message.type.js.map +1 -0
  62. package/dist/esm/api/localization/namespace.type.d.ts +67 -0
  63. package/dist/esm/api/localization/namespace.type.d.ts.map +1 -0
  64. package/dist/esm/api/localization/namespace.type.js +2 -0
  65. package/dist/esm/api/localization/namespace.type.js.map +1 -0
  66. package/dist/esm/api/localization/release.type.d.ts +74 -0
  67. package/dist/esm/api/localization/release.type.d.ts.map +1 -0
  68. package/dist/esm/api/localization/release.type.js +2 -0
  69. package/dist/esm/api/localization/release.type.js.map +1 -0
  70. package/dist/esm/api/localization/render.type.d.ts +50 -0
  71. package/dist/esm/api/localization/render.type.d.ts.map +1 -0
  72. package/dist/esm/api/localization/render.type.js +2 -0
  73. package/dist/esm/api/localization/render.type.js.map +1 -0
  74. package/dist/esm/api/localization/translation-status.enum.d.ts +29 -0
  75. package/dist/esm/api/localization/translation-status.enum.d.ts.map +1 -0
  76. package/dist/esm/api/localization/translation-status.enum.js +30 -0
  77. package/dist/esm/api/localization/translation-status.enum.js.map +1 -0
  78. package/dist/esm/api/localization/translation.type.d.ts +74 -0
  79. package/dist/esm/api/localization/translation.type.d.ts.map +1 -0
  80. package/dist/esm/api/localization/translation.type.js +2 -0
  81. package/dist/esm/api/localization/translation.type.js.map +1 -0
  82. package/dist/esm/api/localization/variable-type.enum.d.ts +39 -0
  83. package/dist/esm/api/localization/variable-type.enum.d.ts.map +1 -0
  84. package/dist/esm/api/localization/variable-type.enum.js +40 -0
  85. package/dist/esm/api/localization/variable-type.enum.js.map +1 -0
  86. package/dist/esm/enum/user-permission.enum.d.ts +44 -1
  87. package/dist/esm/enum/user-permission.enum.d.ts.map +1 -1
  88. package/dist/esm/enum/user-permission.enum.js +50 -0
  89. package/dist/esm/enum/user-permission.enum.js.map +1 -1
  90. package/package.json +9 -1
package/README.md CHANGED
@@ -3,6 +3,13 @@
3
3
  The wire contract every Iveri service and frontend compiles against: shared types and plain
4
4
  enums, and nothing else.
5
5
 
6
+ Release `0.18.0` adds the localization contract under `@iveri/contracts/localization` —
7
+ `Locale`, `Namespace`, `Message` with its declared `MessageVariable` list, `Translation`,
8
+ `Release`, the build-time `TranslationBundle` and the runtime render shapes — plus five
9
+ `localization:*` permissions. Two consumers exist from day one and they read it differently: a
10
+ frontend pulls a bundle at build time and compiles it in, a backend renders a message at runtime
11
+ for a locale that belongs to the recipient rather than the caller.
12
+
6
13
  Release `0.17.0` adds `realtime.unsubscribe`. Subscribing is additive and capped per socket, so
7
14
  without it a long-lived inbox that pages through conversations reaches the cap and then silently
8
15
  stops receiving anything.
@@ -25,9 +32,10 @@ import { CursorPage, ErrorCode, Maybe, Paginated, UUID, UserPermission } from '@
25
32
  import type { CaptureSummary, Endpoint } from '@iveri/contracts/conduit';
26
33
  import type { AuthSession, Principal } from '@iveri/contracts/identity';
27
34
  import type { Conversation, Message } from '@iveri/contracts/unibox';
35
+ import type { Namespace, TranslationBundle } from '@iveri/contracts/localization';
28
36
  ```
29
37
 
30
- Five entry points, and no others — never `@iveri/contracts/dist/...`.
38
+ Six entry points, and no others — never `@iveri/contracts/dist/...`.
31
39
 
32
40
  The per-service surfaces are **not** re-exported from the root, deliberately. Conduit owns a
33
41
  `Provider`, a `Connection` and an `Endpoint`; Unibox owns a `Channel` and a `Contact` and would
@@ -129,6 +137,19 @@ is a first-class member for the same reason Conduit's `local-echo` connector is:
129
137
  is provable without a Meta app, and a test double would put a branch in the normalizer registry
130
138
  that only exists under Jest.
131
139
 
140
+ ### `api/localization/` → `@iveri/contracts/localization`
141
+
142
+ `iveri-localization-api`'s surface, and the clearest case yet for a shared entry point: the two
143
+ halves are consumed by different kinds of client and must not drift. `TranslationBundle` is what a
144
+ frontend build pulls and commits; `RenderBody`/`RenderedMessage` is what a backend posts when it
145
+ needs a string in the _recipient's_ language. `Locale`, `Namespace`, `Message` with its
146
+ `MessageVariable` declarations, `Translation`, `Release` and `ReleaseDiff` carry the authoring
147
+ surface the translator panel is written against, with `TranslationStatus` and `VariableType`.
148
+
149
+ `Locale` is a row rather than an enum on purpose — see the type's own note. Nothing in the
150
+ platform branches on _which_ language a string is in, so encoding the set in a type would make
151
+ adding one a release of this package and a redeploy of every consumer, for a value no code reads.
152
+
132
153
  ### Why the wire shapes moved here
133
154
 
134
155
  `conduit-admin-web` hand-transcribed all of it, carefully and with comments. It still drifted:
@@ -160,6 +181,9 @@ Conduit's outbox.
160
181
  - Version `0.13.0` adds the billing invoice read and manage permissions.
161
182
  - Version `0.14.0` adds messaging message, OTP and credit permissions.
162
183
  - Version `0.15.0` adds optional per-key FIFO ordering to outbound dispatches.
184
+ - Version `0.18.0` adds the localization entry point and the `localization:read`,
185
+ `localization:message:manage`, `localization:translate`, `localization:publish` and
186
+ `localization:render` permissions.
163
187
  - Widening a type is minor; narrowing it is major.
164
188
  - Under `api/`, the contract follows the service: add the field to the service's DTO and to the
165
189
  interface in the same release, and let `implements` prove they agree.
@@ -0,0 +1,41 @@
1
+ import type { IsoDateTime } from '../../type/iso-date-time.type.js';
2
+ /**
3
+ * One namespace at one locale, flattened — what a build pulls and commits into a repo.
4
+ *
5
+ * **UI strings are fetched at build time, never at runtime, and that is the load-bearing decision
6
+ * in this service.** A React app that fetched its labels on mount would put a network call in
7
+ * front of every first paint, make this service a hard dependency of two admin panels that are
8
+ * otherwise happy while it is down, and render a screen of empty strings when it is not. The
9
+ * strings were known when the app compiled; that is when they should be baked in.
10
+ *
11
+ * So a consumer runs `pnpm i18n:pull`, gets one of these per locale, writes it to
12
+ * `src/locale/<code>.json`, and commits it. The diff is reviewable, the app has no runtime
13
+ * dependency, and rolling back a bad translation is `git revert`.
14
+ *
15
+ * {@link RenderedMessage} is the other half — for text produced on a server, where there is no
16
+ * bundle to bake into.
17
+ */
18
+ export interface TranslationBundle {
19
+ namespaceKey: string;
20
+ localeCode: string;
21
+ /** The release this was cut from. Pinned by the consumer; `latest` resolves to a number. */
22
+ version: number;
23
+ generatedAt: IsoDateTime;
24
+ /**
25
+ * Message key to ICU value.
26
+ *
27
+ * **Flat, not nested.** `{"inbox.title": "..."}` rather than `{"inbox": {"title": "..."}}`,
28
+ * even though the dotted keys invite nesting. Nesting means a key containing a dot becomes
29
+ * ambiguous, and it makes `messages[key]` — the only lookup anyone performs — a path walk
30
+ * instead of a property read.
31
+ */
32
+ messages: Record<string, string>;
33
+ /**
34
+ * Keys served from a fallback locale rather than this one, and where they came from.
35
+ *
36
+ * Emitted so a build can fail, or warn, on an incomplete bundle. Without it a half-translated
37
+ * locale looks identical to a complete one: every key resolves, and half of them are English.
38
+ */
39
+ fallbacks: Record<string, string>;
40
+ }
41
+ //# sourceMappingURL=bundle.type.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle.type.d.ts","sourceRoot":"","sources":["../../../../src/api/localization/bundle.type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AAEpE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,iBAAiB;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IAEnB,4FAA4F;IAC5F,OAAO,EAAE,MAAM,CAAC;IAEhB,WAAW,EAAE,WAAW,CAAC;IAEzB;;;;;;;OAOG;IACH,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEjC;;;;;OAKG;IACH,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=bundle.type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle.type.js","sourceRoot":"","sources":["../../../../src/api/localization/bundle.type.ts"],"names":[],"mappings":""}
@@ -0,0 +1,10 @@
1
+ export * from './bundle.type.js';
2
+ export * from './locale.type.js';
3
+ export * from './message.type.js';
4
+ export * from './namespace.type.js';
5
+ export * from './release.type.js';
6
+ export * from './render.type.js';
7
+ export * from './translation-status.enum.js';
8
+ export * from './translation.type.js';
9
+ export * from './variable-type.enum.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/api/localization/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC"}
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./bundle.type.js"), exports);
18
+ __exportStar(require("./locale.type.js"), exports);
19
+ __exportStar(require("./message.type.js"), exports);
20
+ __exportStar(require("./namespace.type.js"), exports);
21
+ __exportStar(require("./release.type.js"), exports);
22
+ __exportStar(require("./render.type.js"), exports);
23
+ __exportStar(require("./translation-status.enum.js"), exports);
24
+ __exportStar(require("./translation.type.js"), exports);
25
+ __exportStar(require("./variable-type.enum.js"), exports);
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/api/localization/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,mDAAiC;AACjC,mDAAiC;AACjC,oDAAkC;AAClC,sDAAoC;AACpC,oDAAkC;AAClC,mDAAiC;AACjC,+DAA6C;AAC7C,wDAAsC;AACtC,0DAAwC"}
@@ -0,0 +1,67 @@
1
+ import type { IsoDateTime } from '../../type/iso-date-time.type.js';
2
+ import type { Nullable } from '../../type/nil.type.js';
3
+ import type { UUID } from '../../type/uuid.type.js';
4
+ /**
5
+ * A language a tenant publishes in.
6
+ *
7
+ * **A row, not an enum member.** The obvious alternative — `enum LocaleCode { EN, RU, KA }` — makes
8
+ * adding Ukrainian a contracts release, an SDK release and a redeploy of every consumer, to add a
9
+ * value that no code branches on. Nothing in the platform switches on *which* locale a string is
10
+ * in; it only ever looks one up. So the set belongs in data.
11
+ *
12
+ * `code` is a BCP-47 tag and is what every other surface uses: the `Accept-Language` header the
13
+ * SDK already resolves into `RequestContext.locale`, the export filename, the render request.
14
+ */
15
+ export interface Locale {
16
+ id: UUID;
17
+ /** BCP-47, lowercased — `en`, `ru`, `ka`, `en-GB`. Unique within the tenant. */
18
+ code: string;
19
+ /** For the language picker in an English-language admin screen. */
20
+ englishName: string;
21
+ /** For the language picker a native speaker sees — `ქართული`, `Русский`. */
22
+ nativeName: string;
23
+ /**
24
+ * The locale translators translate *from*. Exactly one per tenant.
25
+ *
26
+ * It is also the locale a message's source text lives in, so editing a source value is what
27
+ * flips every other locale's translation of that message to `needs-review`. Changing which
28
+ * locale is the source is therefore not a display preference — it moves that trigger.
29
+ */
30
+ isSource: boolean;
31
+ /**
32
+ * Whether this locale is offered at all. Inactive keeps the translations and stops them
33
+ * being exported or rendered, which is what a locale that is half-translated needs — the
34
+ * alternative is deleting the work to hide it.
35
+ */
36
+ isActive: boolean;
37
+ /**
38
+ * Where a lookup goes when this locale has no approved translation. Null ends the chain.
39
+ *
40
+ * Chains are followed transitively (`en-GB → en → null`) and are **rejected at write time if
41
+ * they cycle**, because the resolver would otherwise loop on a row a customer can create.
42
+ */
43
+ fallbackCode: Nullable<string>;
44
+ createdAt: IsoDateTime;
45
+ updatedAt: IsoDateTime;
46
+ }
47
+ /** `GET /api/v1/locales`. Small and unpaged — a tenant has a handful of these, not a page of them. */
48
+ export type LocaleList = Locale[];
49
+ /** `POST /api/v1/locales`. */
50
+ export interface CreateLocaleBody {
51
+ code: string;
52
+ englishName: string;
53
+ nativeName: string;
54
+ isSource?: boolean;
55
+ isActive?: boolean;
56
+ fallbackCode?: Nullable<string>;
57
+ }
58
+ /** `PATCH /api/v1/locales/:code`. */
59
+ export interface UpdateLocaleBody {
60
+ englishName?: string;
61
+ nativeName?: string;
62
+ /** Promoting a locale to source demotes the previous one in the same transaction. */
63
+ isSource?: boolean;
64
+ isActive?: boolean;
65
+ fallbackCode?: Nullable<string>;
66
+ }
67
+ //# sourceMappingURL=locale.type.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locale.type.d.ts","sourceRoot":"","sources":["../../../../src/api/localization/locale.type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAEpD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,MAAM;IACnB,EAAE,EAAE,IAAI,CAAC;IAET,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;IAEb,mEAAmE;IACnE,WAAW,EAAE,MAAM,CAAC;IAEpB,4EAA4E;IAC5E,UAAU,EAAE,MAAM,CAAC;IAEnB;;;;;;OAMG;IACH,QAAQ,EAAE,OAAO,CAAC;IAElB;;;;OAIG;IACH,QAAQ,EAAE,OAAO,CAAC;IAElB;;;;;OAKG;IACH,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAE/B,SAAS,EAAE,WAAW,CAAC;IACvB,SAAS,EAAE,WAAW,CAAC;CAC1B;AAED,sGAAsG;AACtG,MAAM,MAAM,UAAU,GAAG,MAAM,EAAE,CAAC;AAElC,8BAA8B;AAC9B,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CACnC;AAED,qCAAqC;AACrC,MAAM,WAAW,gBAAgB;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qFAAqF;IACrF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CACnC"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=locale.type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locale.type.js","sourceRoot":"","sources":["../../../../src/api/localization/locale.type.ts"],"names":[],"mappings":""}
@@ -0,0 +1,90 @@
1
+ import type { IsoDateTime } from '../../type/iso-date-time.type.js';
2
+ import type { Nullable } from '../../type/nil.type.js';
3
+ import type { Paginated } from '../../type/paginated.type.js';
4
+ import type { UUID } from '../../type/uuid.type.js';
5
+ import type { TranslationStatus } from './translation-status.enum.js';
6
+ import type { VariableType } from './variable-type.enum.js';
7
+ /** One placeholder a message declares. See {@link VariableType} for why these are declared. */
8
+ export interface MessageVariable {
9
+ /** The name inside the braces — `orderNumber` in `{orderNumber}`. `[a-zA-Z][a-zA-Z0-9]*`. */
10
+ name: string;
11
+ type: VariableType;
12
+ /**
13
+ * What it holds, in a sentence, for the translator.
14
+ *
15
+ * Worth more than it looks: a translator seeing `{count}` cannot tell whether it counts
16
+ * unread messages or days remaining, and the two need different words in Georgian.
17
+ */
18
+ description: Nullable<string>;
19
+ /** A representative value, used to preview the rendered string in the editor. */
20
+ example: Nullable<string>;
21
+ /**
22
+ * For {@link VariableType.SELECT} only — the closed set of branches a translation may use.
23
+ * A translation branching on anything outside it is rejected at write time.
24
+ */
25
+ options: Nullable<string[]>;
26
+ }
27
+ /**
28
+ * A translatable string, identified by a key that never changes.
29
+ *
30
+ * The key is the contract with the consuming code: `t('inbox.conversation.assign')` is compiled
31
+ * into an app, so renaming one is a breaking change to every release that already shipped. Keys
32
+ * are therefore **immutable after creation** and retired by archiving, not by deletion.
33
+ */
34
+ export interface Message {
35
+ id: UUID;
36
+ namespaceId: UUID;
37
+ namespaceKey: string;
38
+ /** Dotted, lowercase, `[a-z0-9.-]` — `inbox.conversation.assign`. Unique in the namespace. */
39
+ key: string;
40
+ /**
41
+ * Where this string appears and what it is doing there.
42
+ *
43
+ * The highest-leverage field in the schema. A translator handed `Open` with no context cannot
44
+ * know whether it is a button, an adjective describing a conversation, or a status label —
45
+ * and those are three different Georgian words. Missing context is the main cause of
46
+ * translations that are individually correct and collectively wrong.
47
+ */
48
+ description: Nullable<string>;
49
+ variables: MessageVariable[];
50
+ /**
51
+ * Retired. Excluded from new releases, kept so an older pinned release still resolves and so
52
+ * the translation work is not destroyed by a key that turns out to be still in use.
53
+ */
54
+ isArchived: boolean;
55
+ /** Present on the detail response; omitted from the listing, which is already wide. */
56
+ translations?: MessageTranslationSummary[];
57
+ createdAt: IsoDateTime;
58
+ updatedAt: IsoDateTime;
59
+ }
60
+ /** One locale's standing on a message, as shown in a listing row. */
61
+ export interface MessageTranslationSummary {
62
+ localeCode: string;
63
+ /** `MISSING` here is synthesised — see {@link TranslationStatus}. */
64
+ status: TranslationStatus;
65
+ value: Nullable<string>;
66
+ updatedAt: Nullable<IsoDateTime>;
67
+ }
68
+ /** `GET /api/v1/namespaces/:key/messages`. */
69
+ export type MessagesPage = Paginated<Message>;
70
+ /** `POST /api/v1/namespaces/:key/messages`. */
71
+ export interface CreateMessageBody {
72
+ key: string;
73
+ description?: Nullable<string>;
74
+ variables?: MessageVariable[];
75
+ /** The source-locale text. Written as an `APPROVED` translation in the same transaction. */
76
+ sourceValue: string;
77
+ }
78
+ /**
79
+ * `PATCH /api/v1/namespaces/:key/messages/:messageKey`.
80
+ *
81
+ * Editing `variables` is the sharp one: removing a declared variable invalidates every
82
+ * translation still using it, so the service refuses the edit and names them rather than
83
+ * silently leaving broken strings behind.
84
+ */
85
+ export interface UpdateMessageBody {
86
+ description?: Nullable<string>;
87
+ variables?: MessageVariable[];
88
+ isArchived?: boolean;
89
+ }
90
+ //# sourceMappingURL=message.type.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message.type.d.ts","sourceRoot":"","sources":["../../../../src/api/localization/message.type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAE5D,+FAA+F;AAC/F,MAAM,WAAW,eAAe;IAC5B,6FAA6F;IAC7F,IAAI,EAAE,MAAM,CAAC;IAEb,IAAI,EAAE,YAAY,CAAC;IAEnB;;;;;OAKG;IACH,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAE9B,iFAAiF;IACjF,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAE1B;;;OAGG;IACH,OAAO,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;CAC/B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,OAAO;IACpB,EAAE,EAAE,IAAI,CAAC;IAET,WAAW,EAAE,IAAI,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IAErB,8FAA8F;IAC9F,GAAG,EAAE,MAAM,CAAC;IAEZ;;;;;;;OAOG;IACH,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAE9B,SAAS,EAAE,eAAe,EAAE,CAAC;IAE7B;;;OAGG;IACH,UAAU,EAAE,OAAO,CAAC;IAEpB,uFAAuF;IACvF,YAAY,CAAC,EAAE,yBAAyB,EAAE,CAAC;IAE3C,SAAS,EAAE,WAAW,CAAC;IACvB,SAAS,EAAE,WAAW,CAAC;CAC1B;AAED,qEAAqE;AACrE,MAAM,WAAW,yBAAyB;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,MAAM,EAAE,iBAAiB,CAAC;IAC1B,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACxB,SAAS,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;CACpC;AAED,8CAA8C;AAC9C,MAAM,MAAM,YAAY,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;AAE9C,+CAA+C;AAC/C,MAAM,WAAW,iBAAiB;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/B,SAAS,CAAC,EAAE,eAAe,EAAE,CAAC;IAC9B,4FAA4F;IAC5F,WAAW,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAC9B,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/B,SAAS,CAAC,EAAE,eAAe,EAAE,CAAC;IAC9B,UAAU,CAAC,EAAE,OAAO,CAAC;CACxB"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=message.type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message.type.js","sourceRoot":"","sources":["../../../../src/api/localization/message.type.ts"],"names":[],"mappings":""}
@@ -0,0 +1,67 @@
1
+ import type { IsoDateTime } from '../../type/iso-date-time.type.js';
2
+ import type { Nullable } from '../../type/nil.type.js';
3
+ import type { Paginated } from '../../type/paginated.type.js';
4
+ import type { UUID } from '../../type/uuid.type.js';
5
+ /**
6
+ * A bounded set of keys owned by one consumer — `unibox-web`, `billing.invoice`, `messaging.otp`.
7
+ *
8
+ * **The unit of publish and the unit of fetch, and it has to be both.** Without namespaces every
9
+ * consumer downloads every string the tenant has ever written, and a translator fixing one word in
10
+ * an invoice template republishes the entire admin panel's UI at the same time. Those are the two
11
+ * failures a flat key space produces, and neither is visible until the key count is in the
12
+ * thousands and it is expensive to fix.
13
+ *
14
+ * A namespace maps roughly to a deployable: one app, or one family of server-rendered messages.
15
+ */
16
+ export interface Namespace {
17
+ id: UUID;
18
+ /** Lowercase `[a-z0-9.-]`, e.g. `unibox-web`. Unique within the tenant. */
19
+ key: string;
20
+ /** What lives in here, for whoever has to decide where a new key belongs. */
21
+ description: Nullable<string>;
22
+ /**
23
+ * Whether a release may include translations still in `draft`.
24
+ *
25
+ * Off by default. On for a namespace nobody reads in production yet, where requiring approval
26
+ * on every key means a translator cannot see their own work in the app.
27
+ */
28
+ allowsDraftRelease: boolean;
29
+ messageCount: number;
30
+ /** Null until the namespace has been published once. */
31
+ latestReleaseVersion: Nullable<number>;
32
+ latestReleaseAt: Nullable<IsoDateTime>;
33
+ createdAt: IsoDateTime;
34
+ updatedAt: IsoDateTime;
35
+ }
36
+ /** `GET /api/v1/namespaces`. */
37
+ export type NamespacesPage = Paginated<Namespace>;
38
+ /** `POST /api/v1/namespaces`. */
39
+ export interface CreateNamespaceBody {
40
+ key: string;
41
+ description?: Nullable<string>;
42
+ allowsDraftRelease?: boolean;
43
+ }
44
+ /** `PATCH /api/v1/namespaces/:key`. The key itself is immutable — consumers pin it. */
45
+ export interface UpdateNamespaceBody {
46
+ description?: Nullable<string>;
47
+ allowsDraftRelease?: boolean;
48
+ }
49
+ /**
50
+ * `GET /api/v1/namespaces/:key/progress` — how much is left to do, per locale.
51
+ *
52
+ * The one screen a translation project actually runs on. Answering it from the message listing
53
+ * would mean paging through every key to count what is missing.
54
+ */
55
+ export interface NamespaceProgress {
56
+ namespaceKey: string;
57
+ messageCount: number;
58
+ locales: LocaleProgress[];
59
+ }
60
+ export interface LocaleProgress {
61
+ localeCode: string;
62
+ approved: number;
63
+ needsReview: number;
64
+ draft: number;
65
+ missing: number;
66
+ }
67
+ //# sourceMappingURL=namespace.type.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"namespace.type.d.ts","sourceRoot":"","sources":["../../../../src/api/localization/namespace.type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAEpD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,SAAS;IACtB,EAAE,EAAE,IAAI,CAAC;IAET,2EAA2E;IAC3E,GAAG,EAAE,MAAM,CAAC;IAEZ,6EAA6E;IAC7E,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAE9B;;;;;OAKG;IACH,kBAAkB,EAAE,OAAO,CAAC;IAE5B,YAAY,EAAE,MAAM,CAAC;IAErB,wDAAwD;IACxD,oBAAoB,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACvC,eAAe,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;IAEvC,SAAS,EAAE,WAAW,CAAC;IACvB,SAAS,EAAE,WAAW,CAAC;CAC1B;AAED,gCAAgC;AAChC,MAAM,MAAM,cAAc,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;AAElD,iCAAiC;AACjC,MAAM,WAAW,mBAAmB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/B,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,uFAAuF;AACvF,MAAM,WAAW,mBAAmB;IAChC,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/B,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,cAAc,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACnB"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=namespace.type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"namespace.type.js","sourceRoot":"","sources":["../../../../src/api/localization/namespace.type.ts"],"names":[],"mappings":""}
@@ -0,0 +1,74 @@
1
+ import type { IsoDateTime } from '../../type/iso-date-time.type.js';
2
+ import type { Nullable } from '../../type/nil.type.js';
3
+ import type { Paginated } from '../../type/paginated.type.js';
4
+ import type { UUID } from '../../type/uuid.type.js';
5
+ /**
6
+ * An immutable snapshot of one namespace, at every active locale, at one moment.
7
+ *
8
+ * **This is what makes the service safe to depend on.** Without it, editing a translation changes
9
+ * production text the instant it is saved — so a translator experimenting at 2am is a deploy, an
10
+ * unfinished sentence is an outage, and there is no way to answer "what did this say last
11
+ * Tuesday". With it, editing is free and publishing is the decision, gated by its own permission.
12
+ *
13
+ * The snapshot is stored in full rather than reconstructed from the translation rows by
14
+ * timestamp. Reconstruction sounds cheaper and is wrong: a message archived after the release, or
15
+ * a variable renamed, changes what the reconstruction produces, so a consumer pinned to version 3
16
+ * would silently get different bytes next month.
17
+ */
18
+ export interface Release {
19
+ id: UUID;
20
+ namespaceId: UUID;
21
+ namespaceKey: string;
22
+ /** Monotonic per namespace, starting at 1. What a consumer pins. */
23
+ version: number;
24
+ /** What changed and why, for whoever reads the history. */
25
+ notes: Nullable<string>;
26
+ /** Locales the snapshot contains — the active ones at publish time, not necessarily now. */
27
+ localeCodes: string[];
28
+ messageCount: number;
29
+ /** Null when published by a service principal. */
30
+ publishedByUserId: Nullable<UUID>;
31
+ publishedAt: IsoDateTime;
32
+ }
33
+ /** `GET /api/v1/namespaces/:key/releases`. Newest first. */
34
+ export type ReleasesPage = Paginated<Release>;
35
+ /** `POST /api/v1/namespaces/:key/releases`. */
36
+ export interface PublishReleaseBody {
37
+ notes?: Nullable<string>;
38
+ }
39
+ /**
40
+ * `GET /api/v1/namespaces/:key/releases/preview` — what publishing right now would change.
41
+ *
42
+ * Shown before the button is pressed. A publish is irreversible in the sense that matters — the
43
+ * consumers pull it — so the operator gets to see the diff first rather than discovering it in
44
+ * production.
45
+ */
46
+ export interface ReleaseDiff {
47
+ namespaceKey: string;
48
+ /** The version this would become. */
49
+ nextVersion: number;
50
+ /** Null when nothing has been published yet, in which case everything reads as added. */
51
+ previousVersion: Nullable<number>;
52
+ entries: ReleaseDiffEntry[];
53
+ /**
54
+ * Messages with no publishable translation in a locale that is active.
55
+ *
56
+ * Not an error — a release ships with gaps and the consumer falls back. It is surfaced
57
+ * because shipping a gap should be a choice someone made, not one they made by not looking.
58
+ */
59
+ untranslated: UntranslatedEntry[];
60
+ }
61
+ export interface ReleaseDiffEntry {
62
+ messageKey: string;
63
+ localeCode: string;
64
+ change: 'added' | 'changed' | 'removed';
65
+ previousValue: Nullable<string>;
66
+ nextValue: Nullable<string>;
67
+ }
68
+ export interface UntranslatedEntry {
69
+ messageKey: string;
70
+ localeCode: string;
71
+ /** Where the fallback chain lands, or null if it falls off the end and the key renders raw. */
72
+ fallsBackTo: Nullable<string>;
73
+ }
74
+ //# sourceMappingURL=release.type.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"release.type.d.ts","sourceRoot":"","sources":["../../../../src/api/localization/release.type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAEpD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,OAAO;IACpB,EAAE,EAAE,IAAI,CAAC;IAET,WAAW,EAAE,IAAI,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IAErB,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAC;IAEhB,2DAA2D;IAC3D,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAExB,4FAA4F;IAC5F,WAAW,EAAE,MAAM,EAAE,CAAC;IAEtB,YAAY,EAAE,MAAM,CAAC;IAErB,kDAAkD;IAClD,iBAAiB,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;IAClC,WAAW,EAAE,WAAW,CAAC;CAC5B;AAED,4DAA4D;AAC5D,MAAM,MAAM,YAAY,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;AAE9C,+CAA+C;AAC/C,MAAM,WAAW,kBAAkB;IAC/B,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CAC5B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IACxB,YAAY,EAAE,MAAM,CAAC;IAErB,qCAAqC;IACrC,WAAW,EAAE,MAAM,CAAC;IAEpB,yFAAyF;IACzF,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAElC,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAE5B;;;;;OAKG;IACH,YAAY,EAAE,iBAAiB,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,gBAAgB;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;IACxC,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAChC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,+FAA+F;IAC/F,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CACjC"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=release.type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"release.type.js","sourceRoot":"","sources":["../../../../src/api/localization/release.type.ts"],"names":[],"mappings":""}
@@ -0,0 +1,50 @@
1
+ import type { Nullable } from '../../type/nil.type.js';
2
+ /**
3
+ * `POST /api/v1/render` — resolve and format messages server-side.
4
+ *
5
+ * The counterpart to {@link TranslationBundle}, for the case a bundle cannot serve: text produced
6
+ * on a server, where there is no compiled app to bake strings into and the target locale belongs
7
+ * to whoever will read the message rather than whoever is making the request. An OTP body, an
8
+ * invoice line, an order confirmation.
9
+ *
10
+ * **Batched, because the caller almost always needs several.** An invoice email is a subject, a
11
+ * greeting, six line labels and a footer, and one HTTP round trip per string would put this
12
+ * service on the latency path of every email the platform sends.
13
+ */
14
+ export interface RenderBody {
15
+ /** BCP-47. Falls back through the locale chain when this one has no translation. */
16
+ localeCode: string;
17
+ items: RenderItem[];
18
+ }
19
+ export interface RenderItem {
20
+ namespaceKey: string;
21
+ messageKey: string;
22
+ /**
23
+ * Values for the message's declared placeholders.
24
+ *
25
+ * A missing one is an error rather than an empty substitution: an OTP that renders as
26
+ * "Your code is " is worse than an error, because it is sent.
27
+ */
28
+ variables?: Record<string, string | number>;
29
+ }
30
+ export interface RenderResult {
31
+ items: RenderedMessage[];
32
+ }
33
+ export interface RenderedMessage {
34
+ namespaceKey: string;
35
+ messageKey: string;
36
+ /** The locale actually used, which is not necessarily the one asked for. */
37
+ localeCode: string;
38
+ /** Formatted for {@link localeCode} — plural branches taken, numbers and dates localised. */
39
+ value: string;
40
+ /**
41
+ * True when the requested locale had nothing and the chain supplied this.
42
+ *
43
+ * Returned rather than hidden so a caller that must not send a half-localised message — an
44
+ * OTP, a legal notice — can decide for itself rather than discovering it from a customer.
45
+ */
46
+ isFallback: boolean;
47
+ /** The release the value came from. Null for a message that has never been published. */
48
+ version: Nullable<number>;
49
+ }
50
+ //# sourceMappingURL=render.type.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.type.d.ts","sourceRoot":"","sources":["../../../../src/api/localization/render.type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAEvD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,UAAU;IACvB,oFAAoF;IACpF,UAAU,EAAE,MAAM,CAAC;IAEnB,KAAK,EAAE,UAAU,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IAEnB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,YAAY;IACzB,KAAK,EAAE,eAAe,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IAEnB,4EAA4E;IAC5E,UAAU,EAAE,MAAM,CAAC;IAEnB,6FAA6F;IAC7F,KAAK,EAAE,MAAM,CAAC;IAEd;;;;;OAKG;IACH,UAAU,EAAE,OAAO,CAAC;IAEpB,yFAAyF;IACzF,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CAC7B"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=render.type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.type.js","sourceRoot":"","sources":["../../../../src/api/localization/render.type.ts"],"names":[],"mappings":""}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Where a single translation stands, for one message in one locale.
3
+ *
4
+ * The states exist to answer one question a translator asks constantly — *what is left to do* —
5
+ * and they are ordered by how much trust a reader may put in the value.
6
+ *
7
+ * `MISSING` is **not stored**. A translation row exists only once someone has written something,
8
+ * so "missing" is the absence of a row projected into this enum by the read side. Storing it
9
+ * would mean writing a row per message per locale the moment a key is created, which turns
10
+ * adding one key into N writes and makes "has anyone touched this?" unanswerable.
11
+ */
12
+ export declare enum TranslationStatus {
13
+ /** No row exists. Synthesised by the read side so a listing can be filtered on it. */
14
+ MISSING = "missing",
15
+ /** Someone is working on it. Excluded from a release unless the namespace allows drafts. */
16
+ DRAFT = "draft",
17
+ /**
18
+ * Written, but the source text changed underneath it.
19
+ *
20
+ * Set automatically when the source-locale value of the same message is edited — an English
21
+ * label reworded from `Archive` to `Delete` leaves a Georgian translation that is
22
+ * grammatically fine and now says the wrong thing. Nothing else in the system can catch that,
23
+ * because the translation is still valid text.
24
+ */
25
+ NEEDS_REVIEW = "needs-review",
26
+ /** Reviewed and publishable. */
27
+ APPROVED = "approved"
28
+ }
29
+ //# sourceMappingURL=translation-status.enum.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translation-status.enum.d.ts","sourceRoot":"","sources":["../../../../src/api/localization/translation-status.enum.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,oBAAY,iBAAiB;IACzB,sFAAsF;IACtF,OAAO,YAAY;IAEnB,4FAA4F;IAC5F,KAAK,UAAU;IAEf;;;;;;;OAOG;IACH,YAAY,iBAAiB;IAE7B,gCAAgC;IAChC,QAAQ,aAAa;CACxB"}