@proveanything/smartlinks 1.9.3 → 1.9.5

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,6 +1,6 @@
1
1
  # Smartlinks API Summary
2
2
 
3
- Version: 1.9.3 | Generated: 2026-03-23T18:12:23.239Z
3
+ Version: 1.9.5 | Generated: 2026-03-23T20:19:00.201Z
4
4
 
5
5
  This is a concise summary of all available API functions and types.
6
6
 
@@ -10,13 +10,16 @@ For detailed guides on specific features:
10
10
 
11
11
  - **[SmartLinks Microapp Overview](overview.md)** - Platform architecture, data model, auth patterns, storage, anti-patterns, and quick-reference for all SDK docs
12
12
  - **[AI & Chat Completions](ai.md)** - Chat completions, RAG (document-grounded Q&A), voice integration, streaming, tool calling, podcast generation
13
+ - **[Translations](translations.md)** - Runtime translation lookup, browser-side IndexedDB caching, and admin translation management
13
14
  - **[Widgets](widgets.md)** - Embeddable React components for parent applications
14
15
  - **[Containers](containers.md)** - Building full-app embeddable containers (lazy-loaded)
16
+ - **[Scanner Containers](scanner-container.md)** - Building scanner microapps for the SmartLinks Scanner Android host (RFID, NFC, QR, key events)
15
17
  - **[Multi-Page App Architecture](mpa.md)** - Vite MPA build pipeline: public/admin entry points, widget/container/executor bundles, content-hashed CDN assets
16
18
  - **[App Configuration Files](app-manifest.md)** - `app.manifest.json` and `app.admin.json` reference — bundles, components, setup questions, import schemas, tunable fields, and metrics
17
19
  - **[Executor Model](executor.md)** - Programmatic JS bundles for AI-driven setup, server-side SEO metadata generation, and LLM content for AI crawlers
18
20
  - **[Realtime](realtime.md)** - Real-time data updates and WebSocket connections
19
21
  - **[iframe Responder](iframe-responder.md)** - iframe integration and cross-origin communication
22
+ - **[Utilities](utils.md)** - Helper functions for building portal paths, URLs, and common tasks
20
23
  - **[i18n](i18n.md)** - Internationalization and localization
21
24
  - **[Liquid Templates](liquid-templates.md)** - Dynamic templating for content generation
22
25
  - **[Theme System](theme.system.md)** - Theme configuration and customization
@@ -110,6 +113,7 @@ The Smartlinks SDK is organized into the following namespaces:
110
113
  - **realtime** - Functions for realtime operations
111
114
  - **tags** - Functions for tags operations
112
115
  - **template** - Functions for template operations
116
+ - **translations** - Functions for translations operations
113
117
 
114
118
  ## HTTP Utilities
115
119
 
@@ -6343,6 +6347,153 @@ interface TemplateRenderSourceResponse {
6343
6347
 
6344
6348
  **TemplatePublic** = `TemplateBase`
6345
6349
 
6350
+ ### translations
6351
+
6352
+ **TranslationContext** (interface)
6353
+ ```typescript
6354
+ interface TranslationContext {
6355
+ surface?: string
6356
+ field?: string
6357
+ [key: string]: TranslationContextValue | undefined
6358
+ }
6359
+ ```
6360
+
6361
+ **TranslationLookupRequestBase** (interface)
6362
+ ```typescript
6363
+ interface TranslationLookupRequestBase {
6364
+ targetLanguage: string
6365
+ sourceLanguage?: string
6366
+ mode?: TranslationLookupMode
6367
+ contentType?: TranslationContentType
6368
+ context?: TranslationContext
6369
+ returnMeta?: boolean
6370
+ }
6371
+ ```
6372
+
6373
+ **TranslationLookupItem** (interface)
6374
+ ```typescript
6375
+ interface TranslationLookupItem {
6376
+ index: number
6377
+ hash: string
6378
+ sourceText: string
6379
+ translatedText?: string
6380
+ status?: TranslationItemStatus
6381
+ provider?: string
6382
+ model?: string
6383
+ isOverride?: boolean
6384
+ quality?: TranslationQuality
6385
+ createdAt?: string
6386
+ updatedAt?: string
6387
+ }
6388
+ ```
6389
+
6390
+ **TranslationLookupResponse** (interface)
6391
+ ```typescript
6392
+ interface TranslationLookupResponse {
6393
+ targetLanguage: string
6394
+ sourceLanguage?: string
6395
+ mode?: TranslationLookupMode
6396
+ items: TranslationLookupItem[]
6397
+ }
6398
+ ```
6399
+
6400
+ **ResolvedTranslationResponse** (interface)
6401
+ ```typescript
6402
+ interface ResolvedTranslationResponse {
6403
+ targetLanguage: string
6404
+ sourceLanguage?: string
6405
+ mode?: TranslationLookupMode
6406
+ items: ResolvedTranslationItem[]
6407
+ }
6408
+ ```
6409
+
6410
+ **TranslationHashOptions** (interface)
6411
+ ```typescript
6412
+ interface TranslationHashOptions {
6413
+ trim?: boolean
6414
+ collapseWhitespace?: boolean
6415
+ unicodeNormalization?: 'NFC' | 'NFKC' | false
6416
+ }
6417
+ ```
6418
+
6419
+ **TranslationResolveOptions** (interface)
6420
+ ```typescript
6421
+ interface TranslationResolveOptions {
6422
+ useLocalCache?: boolean
6423
+ refreshLocalCache?: boolean
6424
+ localCacheTtlMs?: number
6425
+ hashOptions?: TranslationHashOptions
6426
+ }
6427
+ ```
6428
+
6429
+ **TranslationRecord** (interface)
6430
+ ```typescript
6431
+ interface TranslationRecord {
6432
+ id: string
6433
+ collectionId: string
6434
+ sourceHash: string
6435
+ sourceText: string
6436
+ sourceLanguage?: string
6437
+ targetLanguage: string
6438
+ contentType: string
6439
+ contextKey?: string | null
6440
+ translatedText: string
6441
+ provider?: string | null
6442
+ model?: string | null
6443
+ quality: TranslationQuality
6444
+ isOverride: boolean
6445
+ metadata?: Record<string, any>
6446
+ createdAt: string
6447
+ updatedAt: string
6448
+ }
6449
+ ```
6450
+
6451
+ **TranslationListParams** (interface)
6452
+ ```typescript
6453
+ interface TranslationListParams {
6454
+ targetLanguage?: string
6455
+ sourceLanguage?: string
6456
+ contentType?: string
6457
+ contextKey?: string
6458
+ q?: string
6459
+ isOverride?: boolean
6460
+ limit?: number
6461
+ offset?: number
6462
+ }
6463
+ ```
6464
+
6465
+ **TranslationListResponse** (interface)
6466
+ ```typescript
6467
+ interface TranslationListResponse {
6468
+ items: TranslationRecord[]
6469
+ total?: number
6470
+ limit?: number
6471
+ offset?: number
6472
+ }
6473
+ ```
6474
+
6475
+ **TranslationUpdateRequest** (interface)
6476
+ ```typescript
6477
+ interface TranslationUpdateRequest {
6478
+ translatedText?: string
6479
+ isOverride?: boolean
6480
+ quality?: TranslationQuality
6481
+ metadata?: Record<string, any>
6482
+ }
6483
+ ```
6484
+
6485
+ **TranslationLookupMode** = `'cache-fill' | 'cache-only'`
6486
+
6487
+ **TranslationContentType** = `'text/plain' | 'text/html' | 'text/x-liquid' | (string & {})`
6488
+
6489
+ **TranslationQuality** = `'machine' | 'human' | 'passthrough' | (string & {})`
6490
+
6491
+ **TranslationItemStatus** = `'cached' | 'generated' | 'miss' | 'passthrough' | 'local-cache' | (string & {})`
6492
+
6493
+ **TranslationContextValue** = `string | number | boolean | null`
6494
+
6495
+ **TranslationLookupRequest** = `TranslationLookupSingleRequest | TranslationLookupBatchRequest`
6496
+
6346
6497
  ### variant
6347
6498
 
6348
6499
  **VariantResponse** = `any`
@@ -6412,6 +6563,140 @@ type VerifyTokenResponse = {
6412
6563
  }
6413
6564
  ```
6414
6565
 
6566
+ ### conditions (utils)
6567
+
6568
+ **BaseCondition** (interface)
6569
+ ```typescript
6570
+ interface BaseCondition {
6571
+ type: string
6572
+ contains?: boolean
6573
+ passes?: boolean
6574
+ }
6575
+ ```
6576
+
6577
+ **ConditionSet** (interface)
6578
+ ```typescript
6579
+ interface ConditionSet {
6580
+ id?: string
6581
+ type?: 'and' | 'or'
6582
+ conditions?: Condition[]
6583
+ }
6584
+ ```
6585
+
6586
+ **UserLocation** (interface)
6587
+ ```typescript
6588
+ interface UserLocation {
6589
+ country?: string
6590
+ latitude?: number
6591
+ longitude?: number
6592
+ }
6593
+ ```
6594
+
6595
+ **PlatformInfo** (interface)
6596
+ ```typescript
6597
+ interface PlatformInfo {
6598
+ android?: boolean
6599
+ ios?: boolean
6600
+ win?: boolean
6601
+ mac?: boolean
6602
+ }
6603
+ ```
6604
+
6605
+ **StatsInfo** (interface)
6606
+ ```typescript
6607
+ interface StatsInfo {
6608
+ version?: string | null
6609
+ platform?: PlatformInfo
6610
+ mobile?: boolean
6611
+ }
6612
+ ```
6613
+
6614
+ **UserInfo** (interface)
6615
+ ```typescript
6616
+ interface UserInfo {
6617
+ valid: boolean
6618
+ uid?: string
6619
+ location?: UserLocation
6620
+ groups?: string[]
6621
+ }
6622
+ ```
6623
+
6624
+ **ProductInfo** (interface)
6625
+ ```typescript
6626
+ interface ProductInfo {
6627
+ id: string
6628
+ tags?: Record<string, any>
6629
+ }
6630
+ ```
6631
+
6632
+ **ProofInfo** (interface)
6633
+ ```typescript
6634
+ interface ProofInfo {
6635
+ id?: string
6636
+ userId?: string
6637
+ claimable?: boolean
6638
+ virtual?: boolean
6639
+ }
6640
+ ```
6641
+
6642
+ **CollectionInfo** (interface)
6643
+ ```typescript
6644
+ interface CollectionInfo {
6645
+ id: string
6646
+ roles?: Record<string, any>
6647
+ }
6648
+ ```
6649
+
6650
+ **ConditionParams** (interface)
6651
+ ```typescript
6652
+ interface ConditionParams {
6653
+ condition?: ConditionSet
6654
+ conditionId?: string
6655
+ conditionStack?: string[]
6656
+ user?: UserInfo
6657
+ product?: ProductInfo
6658
+ proof?: ProofInfo
6659
+ collection?: CollectionInfo
6660
+ stats?: StatsInfo
6661
+ fetchCondition?: (collectionId: string, conditionId: string) => Promise<ConditionSet | null>
6662
+ getLocation?: () => Promise<{ latitude: number; longitude: number }>
6663
+ debugConditions?: boolean | ConditionDebugOptions
6664
+ [key: string]: any
6665
+ }
6666
+ ```
6667
+
6668
+ **ConditionDebugOptions** (interface)
6669
+ ```typescript
6670
+ interface ConditionDebugOptions {
6671
+ enabled?: boolean
6672
+ logger?: ConditionDebugLogger
6673
+ label?: string
6674
+ }
6675
+ ```
6676
+
6677
+ **RegionKey** = `keyof typeof REGION_COUNTRIES`
6678
+
6679
+ **Condition** = ``
6680
+
6681
+ **ConditionDebugLogger** = `(...args: any[]) => void`
6682
+
6683
+ ### paths (utils)
6684
+
6685
+ **PortalPathParams** (interface)
6686
+ ```typescript
6687
+ interface PortalPathParams {
6688
+ collection: Collection | { shortId: string; portalUrl?: string }
6689
+ product?: Product
6690
+ productId?: string
6691
+ batch?: BatchResponse
6692
+ batchId?: string
6693
+ variant?: { id: string } | string
6694
+ proof?: Proof | string
6695
+ queryParams?: Record<string, string>
6696
+ pathOnly?: boolean
6697
+ }
6698
+ ```
6699
+
6415
6700
  ## API Functions
6416
6701
 
6417
6702
  ### analytics.admin
@@ -8169,6 +8454,33 @@ Reverse lookup by ref via POST (public). `POST /public/collection/:collectionId/
8169
8454
  **renderSource**(collectionId: string,
8170
8455
  body: TemplateRenderSourceRequest) → `Promise<TemplateRenderSourceResponse>`
8171
8456
 
8457
+ ### translations
8458
+
8459
+ **hashText**(text: string, options?: TranslationHashOptions) → `Promise<string>`
8460
+
8461
+ **hashTexts**(texts: string[], options?: TranslationHashOptions) → `Promise<string[]>`
8462
+
8463
+ **normalizeText**(text: string, options?: TranslationHashOptions) → `string`
8464
+
8465
+ **lookup**(collectionId: string,
8466
+ body: TranslationLookupRequest) → `Promise<TranslationLookupResponse>`
8467
+
8468
+ **resolve**(collectionId: string,
8469
+ body: TranslationLookupRequest,
8470
+ options: TranslationResolveOptions = {}) → `Promise<ResolvedTranslationResponse>`
8471
+
8472
+ **list**(collectionId: string,
8473
+ params?: TranslationListParams) → `Promise<TranslationListResponse>`
8474
+
8475
+ **get**(collectionId: string,
8476
+ translationId: string) → `Promise<TranslationRecord>`
8477
+
8478
+ **update**(collectionId: string,
8479
+ translationId: string,
8480
+ body: TranslationUpdateRequest) → `Promise<TranslationRecord>`
8481
+
8482
+ **clearLocalCache**(collectionId?: string) → `Promise<void>`
8483
+
8172
8484
  ### tts
8173
8485
 
8174
8486
  **generate**(collectionId: string,
package/docs/overview.md CHANGED
@@ -49,6 +49,7 @@ The SmartLinks SDK (`@proveanything/smartlinks`) includes comprehensive document
49
49
  | **Multi-Page Architecture** | `docs/mpa.md` | Build pipeline, entry points, multi-page setup, content hashing |
50
50
  | **AI & Chat** | `docs/ai.md` | Chat completions, RAG, streaming, tool calling, voice, podcasts, TTS |
51
51
  | **Analytics** | `docs/analytics.md` | Fire-and-forget page/click/tag analytics plus admin dashboard queries |
52
+ | **Translations** | `docs/translations.md` | Runtime translation lookup, local-first IndexedDB caching, and translation admin APIs |
52
53
  | **Theming** | `docs/theme.system.md` | Implementing dynamic themes via URL params or postMessage |
53
54
  | **Theme Defaults** | `docs/theme-defaults.md` | Default colour values for light/dark modes |
54
55
  | **Internationalization** | `docs/i18n.md` | Adding multi-language support, translation patterns |
@@ -0,0 +1,335 @@
1
+ # SmartLinks Translations
2
+
3
+ Runtime translation API for collection-scoped UI strings and content blocks, with optional browser-side IndexedDB caching.
4
+
5
+ This guide covers the new `translations` namespace in the SDK.
6
+
7
+ ## When To Use This
8
+
9
+ Use `translations` when you need to translate dynamic runtime content such as:
10
+
11
+ - product descriptions fetched from APIs
12
+ - customer-configurable portal copy
13
+ - CMS-driven long-form content blocks
14
+ - repeated UI strings that should be cached per collection and language
15
+
16
+ This is different from the static app-local i18n flow in [i18n.md](i18n.md), which is still the right choice for build-time translation keys such as button labels and route titles.
17
+
18
+ ## Two Levels Of API
19
+
20
+ The SDK exposes two ways to work with translations:
21
+
22
+ ### 1. `translations.lookup(...)`
23
+
24
+ This is the direct backend API wrapper.
25
+
26
+ - calls `POST /public/collection/:collectionId/translations/lookup`
27
+ - sends one string or many strings
28
+ - returns the server response as-is
29
+ - does not check local IndexedDB first
30
+
31
+ ### 2. `translations.resolve(...)`
32
+
33
+ This is the enriched client helper for front-end use.
34
+
35
+ - hashes each source string locally
36
+ - checks the browser-local translation cache first
37
+ - sends only cache misses to the backend
38
+ - stores successful results back into IndexedDB
39
+ - preserves the original input order, including duplicates
40
+
41
+ For browser apps, `resolve(...)` is the recommended default.
42
+
43
+ ## Quick Start
44
+
45
+ ```ts
46
+ import { initializeApi, translations } from '@proveanything/smartlinks'
47
+
48
+ initializeApi({ baseURL: 'https://smartlinks.app/api/v1' })
49
+
50
+ const response = await translations.resolve('collection-123', {
51
+ targetLanguage: 'fr',
52
+ sourceLanguage: 'en',
53
+ context: {
54
+ surface: 'portal-product-page',
55
+ field: 'description',
56
+ },
57
+ texts: [
58
+ 'Welcome to the product page',
59
+ 'Scan to verify authenticity',
60
+ ],
61
+ })
62
+
63
+ console.log(response.items.map((item) => item.translatedText))
64
+ ```
65
+
66
+ ## Raw Backend Lookup
67
+
68
+ Use `lookup(...)` if you want the SDK to stay close to the backend contract.
69
+
70
+ ```ts
71
+ const response = await translations.lookup('collection-123', {
72
+ targetLanguage: 'de',
73
+ text: 'Claim your item',
74
+ })
75
+
76
+ console.log(response.items[0].translatedText)
77
+ ```
78
+
79
+ ### Batch Lookup
80
+
81
+ ```ts
82
+ const response = await translations.lookup('collection-123', {
83
+ targetLanguage: 'es',
84
+ sourceLanguage: 'en',
85
+ mode: 'cache-fill',
86
+ contentType: 'text/plain',
87
+ texts: [
88
+ 'Welcome to the product page',
89
+ 'Scan to verify authenticity',
90
+ ],
91
+ returnMeta: true,
92
+ })
93
+ ```
94
+
95
+ ## Content Types
96
+
97
+ `contentType` is part of the translation cache identity. Use it to tell the backend what kind of content is being translated so it can preserve structure correctly.
98
+
99
+ ### `text/plain`
100
+
101
+ Use this for normal strings, paragraphs, labels, and other plain text content with no markup.
102
+
103
+ ```ts
104
+ await translations.resolve('collection-123', {
105
+ targetLanguage: 'fr',
106
+ sourceLanguage: 'en',
107
+ contentType: 'text/plain',
108
+ texts: [
109
+ 'Welcome to the product page',
110
+ 'Scan to verify authenticity',
111
+ ],
112
+ })
113
+ ```
114
+
115
+ ### `text/html`
116
+
117
+ Use this when the source contains HTML tags that must survive translation unchanged. This is important for rich text descriptions, CMS content, and formatted snippets.
118
+
119
+ ```ts
120
+ await translations.resolve('collection-123', {
121
+ targetLanguage: 'de',
122
+ sourceLanguage: 'en',
123
+ contentType: 'text/html',
124
+ context: {
125
+ surface: 'portal-product-page',
126
+ field: 'rich-description',
127
+ },
128
+ texts: [
129
+ '<p>Welcome to the <strong>product page</strong>.</p>',
130
+ '<p>Scan the tag to <a href="/verify">verify authenticity</a>.</p>',
131
+ ],
132
+ })
133
+ ```
134
+
135
+ Use `text/html` when you want the translation system to preserve tags such as:
136
+
137
+ - `<p>`, `<strong>`, `<em>`
138
+ - `<ul>`, `<li>`
139
+ - `<a>`
140
+ - inline markup embedded in CMS-rendered HTML
141
+
142
+ ### `text/x-liquid`
143
+
144
+ Use this when the content includes Liquid syntax that must be preserved exactly, including output tags, control-flow blocks, and filters.
145
+
146
+ ```ts
147
+ await translations.resolve('collection-123', {
148
+ targetLanguage: 'es',
149
+ sourceLanguage: 'en',
150
+ contentType: 'text/x-liquid',
151
+ context: {
152
+ surface: 'portal-email-template',
153
+ field: 'body',
154
+ },
155
+ texts: [
156
+ 'Hello {{ customer.first_name }}, your item {{ product.title }} is ready.',
157
+ '{% if claimable %}Claim your item{% else %}View item details{% endif %}',
158
+ ],
159
+ })
160
+ ```
161
+
162
+ Use `text/x-liquid` when the source includes constructs such as:
163
+
164
+ - `{{ customer.first_name }}`
165
+ - `{{ product.title | upcase }}`
166
+ - `{% if claimable %}...{% endif %}`
167
+ - loop or conditional blocks used in templates
168
+
169
+ ### Choosing The Right Value
170
+
171
+ - use `text/plain` for normal strings with no markup
172
+ - use `text/html` when HTML tags are part of the source and must be preserved
173
+ - use `text/x-liquid` when Liquid template syntax is part of the source and must be preserved
174
+
175
+ Do not mix plain text, HTML, and Liquid under the same `contentType` if you want stable cache keys and predictable translation behavior.
176
+
177
+ ## Local-First Resolution
178
+
179
+ `resolve(...)` is intended for browser rendering paths where repeated translations should not keep hitting the network.
180
+
181
+ ```ts
182
+ const response = await translations.resolve('collection-123', {
183
+ targetLanguage: 'fr',
184
+ sourceLanguage: 'en',
185
+ texts: [
186
+ 'Welcome to the product page',
187
+ 'Welcome to the product page',
188
+ 'Scan to verify authenticity',
189
+ ],
190
+ })
191
+
192
+ for (const item of response.items) {
193
+ console.log(item.index, item.cacheSource, item.translatedText)
194
+ }
195
+ ```
196
+
197
+ ### Default Client Cache Behavior
198
+
199
+ - cache backend hits in IndexedDB when available
200
+ - fall back to in-memory cache when IndexedDB is unavailable
201
+ - expire entries lazily on read
202
+ - keep entries for 90 days by default
203
+
204
+ IndexedDB does not provide native time-based expiry, so the SDK stores `expiresAt` and evicts stale records when reading them.
205
+
206
+ ### Configure Local Cache TTL
207
+
208
+ ```ts
209
+ await translations.resolve('collection-123', {
210
+ targetLanguage: 'fr',
211
+ texts: ['Limited edition'],
212
+ }, {
213
+ localCacheTtlMs: 180 * 24 * 60 * 60_000,
214
+ })
215
+ ```
216
+
217
+ ### Force A Fresh Remote Lookup
218
+
219
+ ```ts
220
+ await translations.resolve('collection-123', {
221
+ targetLanguage: 'fr',
222
+ texts: ['Welcome back'],
223
+ }, {
224
+ refreshLocalCache: true,
225
+ })
226
+ ```
227
+
228
+ ### Disable The Local Cache
229
+
230
+ ```ts
231
+ await translations.resolve('collection-123', {
232
+ targetLanguage: 'fr',
233
+ texts: ['Welcome back'],
234
+ }, {
235
+ useLocalCache: false,
236
+ })
237
+ ```
238
+
239
+ ## Context Matters
240
+
241
+ The same source string can require different translations depending on where it appears. Pass stable context whenever the meaning can change.
242
+
243
+ ```ts
244
+ await translations.resolve('collection-123', {
245
+ targetLanguage: 'fr',
246
+ texts: ['Claim'],
247
+ context: {
248
+ surface: 'portal-product-page',
249
+ field: 'cta-button',
250
+ },
251
+ })
252
+ ```
253
+
254
+ The SDK derives a deterministic local cache key from `context` so browser-local entries do not collide across different UI surfaces.
255
+
256
+ ## Hashing Helpers
257
+
258
+ The SDK also exposes the normalization and hashing helpers used by the local cache flow.
259
+
260
+ ```ts
261
+ const hash = await translations.hashText('Welcome to the product page')
262
+
263
+ const hashes = await translations.hashTexts([
264
+ 'Welcome to the product page',
265
+ 'Scan to verify authenticity',
266
+ ])
267
+
268
+ const normalized = translations.normalizeText(' Hello\r\nWorld ')
269
+ ```
270
+
271
+ By default the hash path:
272
+
273
+ - normalizes CRLF to LF
274
+ - trims surrounding whitespace
275
+ - applies Unicode NFC normalization
276
+ - preserves interior whitespace unless `collapseWhitespace: true` is set
277
+
278
+ ## Clearing Local Cache
279
+
280
+ Clear all locally cached translations:
281
+
282
+ ```ts
283
+ await translations.clearLocalCache()
284
+ ```
285
+
286
+ Clear only one collection's local entries:
287
+
288
+ ```ts
289
+ await translations.clearLocalCache('collection-123')
290
+ ```
291
+
292
+ ## Admin APIs
293
+
294
+ The namespace also exposes basic admin translation management.
295
+
296
+ ### List
297
+
298
+ ```ts
299
+ const page = await translations.list('collection-123', {
300
+ targetLanguage: 'fr',
301
+ q: 'authenticity',
302
+ limit: 20,
303
+ offset: 0,
304
+ })
305
+ ```
306
+
307
+ ### Get One
308
+
309
+ ```ts
310
+ const record = await translations.get('collection-123', 'translation-id')
311
+ ```
312
+
313
+ ### Update One
314
+
315
+ ```ts
316
+ const updated = await translations.update('collection-123', 'translation-id', {
317
+ translatedText: 'Bienvenue sur la page produit',
318
+ isOverride: true,
319
+ quality: 'human',
320
+ })
321
+ ```
322
+
323
+ ## Recommended Usage Pattern
324
+
325
+ For front-end rendering:
326
+
327
+ 1. Use static app-local i18n for fixed UI keys.
328
+ 2. Use `translations.resolve(...)` for dynamic runtime content.
329
+ 3. Always pass `context` for ambiguous strings.
330
+ 4. Prefer batched requests for multiple strings on the same screen.
331
+
332
+ For back-office or tooling flows:
333
+
334
+ 1. Use `translations.lookup(...)` for direct backend access.
335
+ 2. Use `translations.list/get/update` for translation review and correction workflows.