@cometchat/chat-uikit-react-native
Version:
Ready-to-use Chat UI Components for React Native
278 lines • 14.1 kB
JavaScript
import { ChatConfigurator, DataSourceDecorator } from "../../shared/framework";
import { CometChat } from "@cometchat/chat-sdk-react-native";
import { CometChatLocalize, localize } from "../../shared/resources/CometChatLocalize";
import { ExtensionConstants, ExtensionURLs } from "../ExtensionConstants";
import React from "react";
import { CometChatMentionsFormatter, CometChatUIKit, CometChatUrlsFormatter, } from "../../shared";
import { MentionsTargetElement, MessageOptionConstants } from "../../shared/constants/UIKitConstants";
import { CometChatUIEvents, MessageEvents } from "../../shared/events";
import { CometChatUIEventHandler } from "../../shared/events/CometChatUIEventHandler/CometChatUIEventHandler";
import { messageStatus } from "../../shared/utils/CometChatMessageHelper";
import { CommonUtils } from "../../shared/utils/CommonUtils";
import { MessageTranslationBubble } from "./MessageTranslationBubble";
import { Icon } from "../../shared/icons/Icon";
/**
* Decorator class for handling message translation in the chat application.
*/
export class MessageTranslationExtensionDecorator extends DataSourceDecorator {
translatedMessage = {};
/**
* Creates an instance of MessageTranslationExtensionDecorator.
*
* @param {DataSource} dataSource - The data source to be decorated.
*/
constructor(dataSource) {
super(dataSource);
}
/**
* Returns the unique ID for this extension.
*
* @returns {string} The ID string "MessageTranslation".
*/
getId() {
return "MessageTranslation";
}
/**
* Gets the text message options for a given message.
*
* @param {CometChat.User} loggedInUser - The currently logged in user.
* @param {CometChat.BaseMessage} messageObject - The message object.
* @param {CometChatTheme} theme - The current theme settings.
* @param {CometChat.Group} group - The group to which the message belongs.
*
* @returns {CometChatMessageOption[]} An array of message options including the translate option.
*/
getTextMessageOptions(loggedInUser, messageObject, theme, group, additionalParams) {
// Retrieve default text message options from the decorated data source.
let optionsList = super.getTextMessageOptions(loggedInUser, messageObject, theme, group, additionalParams);
// Add the translate option to the options list.
!additionalParams?.hideTranslateMessageOption && optionsList.push(this.getTranslateOption(messageObject, theme));
return optionsList;
}
/**
* Constructs the translation option for a message.
*
* @param {CometChat.BaseMessage} messageObject - The message object to be translated.
* @param {CometChatTheme} theme - The current theme settings.
*
* @returns {CometChatMessageOption} A message option object for translation.
*/
getTranslateOption(messageObject, theme) {
return {
id: MessageOptionConstants.translateMessage,
title: localize("TRANSLATE"),
icon: (<Icon name='translate' color={theme.messageListStyles?.messageOptionsStyles?.optionsItemStyle?.iconStyle?.tintColor} height={theme.messageListStyles?.messageOptionsStyles?.optionsItemStyle?.iconStyle?.height} width={theme.messageListStyles?.messageOptionsStyles?.optionsItemStyle?.iconStyle?.width} containerStyle={theme.messageListStyles?.messageOptionsStyles?.optionsItemStyle?.iconContainerStyle}></Icon>),
onPress: () => {
// Invoke translation when the option is pressed.
this.translateMessage(messageObject);
},
};
}
/**
* Updates the metadata of a message with translation information.
*
* @param {CometChat.TextMessage} messageObj - The text message object.
* @param {any} messageTranslation - The translated text for the message.
*
* @returns {object} An object containing the updated message and translation metadata.
*/
getSetMetaData = (messageObj, messageTranslation) => {
let metaData = messageObj.getMetadata();
if (!metaData) {
metaData = {};
}
// Inject the translate extension if not already present.
if (metaData && !metaData["@injected"]) {
metaData = {
...metaData,
"@injected": { extensions: { translate: {} } },
};
}
if (metaData && metaData["@injected"] && metaData["@injected"]["extensions"]) {
let tempData = metaData["@injected"]["extensions"];
tempData = {
...metaData,
"@injected": {
...metaData["@injected"],
extensions: {
...metaData["@injected"]["extensions"],
translate: { [messageObj.getId()]: messageTranslation },
},
},
};
metaData = tempData;
}
if (metaData && metaData["@injected"] && metaData["@injected"]["extensions"]["translate"]) {
let tempMetaData = {};
let translateData = metaData["@injected"]["extensions"]["translate"];
if (translateData) {
translateData = {
...translateData,
[messageObj.getId()]: messageTranslation,
};
}
else {
translateData[messageObj.getId()] = {
[messageObj.getId()]: messageTranslation,
};
}
tempMetaData = {
...metaData["@injected"]["extensions"]["translate"],
...translateData,
};
metaData["@injected"]["extensions"]["translate"] = tempMetaData;
}
// Update the message metadata.
messageObj.setMetadata(metaData);
return {
msg: messageObj,
metaData: metaData["@injected"]["extensions"]["translate"],
};
};
/**
* Translates a given text message by calling the translation extension.
*
* @param {CometChat.TextMessage} message - The text message to be translated.
*/
translateMessage = (message) => {
const messageId = message.getId();
const messageText = message.getText();
// Get the target language for translation.
let translateToLanguage = CometChatLocalize.getLocale();
// Hide the bottom sheet (if visible).
CometChatUIEventHandler.emitUIEvent(CometChatUIEvents.ccToggleBottomSheet, {
isBottomSheetVisible: false,
});
// Modify the text to avoid translating specific tags.
let tempText = messageText.replace(/<@uid:[a-zA-Z0-9]+>/g, (match) => `<span translate='no'>${match}</span>`);
// Call the translation extension endpoint.
CometChat.callExtension(ExtensionConstants.messageTranslation, "POST", ExtensionURLs.translate, {
msgId: messageId,
text: tempText,
languages: [translateToLanguage],
})
.then((result) => {
if (result?.hasOwnProperty("translations") && result["translations"]["length"]) {
let messageTranslation = result["translations"][0];
// Replace span tags to restore original formatting.
messageTranslation["message_translated"] = messageTranslation["message_translated"].replace(/<span translate='no'>(<@uid:[a-zA-Z0-9]+>)<\/span>/g, (_, match) => match);
// Update message metadata with translation.
const translatedMsg = this.getSetMetaData(message, messageTranslation["message_translated"]);
if (translatedMsg) {
if (translatedMsg.metaData?.translate)
this.translatedMessage = translatedMsg?.metaData?.translate;
}
else {
this.translatedMessage = {
[message.getId()]: `${messageTranslation["message_translated"]}`,
};
}
// Emit an event indicating the message has been edited.
CometChatUIEventHandler.emitMessageEvent(MessageEvents.ccMessageEdited, {
message: translatedMsg.msg,
status: messageStatus.success,
});
}
})
.catch((error) => {
console.log(error);
});
};
/**
* Returns the text message bubble component.
*
* This method renders a MessageTranslationBubble if the message has been translated;
* otherwise, it falls back to the default text message bubble.
*
* @param {string} messageText - The original text of the message.
* @param {CometChat.TextMessage} message - The message object.
* @param {MessageBubbleAlignmentType} alignment - The alignment of the message bubble.
* @param {CometChatTheme} theme - The current theme settings.
* @param {AdditionalParams} [additionalParams] - Additional parameters for rendering.
*
* @returns {JSX.Element} The text message bubble component.
*/
getTextMessageBubble(messageText, message, alignment, theme, additionalParams) {
let tempTranslatedMsg = {};
let translatedMetaData = message.getMetadata();
// Check if translation metadata exists in the message.
if (translatedMetaData &&
translatedMetaData["@injected"] &&
translatedMetaData["@injected"]["extensions"] &&
translatedMetaData["@injected"]["extensions"]["translate"]) {
tempTranslatedMsg = translatedMetaData["@injected"]["extensions"]["translate"];
}
let loggedInUser = CometChatUIKit.loggedInUser;
let mentionedUsers = message.getMentionedUsers();
let textFormatters = [...(additionalParams?.textFormatters || [])];
// Determine if the message was sent by the logged-in user.
const isMessageSentByLoggedInUser = message.getSender().getUid() === loggedInUser.getUid();
// Select the appropriate style based on the sender.
const _style = isMessageSentByLoggedInUser
? theme.messageListStyles.outgoingMessageBubbleStyles.textBubbleStyles
: theme.messageListStyles.incomingMessageBubbleStyles.textBubbleStyles;
// Create URL formatter and set properties.
let linksTextFormatter = ChatConfigurator.getDataSource().getUrlsFormatter(loggedInUser);
let mentionsTextFormatter = ChatConfigurator.getDataSource().getMentionsFormatter(loggedInUser);
linksTextFormatter.setMessage(message);
linksTextFormatter.setId("ccDefaultUrlsFormatterId");
linksTextFormatter.setStyle({ linkTextColor: theme.color.receiveBubbleLink });
if (isMessageSentByLoggedInUser) {
linksTextFormatter.setStyle({ linkTextColor: theme.color.sendBubbleText });
}
// Configure mentions formatter if mentioned users are present.
if (!additionalParams?.disableMentions && mentionedUsers && mentionedUsers.length) {
mentionsTextFormatter.setLoggedInUser(loggedInUser);
mentionsTextFormatter.setMessage(message);
mentionsTextFormatter.setId("ccDefaultMentionFormatterId");
let isUserSentMessage = message.getSender().getUid() == loggedInUser.getUid();
if (isUserSentMessage) {
mentionsTextFormatter.setMentionsStyle(_style?.mentionsStyle);
}
else {
mentionsTextFormatter.setMentionsStyle(_style?.mentionsStyle);
}
mentionsTextFormatter.setTextStyle(_style?.textStyle);
}
let finalFormatters = [];
let urlFormatterExists = false;
let mentionsFormatterExists = false;
// Process the provided text formatters.
for (const formatter of textFormatters) {
if (formatter instanceof CometChatUrlsFormatter) {
urlFormatterExists = true;
}
if (formatter instanceof CometChatMentionsFormatter) {
mentionsFormatterExists = true;
formatter.setMessage(message);
formatter.setTargetElement(MentionsTargetElement.textbubble);
formatter.setLoggedInUser(CometChatUIKit.loggedInUser);
}
formatter.setMessage(message);
finalFormatters.push(CommonUtils.clone(formatter));
if (urlFormatterExists && mentionsFormatterExists) {
break;
}
}
// Ensure URL formatter is present.
if (!urlFormatterExists) {
finalFormatters.push(linksTextFormatter);
}
// Ensure mentions formatter is present.
if (!mentionsFormatterExists) {
finalFormatters.push(mentionsTextFormatter);
}
// If a translation exists for the message, render the MessageTranslationBubble.
if ((tempTranslatedMsg && tempTranslatedMsg[message.getId()]) ||
(this.translatedMessage && this.translatedMessage[message.getId()])) {
return (<MessageTranslationBubble translatedText={tempTranslatedMsg
? tempTranslatedMsg[message.getId()]
: this.translatedMessage[message.getId()]
? this.translatedMessage[message.getId()]
: ""} textStyle={_style?.textStyle} textContainerStyle={_style?.textContainerStyle} translatedTextStyle={_style?.translatedTextStyle} translatedTextContainerStyle={_style?.translatedTextContainerStyle} text={messageText} alignment={alignment} textFormatters={finalFormatters} translatedTextDividerStyle={_style?.translatedTextDividerStyle}/>);
}
// Otherwise, return the default text message bubble from the decorated data source.
return super.getTextMessageBubble(messageText, message, alignment, theme, additionalParams);
}
}
//# sourceMappingURL=MessageTranslationDecorator.js.map