Notifications text
Use this page to change the text of a notification, whether a built-in one or one your app publishes. The text is translated with the rest of the UI, so it follows the user's language. Where notifications appear and how they look is on Displaying notifications. What screen readers do with them is on Notifications accessibility.
Translating notifications
The Notification component chooses the text of each notification as it renders it, by the notification's type:
- A type
stream-chatpublishes, such asapi:attachment:upload:failed, renders a translation key throught(). The SDK maps every typestream-chatdefines. - A few types the SDK publishes itself,
api:poll:end:success,api:poll:end:failed,browser:audio:playback:errorandchannel:jumpToFirstUnread:failed, are mapped the same way. - Any other type renders
notification.messageas it is.
The SDK's components translate most of their notifications before publishing them: "Message pinned" is t("message.pinned.text", "Message pinned"). So there are three ways to change the text:
- A notification from an SDK component: override the key it was published with. When a message action fails with an error that has a message, the notification shows that message instead.
- A notification from
stream-chat, or one of the four SDK types above: override the key its type is mapped to, listed in Keys by type. - Text that depends on the notification: render your own
Notification.
import { Streami18n } from "stream-chat-react-native";
export const streami18n = new Streami18n({
translationsForLanguage: {
// Published by the Pin action, translated at the call site.
"message.pinned.text": "Pinned",
// Published by stream-chat: an upload that failed.
"notifications.attachmentUploadFailed.error":
"That file could not be uploaded",
"notifications.attachmentUploadFailed.withReason.error":
"That file could not be uploaded: {{reason}}",
},
});Pass the instance to Chat and OverlayProvider as i18nInstance. Localization covers dictionaries, other languages and reading the catalog of keys from your editor.
Keys by type
A type stream-chat publishes, with the key it renders:
| Type | Key | English |
|---|---|---|
validation:attachment:file:missing |
notifications.attachmentFileMissing.error |
File is required for upload attachment |
validation:attachment:id:missing |
notifications.attachmentIdMissing.error |
Local upload attachment missing local id |
validation:attachment:upload:blocked |
notifications.attachmentUploadBlocked.error |
Attachment upload blocked due to {{reason}} |
api:attachment:upload:failed |
notifications.attachmentUploadFailed.error, or notifications.attachmentUploadFailed.withReason.error |
Error uploading attachment |
validation:attachment:upload:in-progress |
notifications.attachmentUploadInProgress.error |
Wait until all attachments have uploaded |
validation:command:disabled |
notifications.commandUnavailable.error, .whileEditing.error or .whileReplying.error |
Command not available |
validation:command:not-ready |
notifications.commandNotReady.error |
Command not ready to be sent |
api:location:create:failed |
notifications.locationShareFailed.error |
Failed to share location |
api:message:jump:failed |
notifications.messageJumpFailed.error |
Failed to jump to the message |
api:message:jumpToLatest:failed |
notifications.messageJumpToLatestFailed.error |
Failed to jump to the latest message |
api:message:send:failed |
common.sendMessageFailed.error |
Send message request failed |
api:message:update:failed |
common.editMessageFailed.error |
Edit message request failed |
validation:poll:castVote:limit |
notifications.voteLimitReached.error |
Reached the vote limit. Remove an existing vote first. |
api:poll:create:failed |
notifications.pollCreateFailed.error, or notifications.pollCreateFailed.withReason.error |
Failed to create the poll |
Four types the SDK publishes:
| Type | Key | English |
|---|---|---|
api:poll:end:success |
notifications.pollEnded.text |
Poll ended |
api:poll:end:failed |
poll.endVote.error, or notifications.pollEndFailed.withReason.error |
Failed to end the poll |
browser:audio:playback:error |
the message the player published: audioPlayer.playbackFailed.error, .formatUnsupported.error or .seekUnsupported.error |
Failed to play the recording |
channel:jumpToFirstUnread:failed |
channel.jumpToFirstUnreadFailed.error |
Failed to jump to the first unread message |
The keys with withReason are used when the notification carries a string in metadata.reason, which they put in {{reason}} in lowercase. An upload that was blocked fills {{reason}} from three keys of its own: notifications.attachmentUploadBlocked.reason.sizeLimit.text for a size_limit reason, .unknownError.text for a reason that isn't a string, and .unsupportedFileType.text for any other. A disabled command uses .whileEditing.error for the reason editing, and .whileReplying.error for quoted_message. When browser:audio:playback:error carries no message, it renders notifications.recordingPlaybackFailed.error, "Error reproducing the recording".
Text that depends on the notification
The SDK has no registry of translators. To change the text beyond what the keys allow, replace the Notification component and pass the default one a notification with the text you want. This one names the author of a pinned message:
import type { PropsWithChildren } from "react";
import {
asDynamicKey,
Notification,
useTranslationContext,
WithComponents,
} from "stream-chat-react-native";
import type {
ComponentOverrides,
NotificationProps,
} from "stream-chat-react-native";
const PIN_SUCCESS = "api:message:pin:success";
const PinNotification = (props: NotificationProps) => {
const { t } = useTranslationContext();
const { notification } = props;
if (notification.type !== PIN_SUCCESS) return <Notification {...props} />;
const message = notification.origin.context?.message as
{ user?: { name?: string } } | undefined;
const text = t(
asDynamicKey("myApp.notification.messagePinned"),
"Pinned a message from {{author}}",
{ author: message?.user?.name ?? "someone" },
);
return (
<Notification
{...props}
notification={{ ...notification, message: text }}
/>
);
};
const overrides: ComponentOverrides = { Notification: PinNotification };
export const WithPinNotification = ({ children }: PropsWithChildren) => (
<WithComponents overrides={overrides}>{children}</WithComponents>
);This works for the types the SDK doesn't map. A type from the tables above renders its key instead of the message the notification carries, except browser:audio:playback:error, which renders its message when it has one. A replacement Notification has to render the text itself for those types. Declare overrides at module scope: WithComponents reads it once.
Text of notifications you publish
A notification of your own renders its message as you publish it, so translate it first. Keys of your own take part in the dictionaries like any other, and t reads them through asDynamicKey, as Localization shows:
import { Pressable, Text } from "react-native";
import {
asDynamicKey,
useNotificationApi,
useTranslationContext,
} from "stream-chat-react-native";
export const FavoriteButton = ({
onFavorite,
}: {
onFavorite: () => Promise<void>;
}) => {
const { addNotification } = useNotificationApi();
const { t } = useTranslationContext();
const favorite = async () => {
try {
await onFavorite();
addNotification({
message: t(
asDynamicKey("myApp.favorite.success"),
"Added to favorites",
),
options: { severity: "success", type: "app:channel:favorite:success" },
origin: { emitter: "FavoriteButton" },
});
} catch (error) {
addNotification({
message: t(
asDynamicKey("myApp.favorite.failed"),
"Could not add to favorites",
),
options: {
originalError: error instanceof Error ? error : undefined,
severity: "error",
type: "app:channel:favorite:failed",
},
origin: { emitter: "FavoriteButton" },
});
}
};
return (
<Pressable accessibilityRole="button" onPress={favorite}>
<Text>Favorite</Text>
</Pressable>
);
};Use a type of your own, in the domain:entity:operation:result form. A type from the tables above renders its mapped key instead of the message, except browser:audio:playback:error, which renders its message when it has one. Publishing, severity and durations are on Publishing notifications, and routing a notification to another part of the screen is on Routing notifications.
Text the SDK's components don't translate
The SDK's components publish notifications of their own, such as when a message action succeeds or a channel can't be left. Notifications lists every type, with its emitter and when it's published, and What the SDK publishes lists them by component.
Most messages are translated with t() before they're published. A failed message action whose error carries a message is the exception: the notification shows that message, which is the error's own text and isn't translated.
Uploads, sending, jumps in the message paginator, commands and poll votes are published by stream-chat: see Publishing notifications.