@weavix/tracker-plugin-sdk-react 0.0.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.
package/AGENTS.md ADDED
@@ -0,0 +1,31 @@
1
+ # @weavix/tracker-plugin-sdk-react — agents
2
+
3
+ **Пакет:** React (Weavix / npm) + реэкспорт core.
4
+
5
+ ## Импорты
6
+
7
+ ```typescript
8
+ import {
9
+ TrackerPluginProvider,
10
+ useTrackerPluginContext,
11
+ useToaster,
12
+ useConfirm,
13
+ hostApi,
14
+ trackerApi,
15
+ } from '@weavix/tracker-plugin-sdk-react';
16
+ ```
17
+
18
+ ## Правила
19
+
20
+ - **contextLevel** `basic` / `full` — см. [COOKBOOK](../../docs/agent/COOKBOOK.md).
21
+ - **hostApi** + **trackerApi.v3** — см. [core AGENTS](../tracker-plugin-external/AGENTS.md).
22
+
23
+ ## Документация
24
+
25
+ | Файл | Назначение |
26
+ |------|------------|
27
+ | [../../AGENTS.md](../../AGENTS.md) | Общий вход |
28
+ | [../../docs/agent/COOKBOOK.md](../../docs/agent/COOKBOOK.md) | Рецепты |
29
+ | [README.md](./README.md) | Быстрый старт |
30
+ | [API_REFERENCE.md](./API_REFERENCE.md) | Provider, хуки |
31
+ | [../tracker-plugin-external/API_REFERENCE.md](../tracker-plugin-external/API_REFERENCE.md) | hostApi, uiApi, v3 |
@@ -0,0 +1,649 @@
1
+ # API Reference - @weavix/tracker-plugin-sdk-react
2
+
3
+ ## Table of Contents
4
+
5
+ - [Components](#components)
6
+ - [TrackerPluginProvider](#trackerpluginprovider)
7
+ - [Hooks](#hooks)
8
+ - [useTrackerPluginContext](#usetrackerplugincontext)
9
+ - [useLocalizedString](#uselocalizedstring)
10
+ - [Types](#types)
11
+ - [TrackerPluginProviderProps](#trackerpluginproviderprops)
12
+ - [TrackerPluginContextValue](#trackerplugincontextvalue)
13
+ - [BasicTrackerPluginContextValue](#basictrackerplugincontextvalue)
14
+ - [FullTrackerPluginContextValue](#fulltrackerplugincontextvalue)
15
+ - [Публичное API](#публичное-api) — hostApi, trackerApi (реэкспорт из core)
16
+ - [Утилиты](#утилиты)
17
+ - [getLocalizedString](#getlocalizedstring)
18
+
19
+ ---
20
+
21
+ ## Components
22
+
23
+ ### TrackerPluginProvider
24
+
25
+ Провайдер для инициализации плагина Tracker. Оборачивает приложение и управляет жизненным циклом плагина. Предоставляет тему, язык и контекст слота через контекст React.
26
+
27
+ **Props:** [`TrackerPluginProviderProps`](#trackerpluginproviderprops)
28
+
29
+ **Features:**
30
+
31
+ - Автоматическая инициализация плагина
32
+ - Управление состояниями загрузки и ошибок
33
+ - Предоставление контекста через React Context API
34
+ - Автоматическое уведомление хоста о готовности плагина
35
+ - Защита от двойной инициализации в React StrictMode
36
+
37
+ **Example (базовое использование):**
38
+
39
+ ```tsx
40
+ import { TrackerPluginProvider } from '@weavix/tracker-plugin-sdk-react';
41
+ import { createRoot } from 'react-dom/client';
42
+ import { App } from './App';
43
+
44
+ const root = createRoot(document.getElementById('root')!);
45
+
46
+ root.render(
47
+ <TrackerPluginProvider>
48
+ <App />
49
+ </TrackerPluginProvider>,
50
+ );
51
+ ```
52
+
53
+ **Example (с кастомными опциями):**
54
+
55
+ ```tsx
56
+ import { TrackerPluginProvider } from '@weavix/tracker-plugin-sdk-react';
57
+ import { Loader } from './components/Loader';
58
+ import { ErrorScreen } from './components/ErrorScreen';
59
+
60
+ root.render(
61
+ <TrackerPluginProvider
62
+ autoResize={false}
63
+ fallback={<Loader />}
64
+ errorFallback={(error) => <ErrorScreen error={error} />}
65
+ autoNotifyReady={false}
66
+ >
67
+ <App />
68
+ </TrackerPluginProvider>,
69
+ );
70
+ ```
71
+
72
+ **Example (отключение автоматического уведомления):**
73
+
74
+ ```tsx
75
+ import { TrackerPluginProvider, hostApi } from '@weavix/tracker-plugin-sdk-react';
76
+
77
+ function App() {
78
+ useEffect(() => {
79
+ // Выполняем дополнительную инициализацию, затем уведомляем хост
80
+ initializeApp().then(() => {
81
+ hostApi.notifyReady()
82
+ });
83
+ }, []);
84
+
85
+ return <div>My Plugin</div>;
86
+ }
87
+
88
+ root.render(
89
+ <TrackerPluginProvider autoNotifyReady={false}>
90
+ <App />
91
+ </TrackerPluginProvider>,
92
+ );
93
+ ```
94
+
95
+ ---
96
+
97
+ ## Hooks
98
+
99
+ ### useTrackerPluginContext
100
+
101
+ Хук для получения темы, языка и контекста слота из [`TrackerPluginProvider`](#trackerpluginprovider).
102
+
103
+ Поддерживает два уровня контекста, управляемых полем `contextLevel` в манифесте плагина:
104
+
105
+ - **`'basic'`** (по умолчанию) — `slotContext` содержит только `{ entityId, entityMeta? }`. Данные берутся из параметров iframe без postMessage-запроса к хосту.
106
+ - **`'full'`** — `slotContext` содержит полный объект слота (Issue и т.д.). Требует `contextLevel: "full"` в манифесте.
107
+
108
+ **Type Signature:**
109
+
110
+ ```typescript
111
+ // Без аргумента или с 'basic' — slotContext: BasicContext | undefined
112
+ function useTrackerPluginContext(): BasicTrackerPluginContextValue;
113
+ function useTrackerPluginContext(level: 'basic'): BasicTrackerPluginContextValue;
114
+
115
+ // С 'full' — slotContext: SlotContextMap[TSlot] | undefined
116
+ function useTrackerPluginContext(level: 'full'): FullTrackerPluginContextValue;
117
+
118
+ // С generic — типизированный контекст для конкретного слота
119
+ function useTrackerPluginContext<TSlot extends keyof SlotContextMap>(level?: 'basic'): BasicTrackerPluginContextValue<TSlot>;
120
+ function useTrackerPluginContext<TSlot extends keyof SlotContextMap>(level: 'full'): FullTrackerPluginContextValue<TSlot>;
121
+ ```
122
+
123
+ **Parameters:**
124
+
125
+ - `level` — `'basic' | 'full'` (опционально, по умолчанию `'basic'`). Уровень запрашиваемого контекста.
126
+
127
+ **Type Parameters:**
128
+
129
+ - `TSlot` — тип слота (опционально). С generic — `slotContext` типизирован под этот слот.
130
+
131
+ **Returns:** [`BasicTrackerPluginContextValue`](#basictrackerplugincontextvalue) или [`FullTrackerPluginContextValue`](#fulltrackerplugincontextvalue)
132
+
133
+ **Throws:**
134
+
135
+ - `Error` — если используется вне [`TrackerPluginProvider`](#trackerpluginprovider)
136
+ - `Error` — если код запрашивает `'full'` контекст, но манифест объявляет `'basic'` (runtime security guard)
137
+
138
+ **Example (базовый контекст — только entityId и entityMeta):**
139
+
140
+ ```tsx
141
+ import { useTrackerPluginContext } from '@weavix/tracker-plugin-sdk-react';
142
+
143
+ function MyPlugin() {
144
+ // По умолчанию — basic контекст
145
+ const { slotContext } = useTrackerPluginContext();
146
+ // slotContext: { entityId: string; entityMeta?: Record<string, string> } | undefined
147
+
148
+ return <div>Entity: {slotContext?.entityId}</div>;
149
+ }
150
+ ```
151
+
152
+ **Example (полный контекст — требует contextLevel: "full" в манифесте):**
153
+
154
+ ```tsx
155
+ import { useTrackerPluginContext } from '@weavix/tracker-plugin-sdk-react';
156
+
157
+ function IssuePlugin() {
158
+ const { theme, language, slotContext } = useTrackerPluginContext('full');
159
+ // slotContext: Issue | undefined (для слота issue.action)
160
+
161
+ return (
162
+ <div>
163
+ <h1>Issue: {slotContext?.key}</h1>
164
+ <p>Version: {slotContext?.version}</p>
165
+ <p>Theme: {theme}</p>
166
+ </div>
167
+ );
168
+ }
169
+ ```
170
+
171
+ **Example (полный контекст с типизацией слота):**
172
+
173
+ ```tsx
174
+ const { slotContext } = useTrackerPluginContext<'issue.action'>('full');
175
+ slotContext?.key; // тип контекста — Issue (из @weavix/tracker-core)
176
+ ```
177
+
178
+ **Example (несколько слотов — сужение по slot):**
179
+
180
+ ```tsx
181
+ const { slot, slotContext } = useTrackerPluginContext('full');
182
+ if (slot === 'issue.action') {
183
+ slotContext?.key; // здесь slotContext типизирован под слот issue.action
184
+ }
185
+ ```
186
+
187
+ ---
188
+
189
+ ### useLocalizedString
190
+
191
+ Хук для получения локализованной строки на основе текущего языка из контекста [`TrackerPluginProvider`](#trackerpluginprovider).
192
+
193
+ **Type Signature:**
194
+
195
+ ```typescript
196
+ function useLocalizedString(fallbackLanguage?: string): (value: LocalizedString) => string;
197
+ ```
198
+
199
+ **Parameters:**
200
+
201
+ - `fallbackLanguage` - `string` (опционально, по умолчанию 'en') - резервный язык, если основной не найден
202
+
203
+ **Returns:** Функция для локализации строк `(value: LocalizedString) => string`
204
+
205
+ **Example (базовое использование):**
206
+
207
+ ```tsx
208
+ import { useLocalizedString } from '@weavix/tracker-plugin-sdk-react';
209
+
210
+ function MyComponent() {
211
+ const localize = useLocalizedString();
212
+
213
+ const field = {
214
+ name: { ru: 'Имя', en: 'Name' },
215
+ description: { ru: 'Описание', en: 'Description' },
216
+ };
217
+
218
+ return (
219
+ <div>
220
+ <h1>{localize(field.name)}</h1>
221
+ <p>{localize(field.description)}</p>
222
+ </div>
223
+ );
224
+ }
225
+ ```
226
+
227
+ **Example (с резервным языком):**
228
+
229
+ ```tsx
230
+ import { useLocalizedString } from '@weavix/tracker-plugin-sdk-react';
231
+
232
+ function MyComponent() {
233
+ // Если перевод на текущем языке не найден, используется русский
234
+ const localize = useLocalizedString('ru');
235
+
236
+ const name = { en: 'Name' }; // нет русского перевода
237
+
238
+ return <div>{localize(name)}</div>; // вернет 'Name'
239
+ }
240
+ ```
241
+
242
+ **Example (работа с полями задачи):**
243
+
244
+ ```tsx
245
+ import {
246
+ useLocalizedString,
247
+ useTrackerPluginContext,
248
+ } from '@weavix/tracker-plugin-sdk-react';
249
+ import { trackerApi } from '@weavix/tracker-plugin-sdk-react';
250
+
251
+ function FieldsList() {
252
+ const localize = useLocalizedString();
253
+ const { slotContext } = useTrackerPluginContext<'issue.action'>();
254
+ const [fields, setFields] = useState([]);
255
+
256
+ useEffect(() => {
257
+ trackerApi.v3.get['/fields/...']({ ... }).then(setFields);
258
+ }, []);
259
+
260
+ return (
261
+ <ul>
262
+ {fields.map((field) => (
263
+ <li key={field.id}>
264
+ <strong>{localize(field.name)}</strong>
265
+ {field.description && <p>{localize(field.description)}</p>}
266
+ </li>
267
+ ))}
268
+ </ul>
269
+ );
270
+ }
271
+ ```
272
+
273
+ ---
274
+
275
+ ## Types
276
+
277
+ ### TrackerPluginProviderProps
278
+
279
+ Свойства компонента [`TrackerPluginProvider`](#trackerpluginprovider).
280
+
281
+ ```typescript
282
+ interface TrackerPluginProviderProps {
283
+ /** Дочерние элементы */
284
+ children: ReactNode;
285
+
286
+ /**
287
+ * Автоматически изменять размер контейнера плагина при изменении содержимого
288
+ * @default true
289
+ */
290
+ autoResize?: boolean;
291
+
292
+ /**
293
+ * Компонент для отображения во время инициализации
294
+ * @default <PluginLoader />
295
+ */
296
+ fallback?: ReactNode;
297
+
298
+ /**
299
+ * Компонент для отображения при ошибке инициализации
300
+ * @default <PluginError error={error} />
301
+ */
302
+ errorFallback?: (error: Error) => ReactNode;
303
+
304
+ /**
305
+ * Автоматически уведомить хост о готовности плагина после инициализации
306
+ * @default true
307
+ */
308
+ autoNotifyReady?: boolean;
309
+ }
310
+ ```
311
+
312
+ **Properties:**
313
+
314
+ #### `children`
315
+
316
+ - **Type:** `ReactNode`
317
+ - **Required:** Yes
318
+ - **Description:** Дочерние компоненты, которые будут отрендерены после успешной инициализации
319
+
320
+ #### `autoResize`
321
+
322
+ - **Type:** `boolean`
323
+ - **Required:** No
324
+ - **Description:** Автоматически изменять размер контейнера плагина при изменении содержимого. Включает отслеживание изменений DOM и автоматическую отправку новой высоты хосту.
325
+ - **Default:** `true`
326
+
327
+ **Example:**
328
+
329
+ ```tsx
330
+ <TrackerPluginProvider autoResize={false}>
331
+ <App />
332
+ </TrackerPluginProvider>
333
+ ```
334
+
335
+ **Note:** Отключайте autoResize, если вы управляете размером контейнера вручную (через доступный в конфигурации API).
336
+
337
+ #### `fallback`
338
+
339
+ - **Type:** `ReactNode`
340
+ - **Required:** No
341
+ - **Description:** Компонент, отображаемый во время инициализации плагина
342
+ - **Default:** Встроенный компонент `<PluginLoader />`
343
+
344
+ **Example:**
345
+
346
+ ```tsx
347
+ <TrackerPluginProvider fallback={<div>Loading...</div>}>
348
+ <App />
349
+ </TrackerPluginProvider>
350
+ ```
351
+
352
+ #### `errorFallback`
353
+
354
+ - **Type:** `(error: Error) => ReactNode`
355
+ - **Required:** No
356
+ - **Description:** Функция, возвращающая компонент для отображения при ошибке инициализации
357
+ - **Default:** Встроенный компонент `<PluginError error={error} />`
358
+
359
+ **Example:**
360
+
361
+ ```tsx
362
+ <TrackerPluginProvider
363
+ errorFallback={(error) => (
364
+ <div>
365
+ <h1>Error!</h1>
366
+ <p>{error.message}</p>
367
+ </div>
368
+ )}
369
+ >
370
+ <App />
371
+ </TrackerPluginProvider>
372
+ ```
373
+
374
+ #### `autoNotifyReady`
375
+
376
+ - **Type:** `boolean`
377
+ - **Required:** No
378
+ - **Description:** Автоматически уведомлять хост о готовности плагина после инициализации
379
+ - **Default:** `true`
380
+
381
+ **Example:**
382
+
383
+ ```tsx
384
+ <TrackerPluginProvider autoNotifyReady={false}>
385
+ <App />
386
+ </TrackerPluginProvider>
387
+ ```
388
+
389
+ ---
390
+
391
+ ### TrackerPluginContextValue
392
+
393
+ Union-тип: [`BasicTrackerPluginContextValue`](#basictrackerplugincontextvalue) | [`FullTrackerPluginContextValue`](#fulltrackerplugincontextvalue).
394
+
395
+ ```typescript
396
+ type TrackerPluginContextValue<TSlot extends keyof SlotContextMap = keyof SlotContextMap> =
397
+ | BasicTrackerPluginContextValue<TSlot>
398
+ | FullTrackerPluginContextValue<TSlot>;
399
+ ```
400
+
401
+ ---
402
+
403
+ ### BasicTrackerPluginContextValue
404
+
405
+ Значение контекста при `contextLevel = 'basic'`. Возвращается хуком [`useTrackerPluginContext()`](#usetrackerplugincontext) или `useTrackerPluginContext('basic')`.
406
+
407
+ ```typescript
408
+ interface BasicTrackerPluginContextValue<TSlot extends keyof SlotContextMap = keyof SlotContextMap> {
409
+ theme: Theme | undefined;
410
+ language: string | undefined;
411
+ service: string;
412
+ userId?: string;
413
+ isYateam?: boolean;
414
+ origin: string;
415
+ /** Имя слота, в котором открыт плагин */
416
+ slot: TSlot;
417
+ innerUrl: string;
418
+ queryParams: Record<string, string>;
419
+ /** Контекст страницы — только entityId и entityMeta при basic уровне */
420
+ slotContext: BasicContext | undefined;
421
+ registerHandler: RegisterHandlerFunction<TSlot>;
422
+ /** Уровень контекста — всегда 'basic' */
423
+ contextLevel: 'basic';
424
+ }
425
+ ```
426
+
427
+ #### `slotContext` (basic)
428
+
429
+ - **Type:** `BasicContext | undefined`
430
+ - **Description:** Содержит только `entityId` и опциональный `entityMeta`, переданные хостом в параметрах iframe. Доступен без postMessage-запроса.
431
+
432
+ ```typescript
433
+ type BasicContext = {
434
+ entityId: string;
435
+ entityMeta?: Record<string, string>;
436
+ };
437
+ ```
438
+
439
+ **Example:**
440
+
441
+ ```tsx
442
+ const { slotContext } = useTrackerPluginContext(); // basic по умолчанию
443
+ console.log(slotContext?.entityId); // 'QUEUE-123'
444
+ console.log(slotContext?.entityMeta); // { key: 'QUEUE-123' } или undefined
445
+ ```
446
+
447
+ ---
448
+
449
+ ### FullTrackerPluginContextValue
450
+
451
+ Значение контекста при `contextLevel = 'full'`. Возвращается хуком [`useTrackerPluginContext('full')`](#usetrackerplugincontext). Требует `contextLevel: "full"` в манифесте плагина.
452
+
453
+ ```typescript
454
+ interface FullTrackerPluginContextValue<TSlot extends keyof SlotContextMap = keyof SlotContextMap> {
455
+ theme: Theme | undefined;
456
+ language: string | undefined;
457
+ service: string;
458
+ userId?: string;
459
+ isYateam?: boolean;
460
+ origin: string;
461
+ /** Имя слота, в котором открыт плагин */
462
+ slot: TSlot;
463
+ innerUrl: string;
464
+ queryParams: Record<string, string>;
465
+ /** Полный контекст слота (Issue, TriggerContext и т.д.) */
466
+ slotContext: SlotContextMap[TSlot] | undefined;
467
+ registerHandler: RegisterHandlerFunction<TSlot>;
468
+ /** Уровень контекста — всегда 'full' */
469
+ contextLevel: 'full';
470
+ }
471
+ ```
472
+
473
+ #### `slotContext` (full)
474
+
475
+ - **Type:** `SlotContextMap[TSlot] | undefined`
476
+ - **Description:** Полный контекст слота, полученный через postMessage (`context.get`). Для `'issue.action'` — тип `Issue` из **`@weavix/tracker-core`**.
477
+
478
+ **Example:**
479
+
480
+ ```tsx
481
+ const { slotContext } = useTrackerPluginContext<'issue.action'>('full');
482
+ console.log(slotContext?.key); // 'QUEUE-123'
483
+ console.log(slotContext?.version); // 42
484
+ ```
485
+
486
+ #### `theme`
487
+
488
+ - **Type:** `Theme | undefined` (`'light' | 'light-hc' | 'dark' | 'dark-hc' | 'system'`)
489
+ - **Description:** Текущая тема оформления хоста
490
+
491
+ **Example:**
492
+
493
+ ```tsx
494
+ const { theme } = useTrackerPluginContext();
495
+ const isDark = theme === 'dark' || theme === 'dark-hc';
496
+ ```
497
+
498
+ #### `language`
499
+
500
+ - **Type:** `string | undefined`
501
+ - **Description:** Код текущего языка хоста (например, 'ru', 'en')
502
+
503
+ **Example:**
504
+
505
+ ```tsx
506
+ const { language } = useTrackerPluginContext();
507
+ const greeting = language === 'ru' ? 'Привет' : 'Hello';
508
+ ```
509
+
510
+ #### `slot`
511
+
512
+ - **Type:** `TSlot` (ключ из `SlotContextMap`)
513
+ - **Description:** Имя слота, в котором открыт плагин (например, `'issue.action'`, `'navigation'`)
514
+
515
+ #### `contextLevel`
516
+
517
+ - **Type:** `'basic' | 'full'`
518
+ - **Description:** Уровень контекста, объявленный в манифесте плагина. Определяет тип `slotContext`.
519
+
520
+ ---
521
+
522
+
523
+ ## Публичное API
524
+
525
+ Пакет `@weavix/tracker-plugin-sdk-react` реэкспортирует **hostApi**, **trackerApi** и типы из `@weavix/tracker-plugin-sdk`.
526
+
527
+ - **hostApi** — работа с хостом: инициализация, тема, язык, контекст слота, размер окна, `notifyReady()`. Подробнее в [API Reference tracker-core](../tracker-plugin-external/API_REFERENCE.md#hostapi-hostapi).
528
+ - **trackerApi** — вызовы Tracker Public API через **типизированное API v3**: `trackerApi.v3.get`, `trackerApi.v3.post`, `trackerApi.v3.put`, `trackerApi.v3.patch`, `trackerApi.v3.delete`. Ключи — пути эндпоинтов (с автоподсказкой и JSDoc из `@weavix/tracker-api-types`). Описание методов и форматов: [Common format](https://docs.yandex-team.ru/tracker/common-format).
529
+
530
+ **Пример:**
531
+
532
+ ```ts
533
+ import { trackerApi } from '@weavix/tracker-plugin-sdk-react';
534
+
535
+ const issue = await trackerApi.v3.get['/issues/{id}']({
536
+ pathParams: { id: 'KEY-1' },
537
+ queryParams: { expand: ['COMMENTS'] },
538
+ });
539
+ ```
540
+
541
+ Тема, язык и контекст слота доступны через [`useTrackerPluginContext`](#usetrackerplugincontext). Инициализация и уведомление хоста — через **hostApi** (или внутри `TrackerPluginProvider`). Вызовы эндпоинтов Tracker — через **trackerApi.v3**.
542
+
543
+ **Полная документация по API (типы, коды ошибок, утилиты):**
544
+
545
+ 📖 [API Reference — @weavix/tracker-plugin-sdk](../tracker-plugin-external/API_REFERENCE.md)
546
+
547
+ ---
548
+
549
+ ## Утилиты
550
+
551
+ ### getLocalizedString
552
+
553
+ Получает локализованную строку на основе языка. Полезно для локализации вне React-компонентов или когда нужен прямой контроль над языком.
554
+
555
+ **Type Signature:**
556
+
557
+ ```typescript
558
+ function getLocalizedString(
559
+ value: LocalizedString,
560
+ language: string,
561
+ fallbackLanguage?: string,
562
+ ): string;
563
+ ```
564
+
565
+ **Parameters:**
566
+
567
+ - `value` - `LocalizedString` - локализованная строка (может быть строкой или объектом с переводами)
568
+ - `language` - `string` - код языка ('ru' или 'en')
569
+ - `fallbackLanguage` - `string` (опционально, по умолчанию 'en') - резервный язык, если основной не найден
570
+
571
+ **Returns:** `string` - локализованная строка на указанном языке
572
+
573
+ **Example (базовое использование):**
574
+
575
+ ```tsx
576
+ import { getLocalizedString } from '@weavix/tracker-plugin-sdk-react';
577
+ import type { LocalizedString } from '@weavix/tracker-plugin-sdk-react';
578
+
579
+ function getFieldName(name: LocalizedString, language: string): string {
580
+ return getLocalizedString(name, language);
581
+ }
582
+ // language можно получить из useTrackerPluginContext() в компоненте
583
+
584
+ const name = { ru: 'Название', en: 'Summary' };
585
+ const localizedName = getFieldName(name, 'ru');
586
+ console.log(localizedName); // 'Название'
587
+ ```
588
+
589
+ **Example (с резервным языком):**
590
+
591
+ ```tsx
592
+ import { getLocalizedString } from '@weavix/tracker-plugin-sdk-react';
593
+
594
+ // Если перевод на русский отсутствует, используется английский
595
+ const partial = { en: 'Name' };
596
+ const name = getLocalizedString(partial, 'ru', 'en');
597
+ console.log(name); // 'Name'
598
+
599
+ // Если передана простая строка, она возвращается как есть
600
+ const simple = 'Simple string';
601
+ const result = getLocalizedString(simple, 'ru');
602
+ console.log(result); // 'Simple string'
603
+ ```
604
+
605
+ **Example (в обработчике событий):**
606
+
607
+ ```tsx
608
+ import {
609
+ getLocalizedString,
610
+ useTrackerPluginContext,
611
+ } from '@weavix/tracker-plugin-sdk-react';
612
+ import type { LocalizedString } from '@weavix/tracker-plugin-sdk-react';
613
+
614
+ type FieldWithName = { id: string; name: LocalizedString };
615
+
616
+ function FieldSelector({ fields }: { fields: FieldWithName[] }) {
617
+ const { language } = useTrackerPluginContext();
618
+ const handleFieldSelect = (field: FieldWithName) => {
619
+ const localizedName = getLocalizedString(field.name, language);
620
+ alert(`Выбрано поле: ${localizedName}`);
621
+ };
622
+
623
+ return (
624
+ <ul>
625
+ {fields.map((field) => (
626
+ <li key={field.id} onClick={() => handleFieldSelect(field)}>
627
+ {field.id}
628
+ </li>
629
+ ))}
630
+ </ul>
631
+ );
632
+ }
633
+ ```
634
+
635
+ **Примечание:** В React-компонентах предпочтительнее использовать хук [`useLocalizedString`](#uselocalizedstring), который автоматически получает язык из контекста:
636
+
637
+ ```tsx
638
+ import { useLocalizedString } from '@weavix/tracker-plugin-sdk-react';
639
+
640
+ function MyComponent() {
641
+ const localize = useLocalizedString();
642
+
643
+ const field = { name: { ru: 'Название', en: 'Title' } };
644
+ return <div>{localize(field.name)}</div>;
645
+ }
646
+ ```
647
+
648
+ ---
649
+