stream-chat-react 13.0.5 → 13.1.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.
Files changed (103) hide show
  1. package/dist/components/Channel/Channel.d.ts +1 -1
  2. package/dist/components/Channel/Channel.js +7 -0
  3. package/dist/components/ChannelList/hooks/useChannelListShape.js +3 -3
  4. package/dist/components/Chat/hooks/useChat.js +7 -3
  5. package/dist/components/Dialog/ButtonWithSubmenu.d.ts +11 -0
  6. package/dist/components/Dialog/ButtonWithSubmenu.js +88 -0
  7. package/dist/components/Dialog/index.d.ts +1 -0
  8. package/dist/components/Dialog/index.js +1 -0
  9. package/dist/components/Loading/LoadingErrorIndicator.js +1 -1
  10. package/dist/components/Message/Message.js +3 -2
  11. package/dist/components/Message/MessageIsThreadReplyInChannelButtonIndicator.d.ts +2 -0
  12. package/dist/components/Message/MessageIsThreadReplyInChannelButtonIndicator.js +63 -0
  13. package/dist/components/Message/MessageSimple.js +11 -4
  14. package/dist/components/Message/ReminderNotification.d.ts +6 -0
  15. package/dist/components/Message/ReminderNotification.js +30 -0
  16. package/dist/components/Message/hooks/index.d.ts +1 -0
  17. package/dist/components/Message/hooks/index.js +1 -0
  18. package/dist/components/Message/hooks/useMessageReminder.d.ts +1 -0
  19. package/dist/components/Message/hooks/useMessageReminder.js +11 -0
  20. package/dist/components/Message/index.d.ts +1 -0
  21. package/dist/components/Message/index.js +1 -0
  22. package/dist/components/Message/utils.d.ts +4 -2
  23. package/dist/components/Message/utils.js +11 -1
  24. package/dist/components/MessageActions/MessageActionsBox.js +12 -6
  25. package/dist/components/MessageActions/RemindMeSubmenu.d.ts +6 -0
  26. package/dist/components/MessageActions/RemindMeSubmenu.js +18 -0
  27. package/dist/components/MessageInput/MessageInputFlat.js +5 -3
  28. package/dist/components/MessageInput/SendToChannelCheckbox.d.ts +2 -0
  29. package/dist/components/MessageInput/SendToChannelCheckbox.js +20 -0
  30. package/dist/components/MessageList/MessageListNotifications.js +8 -3
  31. package/dist/components/MessageList/VirtualizedMessageListComponents.d.ts +1 -1
  32. package/dist/components/MessageList/VirtualizedMessageListComponents.js +4 -0
  33. package/dist/components/Notifications/hooks/index.d.ts +1 -0
  34. package/dist/components/Notifications/hooks/index.js +1 -0
  35. package/dist/components/Notifications/hooks/useNotifications.d.ts +2 -0
  36. package/dist/components/Notifications/hooks/useNotifications.js +10 -0
  37. package/dist/components/Notifications/index.d.ts +1 -0
  38. package/dist/components/Notifications/index.js +1 -0
  39. package/dist/components/TextareaComposer/TextareaComposer.js +4 -0
  40. package/dist/components/Thread/LegacyThreadContext.d.ts +8 -0
  41. package/dist/components/Thread/LegacyThreadContext.js +3 -0
  42. package/dist/components/Thread/Thread.d.ts +0 -4
  43. package/dist/components/Thread/Thread.js +2 -3
  44. package/dist/components/Thread/index.d.ts +1 -0
  45. package/dist/components/Thread/index.js +1 -0
  46. package/dist/components/index.d.ts +1 -0
  47. package/dist/components/index.js +1 -0
  48. package/dist/context/ComponentContext.d.ts +7 -1
  49. package/dist/css/v2/index.css +1 -1
  50. package/dist/css/v2/index.layout.css +1 -1
  51. package/dist/experimental/MessageActions/defaults.d.ts +1 -1
  52. package/dist/experimental/MessageActions/defaults.js +27 -4
  53. package/dist/experimental/index.browser.cjs +382 -169
  54. package/dist/experimental/index.browser.cjs.map +4 -4
  55. package/dist/experimental/index.node.cjs +382 -169
  56. package/dist/experimental/index.node.cjs.map +4 -4
  57. package/dist/i18n/Streami18n.d.ts +32 -3
  58. package/dist/i18n/Streami18n.js +34 -5
  59. package/dist/i18n/TranslationBuilder/TranslationBuilder.d.ts +35 -0
  60. package/dist/i18n/TranslationBuilder/TranslationBuilder.js +92 -0
  61. package/dist/i18n/TranslationBuilder/index.d.ts +2 -0
  62. package/dist/i18n/TranslationBuilder/index.js +2 -0
  63. package/dist/i18n/TranslationBuilder/notifications/NotificationTranslationTopic.d.ts +11 -0
  64. package/dist/i18n/TranslationBuilder/notifications/NotificationTranslationTopic.js +27 -0
  65. package/dist/i18n/TranslationBuilder/notifications/attachmentUpload.d.ts +4 -0
  66. package/dist/i18n/TranslationBuilder/notifications/attachmentUpload.js +32 -0
  67. package/dist/i18n/TranslationBuilder/notifications/index.d.ts +2 -0
  68. package/dist/i18n/TranslationBuilder/notifications/index.js +2 -0
  69. package/dist/i18n/TranslationBuilder/notifications/pollComposition.d.ts +3 -0
  70. package/dist/i18n/TranslationBuilder/notifications/pollComposition.js +9 -0
  71. package/dist/i18n/TranslationBuilder/notifications/types.d.ts +4 -0
  72. package/dist/i18n/TranslationBuilder/notifications/types.js +1 -0
  73. package/dist/i18n/de.json +23 -0
  74. package/dist/i18n/en.json +23 -0
  75. package/dist/i18n/es.json +23 -0
  76. package/dist/i18n/fr.json +23 -0
  77. package/dist/i18n/hi.json +23 -0
  78. package/dist/i18n/index.d.ts +1 -0
  79. package/dist/i18n/index.js +1 -0
  80. package/dist/i18n/it.json +23 -0
  81. package/dist/i18n/ja.json +23 -0
  82. package/dist/i18n/ko.json +23 -0
  83. package/dist/i18n/nl.json +23 -0
  84. package/dist/i18n/pt.json +23 -0
  85. package/dist/i18n/ru.json +23 -0
  86. package/dist/i18n/tr.json +23 -0
  87. package/dist/i18n/types.d.ts +54 -0
  88. package/dist/i18n/utils.d.ts +1 -1
  89. package/dist/i18n/utils.js +8 -2
  90. package/dist/index.browser.cjs +3617 -2162
  91. package/dist/index.browser.cjs.map +4 -4
  92. package/dist/index.node.cjs +3674 -2156
  93. package/dist/index.node.cjs.map +4 -4
  94. package/dist/plugins/Emojis/index.browser.cjs +1 -2
  95. package/dist/plugins/Emojis/index.browser.cjs.map +3 -3
  96. package/dist/plugins/Emojis/index.node.cjs +1 -2
  97. package/dist/plugins/Emojis/index.node.cjs.map +3 -3
  98. package/dist/scss/v2/Message/Message-layout.scss +11 -1
  99. package/dist/scss/v2/Message/Message-theme.scss +31 -1
  100. package/dist/scss/v2/MessageActionsBox/MessageActionsBox-theme.scss +8 -0
  101. package/dist/scss/v2/MessageInput/MessageInput-layout.scss +19 -0
  102. package/dist/scss/v2/MessageInput/MessageInput-theme.scss +11 -0
  103. package/package.json +6 -8
@@ -1,7 +1,9 @@
1
1
  import Dayjs from 'dayjs';
2
+ import { TranslationBuilder } from './TranslationBuilder';
2
3
  import type { TFunction } from 'i18next';
3
4
  import type momentTimezone from 'moment-timezone';
4
5
  import type { TranslationLanguages } from 'stream-chat';
6
+ import type { TranslationTopicConstructor } from './TranslationBuilder';
5
7
  import type { UnknownType } from '../types/types';
6
8
  import type { CustomFormatters, PredefinedFormatters, TDateTimeParser } from './types';
7
9
  import { enTranslations } from './translations';
@@ -36,12 +38,15 @@ export type Streami18nOptions = {
36
38
  formatters?: Partial<PredefinedFormatters> & CustomFormatters;
37
39
  language?: TranslationLanguages;
38
40
  logger?: (message?: string) => void;
41
+ translationBuilderTopics?: Record<string, TranslationTopicConstructor>;
39
42
  parseMissingKeyHandler?: (key: string, defaultValue?: string) => string;
40
43
  timezone?: string;
41
44
  translationsForLanguage?: Partial<typeof enTranslations>;
42
45
  };
43
46
  export declare class Streami18n {
44
47
  i18nInstance: import("i18next").i18n;
48
+ translationBuilder: TranslationBuilder;
49
+ private translationBuilderTopics;
45
50
  Dayjs: null;
46
51
  setLanguageCallback: (t: TFunction) => void;
47
52
  initialized: boolean;
@@ -80,6 +85,7 @@ export declare class Streami18n {
80
85
  lng: string;
81
86
  nsSeparator: false;
82
87
  parseMissingKeyHandler?: (key: string, defaultValue?: string) => string;
88
+ postProcess?: string[];
83
89
  };
84
90
  /**
85
91
  * A valid TZ identifier string (https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)
@@ -116,7 +122,7 @@ export declare class Streami18n {
116
122
  * Initializes the i18next instance with configuration (which enables natural language as default keys)
117
123
  */
118
124
  init(): Promise<{
119
- t: TFunction;
125
+ t: TFunction<"translation", undefined>;
120
126
  tDateTimeParser: TDateTimeParser;
121
127
  }>;
122
128
  localeExists: (language: TranslationLanguages) => boolean;
@@ -136,6 +142,8 @@ export declare class Streami18n {
136
142
  "Allow access to microphone": string;
137
143
  "Allow comments": string;
138
144
  "Allow option suggestion": string;
145
+ "Also send as a direct message": string;
146
+ "Also send in channel": string;
139
147
  "An error has occurred during recording": string;
140
148
  "An error has occurred during the recording processing": string;
141
149
  Anonymous: string;
@@ -143,6 +151,8 @@ export declare class Streami18n {
143
151
  Archive: string;
144
152
  "Ask a question": string;
145
153
  "Attach files": string;
154
+ "Attachment upload blocked due to {{reason}}": string;
155
+ "Attachment upload failed due to {{reason}}": string;
146
156
  Cancel: string;
147
157
  "Cannot seek in the recording": string;
148
158
  "Channel Missing": string;
@@ -157,6 +167,8 @@ export declare class Streami18n {
157
167
  "Download attachment {{ name }}": string;
158
168
  "Drag your files here": string;
159
169
  "Drag your files here to add to your post": string;
170
+ "Due since {{ dueSince }}": string;
171
+ "Due {{ timeLeft }}": string;
160
172
  "Edit Message": string;
161
173
  "Edit message request failed": string;
162
174
  Edited: string;
@@ -180,6 +192,8 @@ export declare class Streami18n {
180
192
  "Error uploading image": string;
181
193
  "Error \u00B7 Unsent": string;
182
194
  "Error: {{ errorMessage }}": string;
195
+ "Failed to create the poll": string;
196
+ "Failed to create the poll due to {{reason}}": string;
183
197
  "Failed to jump to the first unread message": string;
184
198
  "Failed to mark channel as read": string;
185
199
  "Failed to play the recording": string;
@@ -223,8 +237,12 @@ export declare class Streami18n {
223
237
  Question: string;
224
238
  Quote: string;
225
239
  "Recording format is not supported and cannot be reproduced": string;
240
+ "Remind Me": string;
241
+ "Remove reminder": string;
226
242
  Reply: string;
227
243
  "Reply to Message": string;
244
+ "Save for later": string;
245
+ "Saved for later": string;
228
246
  Search: string;
229
247
  "Searching...": string;
230
248
  "See all options ({{count}})_one": string;
@@ -248,6 +266,8 @@ export declare class Streami18n {
248
266
  "This message did not meet our content guidelines": string;
249
267
  "This message was deleted...": string;
250
268
  Thread: string;
269
+ "Thread has not been found": string;
270
+ "Thread reply": string;
251
271
  "To start recording, allow the camera access in your browser": string;
252
272
  "To start recording, allow the microphone access in your browser": string;
253
273
  "Type a number from 2 to 10": string;
@@ -288,13 +308,17 @@ export declare class Streami18n {
288
308
  "aria/Open Reaction Selector": string;
289
309
  "aria/Open Thread": string;
290
310
  "aria/Reaction list": string;
311
+ "aria/Remind Me Options": string;
291
312
  "aria/Remove attachment": string;
292
313
  "aria/Retry upload": string;
293
314
  "aria/Search results": string;
294
315
  "aria/Search results header filter button": string;
295
316
  "aria/Send": string;
296
317
  "aria/Stop AI Generation": string;
318
+ "duration/Message reminder": string;
319
+ "duration/Remind Me": string;
297
320
  live: string;
321
+ "network error": string;
298
322
  replyCount_one: string;
299
323
  replyCount_other: string;
300
324
  "search-results-header-filter-source-button-label--channels": string;
@@ -302,14 +326,19 @@ export declare class Streami18n {
302
326
  "search-results-header-filter-source-button-label--users": string;
303
327
  searchResultsCount_one: string;
304
328
  searchResultsCount_other: string;
329
+ "size limit": string;
305
330
  "this content could not be displayed": string;
306
331
  "timestamp/DateSeparator": string;
307
332
  "timestamp/MessageTimestamp": string;
308
333
  "timestamp/PollVote": string;
309
334
  "timestamp/PollVoteTooltip": string;
335
+ "timestamp/ReminderNotification": string;
310
336
  "timestamp/SystemMessage": string;
337
+ "translationBuilderTopic/notification": string;
338
+ "unknown error": string;
311
339
  unreadMessagesSeparatorText_one: string;
312
340
  unreadMessagesSeparatorText_other: string;
341
+ "unsupported file type": string;
313
342
  "{{ commaSeparatedUsers }} and {{ moreCount }} more": string;
314
343
  "{{ commaSeparatedUsers }}, and {{ lastUser }}": string;
315
344
  "{{ firstUser }} and {{ secondUser }}": string;
@@ -335,12 +364,12 @@ export declare class Streami18n {
335
364
  * Returns current version translator function.
336
365
  */
337
366
  getTranslators(): Promise<{
338
- t: TFunction;
367
+ t: TFunction<"translation", undefined>;
339
368
  tDateTimeParser: TDateTimeParser;
340
369
  }>;
341
370
  registerTranslation(language: TranslationLanguages, translation: typeof enTranslations, customDayjsLocale?: Partial<ILocale>): void;
342
371
  addOrUpdateLocale(key: TranslationLanguages, config: Partial<ILocale>): void;
343
- setLanguage(language: TranslationLanguages): Promise<TFunction | undefined>;
372
+ setLanguage(language: TranslationLanguages): Promise<TFunction<"translation", undefined> | undefined>;
344
373
  registerSetLanguageCallback(callback: (t: TFunction) => void): void;
345
374
  }
346
375
  export {};
@@ -5,8 +5,10 @@ import updateLocale from 'dayjs/plugin/updateLocale';
5
5
  import LocalizedFormat from 'dayjs/plugin/localizedFormat';
6
6
  import localeData from 'dayjs/plugin/localeData';
7
7
  import relativeTime from 'dayjs/plugin/relativeTime';
8
+ import duration from 'dayjs/plugin/duration';
8
9
  import utc from 'dayjs/plugin/utc';
9
10
  import timezone from 'dayjs/plugin/timezone';
11
+ import { NotificationTranslationTopic, TranslationBuilder } from './TranslationBuilder';
10
12
  import { defaultTranslatorFunction, predefinedFormatters } from './utils';
11
13
  import { deTranslations, enTranslations, esTranslations, frTranslations, hiTranslations, itTranslations, jaTranslations, koTranslations, nlTranslations, ptTranslations, ruTranslations, trTranslations, } from './translations';
12
14
  import 'dayjs/locale/de';
@@ -55,7 +57,7 @@ Dayjs.updateLocale('fr', {
55
57
  lastWeek: 'dddd [dernier à] LT',
56
58
  nextDay: '[Demain à] LT',
57
59
  nextWeek: 'dddd [à] LT',
58
- sameDay: '[Aujourdhui à] LT',
60
+ sameDay: "[Aujourd'hui à] LT",
59
61
  sameElse: 'L',
60
62
  },
61
63
  });
@@ -205,9 +207,9 @@ const en_locale = {
205
207
  const isDayJs = (dateTimeParser) => dateTimeParser.extend !== undefined;
206
208
  const supportsTz = (dateTimeParser) => dateTimeParser.tz !== undefined;
207
209
  /**
208
- * Wrapper around [i18next](https://www.i18next.com/) class for Stream related translations.
209
- * Instance of this class should be provided to Chat component to handle translations.
210
- * Stream provides following list of in-built translations:
210
+ * Wrapper around [i18next](https://www.i18next.com/) class for Stream related i18n.
211
+ * Instance of this class should be provided to Chat component to handle i18n.
212
+ * Stream provides following list of in-built i18n:
211
213
  * 1. English (en)
212
214
  * 2. Dutch (nl)
213
215
  * 3. Russian (ru)
@@ -271,7 +273,7 @@ const supportsTz = (dateTimeParser) => dateTimeParser.tz !== undefined;
271
273
  * </Chat>
272
274
  * ```
273
275
  *
274
- * ## Datetime translations
276
+ * ## Datetime i18n
275
277
  *
276
278
  * Stream react chat components uses [dayjs](https://day.js.org/en/) internally by default to format datetime stamp.
277
279
  * e.g., in ChannelPreview, MessageContent components.
@@ -363,6 +365,18 @@ const defaultStreami18nOptions = {
363
365
  disableDateTimeTranslations: false,
364
366
  language: 'en',
365
367
  logger: (message) => console.warn(message),
368
+ /**
369
+ * Key in the translationBuilderTopics has to match postProcessorName in the translation value.
370
+ *
371
+ * {
372
+ * "key": "{{value, postProcessorName}}"
373
+ * }
374
+ *
375
+ * At least the default topics will be supported.
376
+ */
377
+ translationBuilderTopics: {
378
+ notification: NotificationTranslationTopic,
379
+ },
366
380
  };
367
381
  export class Streami18n {
368
382
  /**
@@ -393,6 +407,7 @@ export class Streami18n {
393
407
  */
394
408
  constructor(options = {}) {
395
409
  this.i18nInstance = i18n.createInstance();
410
+ this.translationBuilderTopics = {};
396
411
  this.Dayjs = null;
397
412
  this.setLanguageCallback = () => null;
398
413
  this.initialized = false;
@@ -449,12 +464,18 @@ export class Streami18n {
449
464
  this.DateTimeParser = finalOptions.DateTimeParser;
450
465
  this.timezone = finalOptions.timezone;
451
466
  this.formatters = { ...predefinedFormatters, ...options?.formatters };
467
+ this.translationBuilder = new TranslationBuilder(this.i18nInstance);
468
+ this.translationBuilderTopics = {
469
+ ...defaultStreami18nOptions.translationBuilderTopics,
470
+ ...options.translationBuilderTopics,
471
+ };
452
472
  try {
453
473
  if (this.DateTimeParser && isDayJs(this.DateTimeParser)) {
454
474
  this.DateTimeParser.extend(LocalizedFormat);
455
475
  this.DateTimeParser.extend(calendar);
456
476
  this.DateTimeParser.extend(localeData);
457
477
  this.DateTimeParser.extend(relativeTime);
478
+ this.DateTimeParser.extend(duration);
458
479
  }
459
480
  }
460
481
  catch (error) {
@@ -487,6 +508,10 @@ export class Streami18n {
487
508
  lng: this.currentLanguage,
488
509
  nsSeparator: false,
489
510
  };
511
+ const postProcess = Object.keys(this.translationBuilderTopics);
512
+ if (postProcess.length > 0) {
513
+ this.i18nextConfig.postProcess = postProcess;
514
+ }
490
515
  if (finalOptions.parseMissingKeyHandler) {
491
516
  this.i18nextConfig.parseMissingKeyHandler = finalOptions.parseMissingKeyHandler;
492
517
  }
@@ -537,6 +562,10 @@ export class Streami18n {
537
562
  this.i18nInstance.services.formatter?.add(name, formatterFactory(this));
538
563
  });
539
564
  }
565
+ // Register post-processors after initialization
566
+ Object.entries(this.translationBuilderTopics).forEach(([topic, TranslationTopic]) => {
567
+ this.translationBuilder.registerTopic(topic, TranslationTopic);
568
+ });
540
569
  }
541
570
  catch (error) {
542
571
  this.logger(`Something went wrong with init: ${JSON.stringify(error)}`);
@@ -0,0 +1,35 @@
1
+ import type { i18n, TFunction } from 'i18next';
2
+ type TopicName = string;
3
+ type TranslatorName = string;
4
+ export type Translator<O extends Record<string, unknown> = Record<string, unknown>> = (params: {
5
+ key: string;
6
+ value: string;
7
+ t: TFunction;
8
+ options: O;
9
+ }) => string | null;
10
+ export type TranslationTopicOptions<O extends Record<string, unknown> = Record<string, unknown>> = {
11
+ i18next: i18n;
12
+ translators?: Record<string, Translator<O>>;
13
+ };
14
+ export declare abstract class TranslationTopic<O extends Record<string, unknown> = Record<string, unknown>> {
15
+ protected options: TranslationTopicOptions<O>;
16
+ protected translators: Map<string, Translator<O>>;
17
+ protected i18next: i18n;
18
+ constructor(options: TranslationTopicOptions<O>);
19
+ abstract translate(value: string, key: string, options: O): string;
20
+ setTranslator: (name: string, translator: Translator<O>) => void;
21
+ removeTranslator: (name: string) => void;
22
+ }
23
+ export type TranslationTopicConstructor = new (options: TranslationTopicOptions) => TranslationTopic;
24
+ export declare class TranslationBuilder {
25
+ private i18next;
26
+ private topics;
27
+ private translatorRegistrationsBuffer;
28
+ constructor(i18next: i18n);
29
+ registerTopic: (name: TopicName, Topic: TranslationTopicConstructor) => TranslationTopic<Record<string, unknown>>;
30
+ disableTopic: (topicName: TopicName) => void;
31
+ getTopic: (topicName: TopicName) => TranslationTopic<Record<string, unknown>> | undefined;
32
+ registerTranslators(topicName: TopicName, translators: Record<TranslatorName, Translator>): void;
33
+ removeTranslators(topicName: TopicName, translators: TranslatorName[]): void;
34
+ }
35
+ export {};
@@ -0,0 +1,92 @@
1
+ export class TranslationTopic {
2
+ constructor(options) {
3
+ this.options = options;
4
+ this.translators = new Map();
5
+ this.setTranslator = (name, translator) => {
6
+ this.translators.set(name, translator);
7
+ };
8
+ this.removeTranslator = (name) => {
9
+ this.translators.delete(name);
10
+ };
11
+ this.i18next = options.i18next;
12
+ if (options.translators) {
13
+ Object.entries(options.translators).forEach(([name, translator]) => {
14
+ this.setTranslator(name, translator);
15
+ });
16
+ }
17
+ }
18
+ }
19
+ const forwardTranslation = ({ value }) => value;
20
+ export class TranslationBuilder {
21
+ constructor(i18next) {
22
+ this.i18next = i18next;
23
+ this.topics = new Map();
24
+ // need to keep a registration buffer so that translators can be registered once a topic is registered
25
+ // what does not happen when Streami18n is instantiated but rather once Streami18n.init() is invoked
26
+ this.translatorRegistrationsBuffer = {};
27
+ this.registerTopic = (name, Topic) => {
28
+ let topic = this.topics.get(name);
29
+ if (!topic) {
30
+ topic = new Topic({ i18next: this.i18next });
31
+ this.topics.set(name, topic);
32
+ this.i18next.use({
33
+ name,
34
+ process: (value, key, options) => {
35
+ const topic = this.topics.get(name);
36
+ if (!topic)
37
+ return value;
38
+ return topic.translate(value, key, options);
39
+ },
40
+ type: 'postProcessor',
41
+ });
42
+ }
43
+ const additionalTranslatorsToRegister = this.translatorRegistrationsBuffer[name];
44
+ if (additionalTranslatorsToRegister) {
45
+ Object.entries(additionalTranslatorsToRegister).forEach(([translatorName, translator]) => {
46
+ topic.setTranslator(translatorName, translator);
47
+ });
48
+ delete this.translatorRegistrationsBuffer[name];
49
+ }
50
+ return topic;
51
+ };
52
+ this.disableTopic = (topicName) => {
53
+ const topic = this.topics.get(topicName);
54
+ if (!topic)
55
+ return;
56
+ this.i18next.use({
57
+ name: topicName,
58
+ process: forwardTranslation,
59
+ type: 'postProcessor',
60
+ });
61
+ this.topics.delete(topicName);
62
+ };
63
+ this.getTopic = (topicName) => this.topics.get(topicName);
64
+ }
65
+ registerTranslators(topicName, translators) {
66
+ const topic = this.getTopic(topicName);
67
+ if (!topic) {
68
+ if (!this.translatorRegistrationsBuffer[topicName])
69
+ this.translatorRegistrationsBuffer[topicName] = {};
70
+ Object.entries(translators).forEach(([translatorName, translator]) => {
71
+ this.translatorRegistrationsBuffer[topicName][translatorName] = translator;
72
+ });
73
+ return;
74
+ }
75
+ Object.entries(translators).forEach(([name, translator]) => {
76
+ topic.setTranslator(name, translator);
77
+ });
78
+ }
79
+ removeTranslators(topicName, translators) {
80
+ const topic = this.getTopic(topicName);
81
+ if (this.translatorRegistrationsBuffer[topicName]) {
82
+ translators.forEach((translatorName) => {
83
+ delete this.translatorRegistrationsBuffer[topicName][translatorName];
84
+ });
85
+ }
86
+ if (!topic)
87
+ return;
88
+ translators.forEach((name) => {
89
+ topic.removeTranslator(name);
90
+ });
91
+ }
92
+ }
@@ -0,0 +1,2 @@
1
+ export * from './TranslationBuilder';
2
+ export * from './notifications';
@@ -0,0 +1,2 @@
1
+ export * from './TranslationBuilder';
2
+ export * from './notifications';
@@ -0,0 +1,11 @@
1
+ import { TranslationTopic } from '../../TranslationBuilder';
2
+ import type { Notification } from 'stream-chat';
3
+ import type { NotificationTranslatorOptions } from './types';
4
+ import type { TranslationTopicOptions, Translator } from '../../index';
5
+ export declare const defaultNotificationTranslators: Record<string, Translator<NotificationTranslatorOptions>>;
6
+ export declare class NotificationTranslationTopic extends TranslationTopic<NotificationTranslatorOptions> {
7
+ constructor({ i18next, translators }: TranslationTopicOptions);
8
+ translate: (value: string, key: string, options: {
9
+ notification?: Notification;
10
+ }) => string;
11
+ }
@@ -0,0 +1,27 @@
1
+ import { attachmentUploadBlockedNotificationTranslator, attachmentUploadFailedNotificationTranslator, } from './attachmentUpload';
2
+ import { TranslationTopic } from '../../TranslationBuilder';
3
+ import { pollCreationFailedNotificationTranslator } from './pollComposition';
4
+ export const defaultNotificationTranslators = {
5
+ 'api:attachment:upload:failed': attachmentUploadFailedNotificationTranslator,
6
+ 'api:poll:create:failed': pollCreationFailedNotificationTranslator,
7
+ 'validation:attachment:upload:blocked': attachmentUploadBlockedNotificationTranslator,
8
+ };
9
+ export class NotificationTranslationTopic extends TranslationTopic {
10
+ constructor({ i18next, translators }) {
11
+ super({ i18next, translators: defaultNotificationTranslators });
12
+ this.translate = (value, key, options) => {
13
+ const { notification } = options;
14
+ if (!notification)
15
+ return value;
16
+ const translator = notification.type && this.translators.get(notification.type);
17
+ if (!translator)
18
+ return value;
19
+ return translator({ key, options, t: this.i18next.t, value }) || value;
20
+ };
21
+ if (translators) {
22
+ Object.entries(translators).forEach(([name, translator]) => {
23
+ this.setTranslator(name, translator);
24
+ });
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,4 @@
1
+ import type { NotificationTranslatorOptions } from './types';
2
+ import type { Translator } from '../TranslationBuilder';
3
+ export declare const attachmentUploadBlockedNotificationTranslator: Translator<NotificationTranslatorOptions>;
4
+ export declare const attachmentUploadFailedNotificationTranslator: Translator<NotificationTranslatorOptions>;
@@ -0,0 +1,32 @@
1
+ export const attachmentUploadBlockedNotificationTranslator = ({ options, t }) => {
2
+ const { notification } = options;
3
+ if (!notification)
4
+ return null;
5
+ if (typeof notification.metadata?.reason !== 'string') {
6
+ const reason = t('unknown error');
7
+ return t('Attachment upload blocked due to {{reason}}', { reason });
8
+ }
9
+ if (notification.metadata?.reason === 'size_limit') {
10
+ const reason = t('size limit');
11
+ return t('Attachment upload blocked due to {{reason}}', { reason });
12
+ }
13
+ const reason = t('unsupported file type');
14
+ return t('Attachment upload blocked due to {{reason}}', { reason });
15
+ };
16
+ export const attachmentUploadFailedNotificationTranslator = ({ options, t }) => {
17
+ const { notification } = options;
18
+ if (!notification)
19
+ return null;
20
+ const { reason: originalReason } = notification.metadata ?? {};
21
+ if (typeof originalReason !== 'string') {
22
+ const reason = t('unknown error');
23
+ return t('Attachment upload failed due to {{reason}}', { reason });
24
+ }
25
+ let reason = originalReason.toLowerCase();
26
+ if (reason === 'network error') {
27
+ reason = t('network error');
28
+ return t('Attachment upload failed due to {{reason}}', { reason });
29
+ }
30
+ // custom reason string
31
+ return t('Attachment upload failed due to {{reason}}', { reason });
32
+ };
@@ -0,0 +1,2 @@
1
+ export { NotificationTranslationTopic } from './NotificationTranslationTopic';
2
+ export * from './types';
@@ -0,0 +1,2 @@
1
+ export { NotificationTranslationTopic } from './NotificationTranslationTopic';
2
+ export * from './types';
@@ -0,0 +1,3 @@
1
+ import type { Translator } from '../TranslationBuilder';
2
+ import type { NotificationTranslatorOptions } from './types';
3
+ export declare const pollCreationFailedNotificationTranslator: Translator<NotificationTranslatorOptions>;
@@ -0,0 +1,9 @@
1
+ export const pollCreationFailedNotificationTranslator = ({ options: { notification }, t }) => {
2
+ if (typeof notification?.metadata?.reason === 'string' &&
3
+ notification.metadata.reason.length) {
4
+ return t('Failed to create the poll due to {{reason}}', {
5
+ reason: notification.metadata.reason.toLowerCase(),
6
+ });
7
+ }
8
+ return t('Failed to create the poll');
9
+ };
@@ -0,0 +1,4 @@
1
+ import type { Notification } from 'stream-chat';
2
+ export type NotificationTranslatorOptions = {
3
+ notification?: Notification;
4
+ };
package/dist/i18n/de.json CHANGED
@@ -6,6 +6,8 @@
6
6
  "Allow access to microphone": "Zugriff auf Mikrofon erlauben",
7
7
  "Allow comments": "Kommentare erlauben",
8
8
  "Allow option suggestion": "Optionsvorschläge erlauben",
9
+ "Also send as a direct message": "Auch als Direktnachricht senden",
10
+ "Also send in channel": "Auch im Kanal senden",
9
11
  "An error has occurred during recording": "Ein Fehler ist während der Aufnahme aufgetreten",
10
12
  "An error has occurred during the recording processing": "Ein Fehler ist während der Aufnahmeverarbeitung aufgetreten",
11
13
  "Anonymous": "Anonym",
@@ -13,6 +15,8 @@
13
15
  "Archive": "Archivieren",
14
16
  "Ask a question": "Eine Frage stellen",
15
17
  "Attach files": "Dateien anhängen",
18
+ "Attachment upload blocked due to {{reason}}": "Anhang-Upload blockiert wegen {{reason}}",
19
+ "Attachment upload failed due to {{reason}}": "Anhang-Upload fehlgeschlagen wegen {{reason}}",
16
20
  "Cancel": "Abbrechen",
17
21
  "Cannot seek in the recording": "In der Aufnahme kann nicht gesucht werden",
18
22
  "Channel Missing": "Kanal fehlt",
@@ -27,6 +31,8 @@
27
31
  "Download attachment {{ name }}": "Anhang {{ name }} herunterladen",
28
32
  "Drag your files here": "Ziehen Sie Ihre Dateien hierher",
29
33
  "Drag your files here to add to your post": "Ziehen Sie Ihre Dateien hierher, um sie Ihrem Beitrag hinzuzufügen",
34
+ "Due since {{ dueSince }}": "Fällig seit {{ dueSince }}",
35
+ "Due {{ timeLeft }}": "Fällig {{ timeLeft }}",
30
36
  "Edit Message": "Nachricht bearbeiten",
31
37
  "Edit message request failed": "Anfrage zum Bearbeiten der Nachricht fehlgeschlagen",
32
38
  "Edited": "Bearbeitet",
@@ -50,6 +56,8 @@
50
56
  "Error uploading image": "Fehler beim Hochladen des Bildes",
51
57
  "Error · Unsent": "Fehler · Nicht gesendet",
52
58
  "Error: {{ errorMessage }}": "Fehler: {{ errorMessage }}",
59
+ "Failed to create the poll": "Fehler beim Erstellen der Umfrage",
60
+ "Failed to create the poll due to {{reason}}": "Die Umfrage konnte aufgrund von {{reason}} nicht erstellt werden",
53
61
  "Failed to jump to the first unread message": "Fehler beim Springen zur ersten ungelesenen Nachricht",
54
62
  "Failed to mark channel as read": "Fehler beim Markieren des Kanals als gelesen",
55
63
  "Failed to play the recording": "Wiedergabe der Aufnahme fehlgeschlagen",
@@ -93,8 +101,12 @@
93
101
  "Question": "Frage",
94
102
  "Quote": "Zitieren",
95
103
  "Recording format is not supported and cannot be reproduced": "Aufnahmeformat wird nicht unterstützt und kann nicht wiedergegeben werden",
104
+ "Remind Me": "Erinnern",
105
+ "Remove reminder": "Erinnerung entfernen",
96
106
  "Reply": "Antworten",
97
107
  "Reply to Message": "Auf Nachricht antworten",
108
+ "Save for later": "Für später speichern",
109
+ "Saved for later": "Für später gespeichert",
98
110
  "Search": "Suche",
99
111
  "Searching...": "Suchen...",
100
112
  "See all options ({{count}})_one": "Alle Optionen anzeigen ({{count}})",
@@ -118,6 +130,8 @@
118
130
  "This message did not meet our content guidelines": "Diese Nachricht entsprach nicht unseren Inhaltsrichtlinien",
119
131
  "This message was deleted...": "Diese Nachricht wurde gelöscht...",
120
132
  "Thread": "Thread",
133
+ "Thread has not been found": "Thread wurde nicht gefunden",
134
+ "Thread reply": "Thread-Antwort",
121
135
  "To start recording, allow the camera access in your browser": "Um mit der Aufnahme zu beginnen, erlauben Sie den Zugriff auf die Kamera in Ihrem Browser",
122
136
  "To start recording, allow the microphone access in your browser": "Um mit der Aufnahme zu beginnen, erlauben Sie den Zugriff auf das Mikrofon in Ihrem Browser",
123
137
  "Type a number from 2 to 10": "Geben Sie eine Zahl von 2 bis 10 ein",
@@ -158,6 +172,7 @@
158
172
  "aria/Open Reaction Selector": "Reaktionsauswahl öffnen",
159
173
  "aria/Open Thread": "Thread öffnen",
160
174
  "aria/Reaction list": "Reaktionsliste",
175
+ "aria/Remind Me Options": "Erinnerungsoptionen",
161
176
  "aria/Remove attachment": "Anhang entfernen",
162
177
  "aria/Retry upload": "Upload erneut versuchen",
163
178
  "aria/Search results": "Suchergebnisse",
@@ -166,11 +181,14 @@
166
181
  "aria/Stop AI Generation": "KI-Generierung stoppen",
167
182
  "ban-command-args": "[@Benutzername] [Text]",
168
183
  "ban-command-description": "Einen Benutzer verbannen",
184
+ "duration/Message reminder": "{{ milliseconds | durationFormatter(withSuffix: true) }}",
185
+ "duration/Remind Me": "{{ milliseconds | durationFormatter(withSuffix: true) }}",
169
186
  "giphy-command-args": "[Text]",
170
187
  "giphy-command-description": "Poste ein zufälliges Gif in den Kanal",
171
188
  "live": "live",
172
189
  "mute-command-args": "[@Benutzername]",
173
190
  "mute-command-description": "Stummschalten eines Benutzers",
191
+ "network error": "Netzwerkfehler",
174
192
  "replyCount_one": "1 Antwort",
175
193
  "replyCount_other": "{{ count }} Antworten",
176
194
  "search-results-header-filter-source-button-label--channels": "Kanäle",
@@ -178,18 +196,23 @@
178
196
  "search-results-header-filter-source-button-label--users": "Benutzer",
179
197
  "searchResultsCount_one": "1 Ergebnis",
180
198
  "searchResultsCount_other": "{{ count }} Ergebnisse",
199
+ "size limit": "Größenbeschränkung",
181
200
  "this content could not be displayed": "Dieser Inhalt konnte nicht angezeigt werden",
182
201
  "timestamp/DateSeparator": "{{ timestamp | timestampFormatter(calendar: true) }}",
183
202
  "timestamp/MessageTimestamp": "{{ timestamp | timestampFormatter(calendar: true) }}",
184
203
  "timestamp/PollVote": "{{ timestamp | timestampFormatter(format: MMM D [at] HH:mm) }}",
185
204
  "timestamp/PollVoteTooltip": "{{ timestamp | timestampFormatter(calendar: true) }}",
205
+ "timestamp/ReminderNotification": "{{ timestamp | timestampFormatter(calendar: true) }}",
186
206
  "timestamp/SystemMessage": "{{ timestamp | timestampFormatter(format: dddd L) }}",
207
+ "translationBuilderTopic/notification": "{{value, notification}}",
187
208
  "unban-command-args": "[@Benutzername]",
188
209
  "unban-command-description": "Einen Benutzer entbannen",
210
+ "unknown error": "Unbekannter Fehler",
189
211
  "unmute-command-args": "[@Benutzername]",
190
212
  "unmute-command-description": "Stummschaltung eines Benutzers aufheben",
191
213
  "unreadMessagesSeparatorText_one": "1 ungelesene Nachricht",
192
214
  "unreadMessagesSeparatorText_other": "{{count}} ungelesene Nachrichten",
215
+ "unsupported file type": "Nicht unterstützter Dateityp",
193
216
  "{{ commaSeparatedUsers }} and {{ moreCount }} more": "{{ commaSeparatedUsers }} und {{moreCount}} mehr",
194
217
  "{{ commaSeparatedUsers }}, and {{ lastUser }}": "{{ commaSeparatedUsers }} und {{ lastUser }}",
195
218
  "{{ firstUser }} and {{ secondUser }}": "{{ firstUser }} und {{ secondUser }}",