@procore/ai-translations 0.6.0 → 0.6.1

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.
@@ -0,0 +1,257 @@
1
+ # `@procore/ai-translations` Internal Guide
2
+
3
+ Internal engineering reference for operating and evolving this package in Procore environments.
4
+
5
+ Public consumer docs live in `README.md`.
6
+
7
+ ## Package Purpose
8
+
9
+ `@procore/ai-translations` provides a shared translation runtime for MFEs:
10
+
11
+ - context-based API (`AITranslationProvider`, `useAITranslation`)
12
+ - component-level translation (`AITranslateText`)
13
+ - strategy switching via remote config (`frontend_translations` / `backend_translations`)
14
+ - queue, batching, cache persistence, and cross-component rerender events
15
+
16
+ ## Internal Architecture
17
+
18
+ ```mermaid
19
+ flowchart LR
20
+ consumerComponent[ConsumerComponent] --> aiTranslateText[AITranslateText]
21
+ consumerComponent --> useHook[useAITranslation]
22
+ aiTranslateText --> providerContext[AITranslationProviderContext]
23
+ useHook --> providerContext
24
+ providerContext --> aitFn["ait(text)"]
25
+ providerContext --> configHook[useConfig]
26
+ aitFn --> registry[TranslationRegistry]
27
+ aitFn --> queue[queueManager]
28
+ queue --> manager[TranslationManager]
29
+ manager --> translatorFactory[TranslatorFactory]
30
+ translatorFactory --> frontendClient[FrontendChromeClient]
31
+ translatorFactory --> backendClient[BackendApiClient]
32
+ manager --> storage[IndexedDBStorage]
33
+ manager --> events[EventHandler]
34
+ events --> aiTranslateText
35
+ ```
36
+
37
+ Key files:
38
+
39
+ - `src/Provider.tsx`: context lifecycle, progress subscriptions, config update wiring
40
+ - `src/utils/core.ts`: `aitFunction` orchestration and registration flow
41
+ - `src/utils/translationManager.ts`: queue drain + batch translation + persistence
42
+ - `src/utils/translationRegistry.ts`: memory/DB-backed translation registry
43
+ - `src/utils/eventHandler.ts`: tool-scoped publish/subscribe events
44
+ - `src/configuration/configurationClient.ts`: config API client
45
+ - `src/translators/*`: frontend and backend translation clients
46
+
47
+ ## Detailed Runtime Flow
48
+
49
+ This package is intentionally asynchronous and eventual-consistency based for UI safety and throughput:
50
+
51
+ 1. `AITranslateText` calls `context.ait(text)`.
52
+ 2. `aitFunction` (`src/utils/core.ts`) checks:
53
+ - empty input
54
+ - non-retryable text set
55
+ - in-memory/IndexedDB registry hit
56
+ 3. On cache miss:
57
+ - creates entry ID (`Storage.generateId`)
58
+ - deduplicates with `enqueuedItems`
59
+ - appends to strategy-specific global queue (`queueManager`)
60
+ - schedules `TranslationManager.translate()` on microtask
61
+ 4. `TranslationManager`:
62
+ - guards against concurrent runs via global in-progress flags
63
+ - drains queue in batches based on active `ToolConfig`
64
+ - delegates translation to `Translator` (frontend/backend strategy)
65
+ - persists translated entries (`Storage.saveTranslation`)
66
+ - emits translation-complete and progress events
67
+ 5. Provider listens for complete events, repopulates registry, and triggers rerender event.
68
+ 6. `AITranslateText` receives rerender event and re-calls `ait(text)` to display translated output.
69
+
70
+ ```mermaid
71
+ sequenceDiagram
72
+ participant ui as UIComponent
73
+ participant textComp as AITranslateText
74
+ participant provider as AITranslationProvider
75
+ participant core as aitFunction
76
+ participant queue as queueManager
77
+ participant mgr as TranslationManager
78
+ participant tr as Translator
79
+ participant db as StorageIndexedDB
80
+ participant evt as EventHandler
81
+
82
+ ui->>textComp: render text
83
+ textComp->>provider: get context
84
+ textComp->>core: ait(text)
85
+ core->>db: lookup by key
86
+ alt cache hit
87
+ core-->>textComp: translated text
88
+ else cache miss
89
+ core->>queue: enqueue entry
90
+ core->>mgr: schedule translate()
91
+ core-->>textComp: original text
92
+ mgr->>tr: processTranslations(batch)
93
+ tr-->>mgr: translation results
94
+ mgr->>db: persist results
95
+ mgr->>evt: publish translation complete
96
+ evt-->>textComp: rerender event
97
+ textComp->>core: ait(text) again
98
+ core-->>textComp: translated text
99
+ end
100
+ ```
101
+
102
+ ## API Surface (Current Exports)
103
+
104
+ From `src/index.ts`:
105
+
106
+ - `AITranslationProvider`
107
+ - `AITranslateText`
108
+ - hooks from `src/hooks`
109
+ - `AITranslateTextProps`
110
+ - `TranslatedIconProps`
111
+ - `getAITranslationLDId`
112
+ - `AI_TRANSLATION_FEATURE_FLAG_KEY`
113
+
114
+ Not exported from root:
115
+
116
+ - `AITranslate` component (`src/components/AITranslate.tsx`) is internal-only unless imported by path
117
+ - `TranslatedIcon` component itself is not root-exported
118
+
119
+ ## Runtime Configuration
120
+
121
+ Config fetch:
122
+
123
+ - Base URL: `${window.location.origin}/rest/v1.0/`
124
+ - Endpoint path: `configuration?toolName=...&companyId=...&projectId=...&userId=...`
125
+ - Polling interval: every 30 minutes (`useConfig`)
126
+
127
+ Tool config shape:
128
+
129
+ ```ts
130
+ type ToolConfig = {
131
+ strategy: 'frontend_translations' | 'backend_translations';
132
+ supportedLocales: string[];
133
+ translationBatchSize: number;
134
+ renderingBatchSize: number;
135
+ apiTimeout: number;
136
+ apiVersion: string;
137
+ };
138
+ ```
139
+
140
+ Behavioral notes:
141
+
142
+ - The provider applies remote tool config and locale to the active translator config.
143
+ - Strategy changes may invalidate in-memory queue/registry assumptions between cycles.
144
+ - Invalid ID values in config fetch options throw validation errors in `ConfigurationClient`.
145
+
146
+ ## Data Model and Storage Semantics
147
+
148
+ - Registry keying uses hashed tuple: `sourceText + targetLanguage + tool`.
149
+ - Queue entries are tracked per strategy (`frontend_translations` / `backend_translations`).
150
+ - Enqueued dedupe key: `${id}:${strategy}`.
151
+ - Persistent storage uses IndexedDB via `src/utils/storage.ts`.
152
+ - Cache invalidation behavior:
153
+ - frontend-translated entries are removed if runtime switches to backend strategy
154
+ - tool/strategy-level deletes clear memory indexes and queue markers
155
+
156
+ ## Patterns Used
157
+
158
+ - **Provider + Context pattern**: `AITranslationProvider` exposes translation API and state.
159
+ - **Facade pattern**: `aitFunction` hides queueing, dedupe, cache, persistence, and scheduling details behind `ait(text)`.
160
+ - **Factory pattern**: `Translator` chooses strategy-specific client from config.
161
+ - **Adapter pattern**: frontend and backend clients implement the shared translator client contract.
162
+ - **Pub/Sub pattern**: `EventHandler` dispatches translation-complete, rerender, progress, and model-download events.
163
+ - **Repository/Registry pattern**: `TranslationRegistry` provides unified access over in-memory + IndexedDB states.
164
+ - **Batch processing pattern**: `TranslationManager` drains queue incrementally and emits progress snapshots.
165
+ - **Idempotent enqueue pattern**: enqueued set prevents duplicate work for the same text/strategy.
166
+
167
+ ## Translation Strategies
168
+
169
+ ### Frontend strategy
170
+
171
+ - Uses Chromium AI APIs through `ChromeTranslator`
172
+ - Supported browser list is currently in `src/translators/frontend_translators/chrome/client.ts`
173
+ - Intended for Chrome-family browsers
174
+ - Individual source texts are normalized to single-text requests before translation (`normalizeFrontendRequests`)
175
+
176
+ ### Backend strategy
177
+
178
+ - Uses `@procore/core-http` client
179
+ - Translation endpoint: `POST /translations` on configured API base URL
180
+ - Returns grouped translation records with retry metadata normalization
181
+ - Failed network/API responses are transformed into retryable structured translation failures
182
+
183
+ ## Feature Flag Utilities
184
+
185
+ `src/utils/featureFlag.ts`:
186
+
187
+ - storage key: `AI_TRANSLATION_FEATURE_FLAG_KEY` (`ai-translation`)
188
+ - `getAITranslationLDId(domain)` maps by zone/environment and federal partition behavior
189
+
190
+ ## Concurrency and Progress Model
191
+
192
+ Concurrency control:
193
+
194
+ - `globalThis._FRONTEND_AI_TRANSLATION_IN_PROGRESS_`
195
+ - `globalThis._BACKEND_AI_TRANSLATION_IN_PROGRESS_`
196
+
197
+ Progress behavior:
198
+
199
+ - progress starts from queue size snapshot at translation start
200
+ - if queue grows during a run, total is expanded so percent stays monotonic and <= 100
201
+ - completion publishes reset event (`total = 0`) to clear UI progress bars
202
+
203
+ ```mermaid
204
+ flowchart TD
205
+ startRun[StartTranslationRun] --> strategyCheck[CheckStrategyFlag]
206
+ strategyCheck --> lockFlag[SetInProgressFlag]
207
+ lockFlag --> initTotal[InitializeProgressTotal]
208
+ initTotal --> processBatch[ProcessBatch]
209
+ processBatch --> updateProgress[UpdateProgress]
210
+ updateProgress --> hasMore{QueueHasMore}
211
+ hasMore -->|yes| processBatch
212
+ hasMore -->|no| resetProgress[ResetProgressToZero]
213
+ resetProgress --> releaseFlag[ClearInProgressFlag]
214
+ ```
215
+
216
+ ## Local Development
217
+
218
+ From package root:
219
+
220
+ ```bash
221
+ yarn build
222
+ yarn test
223
+ yarn test:integration
224
+ yarn lint
225
+ yarn storybook
226
+ yarn cypress:run
227
+ ```
228
+
229
+ Helpful variants:
230
+
231
+ - `yarn cypress:run:integration`
232
+ - `yarn cypress:run:component`
233
+ - `yarn cypress:run:headed`
234
+
235
+ ## CI and Quality Gates
236
+
237
+ - CircleCI job coverage includes package tests and Cypress execution
238
+ - Sonar config exists at `sonar-project.properties`
239
+ - `prepublishOnly` runs `yarn build`
240
+
241
+ ## Internal Troubleshooting
242
+
243
+ - If translations do not appear, verify:
244
+ - provider wrapper exists at app root
245
+ - config endpoint returns expected `ToolConfig`
246
+ - chosen strategy is supported in current browser/runtime
247
+ - If progress is stuck:
248
+ - inspect queue/manager integration tests in `src/__integration__`
249
+ - verify translation completion events are being published and subscribed
250
+ - If highlight/rerender behavior is inconsistent:
251
+ - validate tool names are consistent across provider and subscribers
252
+ - check `EventHandler` topic scoping and rerender subscription lifecycle
253
+ - If translation requests do not leave queue:
254
+ - verify in-progress flags were reset (no stale global lock)
255
+ - verify strategy-specific queue contains entries matching active strategy
256
+ - If stale translations appear after strategy switch:
257
+ - confirm registry/storage cleanup path for frontend-to-backend switch is executed
package/README.md CHANGED
@@ -1 +1,158 @@
1
- ### AI Translation Package
1
+ # `@procore/ai-translations`
2
+
3
+ React package for AI-powered UI string translation in frontend apps. It provides:
4
+
5
+ - `AITranslationProvider` to initialize translation context
6
+ - `AITranslateText` to render translated text
7
+ - `useAITranslation` for direct access to translation and progress state
8
+
9
+ Need deeper implementation details? See the internal guide: [`README.internal.md`](./README.internal.md).
10
+
11
+ This package supports two runtime strategies:
12
+
13
+ - `frontend_translations`: browser-based translation (Chrome-family AI APIs)
14
+ - `backend_translations`: server-side translation API
15
+
16
+ For Procore-specific operational details, see `README.internal.md`.
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ yarn add @procore/ai-translations
22
+ ```
23
+
24
+ Peer dependencies:
25
+
26
+ - `react` `>= 16 < 19`
27
+ - `react-dom` `>= 16 < 19`
28
+ - `@procore/web-sdk-mfe-utils` `> 1.0.0 < 2`
29
+
30
+ ## Quick Start
31
+
32
+ ```tsx
33
+ import React from 'react';
34
+ import {
35
+ AITranslationProvider,
36
+ AITranslateText,
37
+ } from '@procore/ai-translations';
38
+
39
+ export function AppRoot() {
40
+ return (
41
+ <AITranslationProvider
42
+ tool="timecard"
43
+ companyId={1}
44
+ projectId={10}
45
+ userId={42}
46
+ locale="es"
47
+ enableAIT={true}
48
+ companyLocale="de-DE"
49
+ projectLocale="fr-CA"
50
+ >
51
+ <AITranslateText text="Hello world" shouldTranslate={true} />
52
+ </AITranslationProvider>
53
+ );
54
+ }
55
+ ```
56
+
57
+ ## Public API
58
+
59
+ ### `AITranslationProvider`
60
+
61
+ Required props:
62
+
63
+ - `locale: string` - target locale (BCP-47, for example `es`, `fr`, `de`)
64
+ - `tool: string` - tool/MFE identifier used to scope translation events
65
+ - `companyId: number`
66
+ - `projectId: number`
67
+ - `userId: number`
68
+
69
+ Optional props:
70
+
71
+ - `enableAIT?: boolean` (default `true`) - when `false`, returns source text without translation
72
+ - `companyLocale?: string` - company-level locale from environment metadata (e.g. `"de-DE"`); passed through to context for downstream consumers such as Amplitude
73
+ - `projectLocale?: string` - project-level locale from environment metadata (e.g. `"fr-CA"`); passed through to context for downstream consumers such as Amplitude
74
+
75
+ ### `AITranslateText`
76
+
77
+ Props:
78
+
79
+ - `text: string`
80
+ - `shouldTranslate: boolean`
81
+ - `showHighlight?: boolean` (default `false`)
82
+ - `translatedIconProps?: TranslatedIconProps`
83
+
84
+ ### `useAITranslation()`
85
+
86
+ Returns:
87
+
88
+ - `ait(text: string): Promise<string>` - translates text or returns cached value
89
+ - `locale: string`
90
+ - `companyLocale: string | undefined` - company-level locale from environment metadata
91
+ - `projectLocale: string | undefined` - project-level locale from environment metadata
92
+ - `tool: string`
93
+ - `translationProgress: { progress: number; current: number; total: number } | null`
94
+ - `modelDownloadProgress: ModelDownloadProgress | null`
95
+ - `renderVersion: number | undefined`
96
+
97
+ ### Feature flag helpers
98
+
99
+ - `AI_TRANSLATION_FEATURE_FLAG_KEY`
100
+ - `getAITranslationLDId(domain: string)`
101
+
102
+ ## How It Works
103
+
104
+ ```mermaid
105
+ flowchart LR
106
+ consumerApp[ConsumerApp] --> provider[AITranslationProvider]
107
+ provider --> aitCall["ait(text)"]
108
+ aitCall --> registryCheck[TranslationRegistryCheck]
109
+ registryCheck --> returnCached[ReturnCachedText]
110
+ registryCheck --> queueText[QueueText]
111
+ queueText --> manager[TranslationManager]
112
+ manager --> strategy[TranslatorStrategy]
113
+ strategy --> frontendClient[ChromeFrontendClient]
114
+ strategy --> backendClient[BackendApiClient]
115
+ frontendClient --> persist[PersistToIndexedDB]
116
+ backendClient --> persist
117
+ persist --> publish[PublishTranslationEvents]
118
+ publish --> rerender[AITranslateTextRerender]
119
+ rerender --> translatedUi[DisplayTranslatedText]
120
+ ```
121
+
122
+ At runtime, strings are registered through `ait()`, processed in batches, cached in memory and IndexedDB, and then rerendered via package events.
123
+
124
+ ## Configuration
125
+
126
+ The provider uses `useConfig` (React Query) to fetch translation config and refetch every 30 minutes.
127
+
128
+ Expected remote config shape:
129
+
130
+ ```ts
131
+ type ToolConfig = {
132
+ strategy: 'frontend_translations' | 'backend_translations';
133
+ supportedLocales: string[];
134
+ translationBatchSize: number;
135
+ renderingBatchSize: number;
136
+ apiTimeout: number;
137
+ apiVersion: string;
138
+ };
139
+ ```
140
+
141
+ ## Operational Notes
142
+
143
+ - `AITranslateText` and `useAITranslation` must be used inside `AITranslationProvider`.
144
+ - Frontend strategy depends on Chrome-family AI support; behavior differs by browser support.
145
+ - Backend/config endpoints are resolved from `window.location.origin` under `/rest/`.
146
+ - Translation cache uses IndexedDB; some restricted browser environments may limit persistence.
147
+
148
+ ## Development
149
+
150
+ From `packages/ai-translations`:
151
+
152
+ ```bash
153
+ yarn build
154
+ yarn test
155
+ yarn lint
156
+ yarn storybook
157
+ yarn cypress:run
158
+ ```
@@ -2,6 +2,35 @@ import * as _tanstack_react_query from '@tanstack/react-query';
2
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
3
3
  import React, { ReactNode } from 'react';
4
4
 
5
+ /** Shape of an analytic event passed to the MFE's `onTrackAnalyticsEvent` callback. */
6
+ interface AnalyticEvent {
7
+ key: string;
8
+ properties: Record<string, unknown>;
9
+ }
10
+ /** Function provided by the MFE that sends the event to the analytics destination. */
11
+ type AIAnalyticsTracker = (event: AnalyticEvent) => void;
12
+ /** Feature scope: `'project'` for project-level tools, `'company'` for company-level tools. */
13
+ type Scope = 'project' | 'company';
14
+ /**
15
+ * Parts needed to build an event key following the pattern:
16
+ * `ux.web.feature.{scope}.{tool}.{object}.{action}`
17
+ */
18
+ interface EventKeyParts {
19
+ scope: Scope;
20
+ tool: string;
21
+ object: string;
22
+ action: string;
23
+ }
24
+ /** Standard properties included in every AI analytics event. */
25
+ interface AIAnalyticsEventProperties {
26
+ user_locale: string;
27
+ project_locale?: string;
28
+ company_locale?: string;
29
+ tool: string;
30
+ page: string;
31
+ [key: string]: unknown;
32
+ }
33
+
5
34
  interface TranslationProgress {
6
35
  /**
7
36
  * Progress percentage (0-100)
@@ -39,12 +68,22 @@ interface ModelDownloadProgress {
39
68
  interface AITranslationContextValue {
40
69
  ait: (text: string) => Promise<string>;
41
70
  locale: string;
71
+ /** Company-level locale from environment metadata (e.g. `"de-DE"`). */
72
+ companyLocale?: string;
73
+ /** Project-level locale from environment metadata (e.g. `"fr-CA"`). */
74
+ projectLocale?: string;
42
75
  renderVersion?: number;
43
76
  /** Batch-translation progress; `null` while the queue is idle. */
44
77
  translationProgress: TranslationProgress | null;
45
78
  /** Chrome AI model download progress; `null` until a download begins. */
46
79
  modelDownloadProgress: ModelDownloadProgress | null;
47
80
  tool: string;
81
+ /** Called by `useAIAnalytics` with a fully assembled event. The MFE is responsible for sending it. */
82
+ onTrackAnalyticsEvent?: AIAnalyticsTracker;
83
+ /** Page context used to build the event key object segment (e.g. `'view'`, `'list_column_description'`). */
84
+ page?: string;
85
+ /** Feature scope: `'project'` or `'company'`. */
86
+ scope?: Scope;
48
87
  }
49
88
 
50
89
  interface ConfigurationResponse {
@@ -117,6 +156,59 @@ declare function useConfig(toolName: string, options?: UseConfigOptions): _tanst
117
156
  */
118
157
  declare function useAITranslation(): AITranslationContextValue;
119
158
 
159
+ /** Button type identifiers for the event key `object` segment. */
160
+ declare const BUTTON_TYPE: {
161
+ readonly TRANSLATE: "translate";
162
+ readonly HIGHLIGHT: "highlight";
163
+ };
164
+ type ButtonType = (typeof BUTTON_TYPE)[keyof typeof BUTTON_TYPE];
165
+ /** Action identifiers for the event key `action` segment. */
166
+ declare const ACTION: {
167
+ readonly CLICKED: "clicked";
168
+ };
169
+ type Action = (typeof ACTION)[keyof typeof ACTION];
170
+ /**
171
+ * Builds the `object` segment: `{pageContext}_{buttonType}_button`
172
+ * e.g. `buildObject('view', 'translate')` → `'view_translate_button'`
173
+ */
174
+ declare function buildObject(pageContext: string, buttonType: ButtonType): string;
175
+ /**
176
+ * Builds a fully-qualified event key:
177
+ * `ux.web.feature.{scope}.{tool}.{object}.{action}`
178
+ */
179
+ declare function buildEventKey(parts: EventKeyParts): string;
180
+ interface BuildAnalyticEventParams {
181
+ scope: Scope;
182
+ tool: string;
183
+ /** Prefix for the object segment, matches the Provider `page` prop (e.g. `'view'`). */
184
+ pageContext: string;
185
+ buttonType: ButtonType;
186
+ baseProperties: AIAnalyticsEventProperties;
187
+ /** Defaults to `'clicked'` if omitted. */
188
+ action?: Action;
189
+ additionalProperties?: Record<string, unknown>;
190
+ }
191
+ /** Assembles a complete `AnalyticEvent` (key + merged properties) ready for `onTrackAnalyticsEvent`. */
192
+ declare function buildAnalyticEvent(params: BuildAnalyticEventParams): AnalyticEvent;
193
+
194
+ interface UseAIAnalyticsReturn {
195
+ /** Fires `ux.web.feature.{scope}.{tool}.{page}_translate_button.clicked`. */
196
+ trackTranslateButtonClicked: (additionalProperties?: Record<string, unknown>) => void;
197
+ /** Fires `ux.web.feature.{scope}.{tool}.{page}_highlight_button.clicked`. */
198
+ trackHighlightButtonClicked: (additionalProperties?: Record<string, unknown>) => void;
199
+ /** Generic tracking for custom button types or actions. */
200
+ trackCustomEvent: (buttonType: ButtonType | string, action?: Action | string, additionalProperties?: Record<string, unknown>) => void;
201
+ /** `true` when `onTrackAnalyticsEvent` was provided to `AITranslationProvider`. */
202
+ isTrackingEnabled: boolean;
203
+ }
204
+ /**
205
+ * Returns analytics tracking helpers pre-wired to the Provider context.
206
+ * All functions no-op if `onTrackAnalyticsEvent` was not supplied.
207
+ *
208
+ * @throws if called outside of an `AITranslationProvider`.
209
+ */
210
+ declare function useAIAnalytics(): UseAIAnalyticsReturn;
211
+
120
212
  interface AITranslationProviderProps {
121
213
  children: ReactNode;
122
214
  locale: string;
@@ -125,6 +217,16 @@ interface AITranslationProviderProps {
125
217
  userId: number;
126
218
  projectId: number;
127
219
  enableAIT?: boolean;
220
+ /** Company-level locale from environment metadata (e.g. `"de-DE"`). Passed through to context for downstream consumers such as Amplitude. */
221
+ companyLocale?: string;
222
+ /** Project-level locale from environment metadata (e.g. `"fr-CA"`). Passed through to context for downstream consumers such as Amplitude. */
223
+ projectLocale?: string;
224
+ /** Called by `useAIAnalytics` with a pre-assembled event. The MFE sends it to the analytics API. */
225
+ onTrackAnalyticsEvent?: AIAnalyticsTracker;
226
+ /** Page context for the event key object segment (e.g. `'view'`, `'list_column_description'`). */
227
+ page?: string;
228
+ /** Feature scope: `'project'` or `'company'`. */
229
+ scope?: Scope;
128
230
  }
129
231
  declare function AITranslationProvider(props: AITranslationProviderProps): react_jsx_runtime.JSX.Element;
130
232
 
@@ -177,4 +279,4 @@ declare global {
177
279
  var _BACKEND_AI_TRANSLATION_IN_PROGRESS_: boolean;
178
280
  }
179
281
 
180
- export { AITranslateText, type AITranslateTextProps, AITranslationProvider, AI_TRANSLATION_FEATURE_FLAG_KEY, type TranslatedIconProps, type UseConfigOptions, getAITranslationLDId, useAITranslation, useConfig };
282
+ export { ACTION, type AIAnalyticsEventProperties, type AIAnalyticsTracker, AITranslateText, type AITranslateTextProps, AITranslationProvider, AI_TRANSLATION_FEATURE_FLAG_KEY, type Action, type AnalyticEvent, BUTTON_TYPE, type BuildAnalyticEventParams, type ButtonType, type EventKeyParts, type Scope, type TranslatedIconProps, type UseAIAnalyticsReturn, type UseConfigOptions, buildAnalyticEvent, buildEventKey, buildObject, getAITranslationLDId, useAIAnalytics, useAITranslation, useConfig };
@@ -2,6 +2,35 @@ import * as _tanstack_react_query from '@tanstack/react-query';
2
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
3
3
  import React, { ReactNode } from 'react';
4
4
 
5
+ /** Shape of an analytic event passed to the MFE's `onTrackAnalyticsEvent` callback. */
6
+ interface AnalyticEvent {
7
+ key: string;
8
+ properties: Record<string, unknown>;
9
+ }
10
+ /** Function provided by the MFE that sends the event to the analytics destination. */
11
+ type AIAnalyticsTracker = (event: AnalyticEvent) => void;
12
+ /** Feature scope: `'project'` for project-level tools, `'company'` for company-level tools. */
13
+ type Scope = 'project' | 'company';
14
+ /**
15
+ * Parts needed to build an event key following the pattern:
16
+ * `ux.web.feature.{scope}.{tool}.{object}.{action}`
17
+ */
18
+ interface EventKeyParts {
19
+ scope: Scope;
20
+ tool: string;
21
+ object: string;
22
+ action: string;
23
+ }
24
+ /** Standard properties included in every AI analytics event. */
25
+ interface AIAnalyticsEventProperties {
26
+ user_locale: string;
27
+ project_locale?: string;
28
+ company_locale?: string;
29
+ tool: string;
30
+ page: string;
31
+ [key: string]: unknown;
32
+ }
33
+
5
34
  interface TranslationProgress {
6
35
  /**
7
36
  * Progress percentage (0-100)
@@ -39,12 +68,22 @@ interface ModelDownloadProgress {
39
68
  interface AITranslationContextValue {
40
69
  ait: (text: string) => Promise<string>;
41
70
  locale: string;
71
+ /** Company-level locale from environment metadata (e.g. `"de-DE"`). */
72
+ companyLocale?: string;
73
+ /** Project-level locale from environment metadata (e.g. `"fr-CA"`). */
74
+ projectLocale?: string;
42
75
  renderVersion?: number;
43
76
  /** Batch-translation progress; `null` while the queue is idle. */
44
77
  translationProgress: TranslationProgress | null;
45
78
  /** Chrome AI model download progress; `null` until a download begins. */
46
79
  modelDownloadProgress: ModelDownloadProgress | null;
47
80
  tool: string;
81
+ /** Called by `useAIAnalytics` with a fully assembled event. The MFE is responsible for sending it. */
82
+ onTrackAnalyticsEvent?: AIAnalyticsTracker;
83
+ /** Page context used to build the event key object segment (e.g. `'view'`, `'list_column_description'`). */
84
+ page?: string;
85
+ /** Feature scope: `'project'` or `'company'`. */
86
+ scope?: Scope;
48
87
  }
49
88
 
50
89
  interface ConfigurationResponse {
@@ -117,6 +156,59 @@ declare function useConfig(toolName: string, options?: UseConfigOptions): _tanst
117
156
  */
118
157
  declare function useAITranslation(): AITranslationContextValue;
119
158
 
159
+ /** Button type identifiers for the event key `object` segment. */
160
+ declare const BUTTON_TYPE: {
161
+ readonly TRANSLATE: "translate";
162
+ readonly HIGHLIGHT: "highlight";
163
+ };
164
+ type ButtonType = (typeof BUTTON_TYPE)[keyof typeof BUTTON_TYPE];
165
+ /** Action identifiers for the event key `action` segment. */
166
+ declare const ACTION: {
167
+ readonly CLICKED: "clicked";
168
+ };
169
+ type Action = (typeof ACTION)[keyof typeof ACTION];
170
+ /**
171
+ * Builds the `object` segment: `{pageContext}_{buttonType}_button`
172
+ * e.g. `buildObject('view', 'translate')` → `'view_translate_button'`
173
+ */
174
+ declare function buildObject(pageContext: string, buttonType: ButtonType): string;
175
+ /**
176
+ * Builds a fully-qualified event key:
177
+ * `ux.web.feature.{scope}.{tool}.{object}.{action}`
178
+ */
179
+ declare function buildEventKey(parts: EventKeyParts): string;
180
+ interface BuildAnalyticEventParams {
181
+ scope: Scope;
182
+ tool: string;
183
+ /** Prefix for the object segment, matches the Provider `page` prop (e.g. `'view'`). */
184
+ pageContext: string;
185
+ buttonType: ButtonType;
186
+ baseProperties: AIAnalyticsEventProperties;
187
+ /** Defaults to `'clicked'` if omitted. */
188
+ action?: Action;
189
+ additionalProperties?: Record<string, unknown>;
190
+ }
191
+ /** Assembles a complete `AnalyticEvent` (key + merged properties) ready for `onTrackAnalyticsEvent`. */
192
+ declare function buildAnalyticEvent(params: BuildAnalyticEventParams): AnalyticEvent;
193
+
194
+ interface UseAIAnalyticsReturn {
195
+ /** Fires `ux.web.feature.{scope}.{tool}.{page}_translate_button.clicked`. */
196
+ trackTranslateButtonClicked: (additionalProperties?: Record<string, unknown>) => void;
197
+ /** Fires `ux.web.feature.{scope}.{tool}.{page}_highlight_button.clicked`. */
198
+ trackHighlightButtonClicked: (additionalProperties?: Record<string, unknown>) => void;
199
+ /** Generic tracking for custom button types or actions. */
200
+ trackCustomEvent: (buttonType: ButtonType | string, action?: Action | string, additionalProperties?: Record<string, unknown>) => void;
201
+ /** `true` when `onTrackAnalyticsEvent` was provided to `AITranslationProvider`. */
202
+ isTrackingEnabled: boolean;
203
+ }
204
+ /**
205
+ * Returns analytics tracking helpers pre-wired to the Provider context.
206
+ * All functions no-op if `onTrackAnalyticsEvent` was not supplied.
207
+ *
208
+ * @throws if called outside of an `AITranslationProvider`.
209
+ */
210
+ declare function useAIAnalytics(): UseAIAnalyticsReturn;
211
+
120
212
  interface AITranslationProviderProps {
121
213
  children: ReactNode;
122
214
  locale: string;
@@ -125,6 +217,16 @@ interface AITranslationProviderProps {
125
217
  userId: number;
126
218
  projectId: number;
127
219
  enableAIT?: boolean;
220
+ /** Company-level locale from environment metadata (e.g. `"de-DE"`). Passed through to context for downstream consumers such as Amplitude. */
221
+ companyLocale?: string;
222
+ /** Project-level locale from environment metadata (e.g. `"fr-CA"`). Passed through to context for downstream consumers such as Amplitude. */
223
+ projectLocale?: string;
224
+ /** Called by `useAIAnalytics` with a pre-assembled event. The MFE sends it to the analytics API. */
225
+ onTrackAnalyticsEvent?: AIAnalyticsTracker;
226
+ /** Page context for the event key object segment (e.g. `'view'`, `'list_column_description'`). */
227
+ page?: string;
228
+ /** Feature scope: `'project'` or `'company'`. */
229
+ scope?: Scope;
128
230
  }
129
231
  declare function AITranslationProvider(props: AITranslationProviderProps): react_jsx_runtime.JSX.Element;
130
232
 
@@ -177,4 +279,4 @@ declare global {
177
279
  var _BACKEND_AI_TRANSLATION_IN_PROGRESS_: boolean;
178
280
  }
179
281
 
180
- export { AITranslateText, type AITranslateTextProps, AITranslationProvider, AI_TRANSLATION_FEATURE_FLAG_KEY, type TranslatedIconProps, type UseConfigOptions, getAITranslationLDId, useAITranslation, useConfig };
282
+ export { ACTION, type AIAnalyticsEventProperties, type AIAnalyticsTracker, AITranslateText, type AITranslateTextProps, AITranslationProvider, AI_TRANSLATION_FEATURE_FLAG_KEY, type Action, type AnalyticEvent, BUTTON_TYPE, type BuildAnalyticEventParams, type ButtonType, type EventKeyParts, type Scope, type TranslatedIconProps, type UseAIAnalyticsReturn, type UseConfigOptions, buildAnalyticEvent, buildEventKey, buildObject, getAITranslationLDId, useAIAnalytics, useAITranslation, useConfig };