Add localization support for chat message components with enhanced Translation component (#4560)
* Initial plan * Add localization support for chat message components Co-authored-by: gabek <414923+gabek@users.noreply.github.com> * Update chat message localization to use string interpolation Co-authored-by: gabek <414923+gabek@users.noreply.github.com> * Restore original styling while preserving string interpolation Co-authored-by: gabek <414923+gabek@users.noreply.github.com> * Separate styling from variables in translation templates Co-authored-by: gabek <414923+gabek@users.noreply.github.com> * Revert to concatenation approach for chat message localization Co-authored-by: gabek <414923+gabek@users.noreply.github.com> * Add id property to Translation component and restore missing CSS classes and IDs Co-authored-by: gabek <414923+gabek@users.noreply.github.com> * Javascript formatting autofixes --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: gabek <414923+gabek@users.noreply.github.com> Co-authored-by: Gabe Kangas <gabek@real-ity.com> Co-authored-by: Owncast <owncast@owncast.online>
This commit is contained in:
co-authored by
gabek
copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Gabe Kangas
Owncast
parent
fa1b07e987
commit
275339bdf0
@@ -1,6 +1,8 @@
|
|||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import { ModerationBadge } from '../ChatUserBadge/ModerationBadge';
|
import { ModerationBadge } from '../ChatUserBadge/ModerationBadge';
|
||||||
|
import { Translation } from '../../ui/Translation/Translation';
|
||||||
|
import { Localization } from '../../../types/localization';
|
||||||
|
|
||||||
import styles from './ChatJoinMessage.module.scss';
|
import styles from './ChatJoinMessage.module.scss';
|
||||||
|
|
||||||
@@ -29,13 +31,19 @@ export const ChatJoinMessage: FC<ChatJoinMessageProps> = ({
|
|||||||
<span className={styles.icon}>
|
<span className={styles.icon}>
|
||||||
<UsergroupAddOutlined />
|
<UsergroupAddOutlined />
|
||||||
</span>
|
</span>
|
||||||
<span className={styles.user}>{displayName}</span>
|
|
||||||
{isAuthorModerator && (
|
{isAuthorModerator && (
|
||||||
<span className={styles.moderatorBadge}>
|
<span className={styles.moderatorBadge}>
|
||||||
<ModerationBadge userColor={userColor} />
|
<ModerationBadge userColor={userColor} />
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<span className={styles.joinMessage}>joined the chat.</span>
|
<span className={styles.joinMessage}>
|
||||||
|
<span className={styles.user}>{displayName}</span>
|
||||||
|
<span> </span>
|
||||||
|
<Translation
|
||||||
|
translationKey={Localization.Frontend.Chat.userJoined}
|
||||||
|
defaultText="joined the chat."
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
|
import { Translation } from '../../ui/Translation/Translation';
|
||||||
|
import { Localization } from '../../../types/localization';
|
||||||
import styles from './ChatModeratorNotification.module.scss';
|
import styles from './ChatModeratorNotification.module.scss';
|
||||||
import Icon from '../../../assets/images/moderator.svg';
|
import Icon from '../../../assets/images/moderator.svg';
|
||||||
|
|
||||||
export const ChatModeratorNotification = () => (
|
export const ChatModeratorNotification = () => (
|
||||||
<div className={styles.chatModerationNotification}>
|
<div className={styles.chatModerationNotification}>
|
||||||
<Icon className={styles.icon} />
|
<Icon className={styles.icon} />
|
||||||
You are now a moderator.
|
<Translation
|
||||||
|
translationKey={Localization.Frontend.Chat.moderatorNotification}
|
||||||
|
defaultText="You are now a moderator."
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
// export const ChatSocialMessage: FC<ChatSocialMessageProps> = ({ message }) => {
|
|
||||||
|
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { NameChangeEvent } from '../../../interfaces/socket-events';
|
import { NameChangeEvent } from '../../../interfaces/socket-events';
|
||||||
|
import { Translation } from '../../ui/Translation/Translation';
|
||||||
|
import { Localization } from '../../../types/localization';
|
||||||
import styles from './ChatNameChangeMessage.module.scss';
|
import styles from './ChatNameChangeMessage.module.scss';
|
||||||
|
|
||||||
export interface ChatNameChangeMessageProps {
|
export interface ChatNameChangeMessageProps {
|
||||||
@@ -27,10 +27,14 @@ export const ChatNameChangeMessage: FC<ChatNameChangeMessageProps> = ({ message
|
|||||||
</div>
|
</div>
|
||||||
<div className={styles.nameChangeText}>
|
<div className={styles.nameChangeText}>
|
||||||
<span style={{ color }}>{oldName}</span>
|
<span style={{ color }}>{oldName}</span>
|
||||||
<span className={styles.plain} id="owncast-name-change-is-now-known-text">
|
<span> </span>
|
||||||
{' '}
|
<Translation
|
||||||
is now known as{' '}
|
translationKey={Localization.Frontend.Chat.nameChangeText}
|
||||||
</span>
|
className={styles.plain}
|
||||||
|
id="owncast-name-change-is-now-known-text"
|
||||||
|
defaultText="is now known as"
|
||||||
|
/>
|
||||||
|
<span> </span>
|
||||||
<span style={{ color }}>{displayName}</span>
|
<span style={{ color }}>{displayName}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import { ModerationBadge } from '../ChatUserBadge/ModerationBadge';
|
import { ModerationBadge } from '../ChatUserBadge/ModerationBadge';
|
||||||
|
import { Translation } from '../../ui/Translation/Translation';
|
||||||
|
import { Localization } from '../../../types/localization';
|
||||||
|
|
||||||
import styles from './ChatPartMessage.module.scss';
|
import styles from './ChatPartMessage.module.scss';
|
||||||
|
|
||||||
@@ -29,13 +31,19 @@ export const ChatPartMessage: FC<ChatPartMessageProps> = ({
|
|||||||
<span className={styles.icon}>
|
<span className={styles.icon}>
|
||||||
<UsergroupDeleteOutlined />
|
<UsergroupDeleteOutlined />
|
||||||
</span>
|
</span>
|
||||||
<span className={styles.user}>{displayName}</span>
|
|
||||||
{isAuthorModerator && (
|
{isAuthorModerator && (
|
||||||
<span className={styles.moderatorBadge}>
|
<span className={styles.moderatorBadge}>
|
||||||
<ModerationBadge userColor={userColor} />
|
<ModerationBadge userColor={userColor} />
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<span className={styles.partMessage}>left the chat.</span>
|
<span className={styles.partMessage}>
|
||||||
|
<span className={styles.user}>{displayName}</span>
|
||||||
|
<span> </span>
|
||||||
|
<Translation
|
||||||
|
translationKey={Localization.Frontend.Chat.userLeft}
|
||||||
|
defaultText="left the chat."
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export interface TranslationProps {
|
|||||||
translationKey: LocalizationKey;
|
translationKey: LocalizationKey;
|
||||||
vars?: Record<string, any>;
|
vars?: Record<string, any>;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
id?: string;
|
||||||
defaultText?: string;
|
defaultText?: string;
|
||||||
count?: number;
|
count?: number;
|
||||||
}
|
}
|
||||||
@@ -15,6 +16,7 @@ export const Translation: FC<TranslationProps> = ({
|
|||||||
translationKey,
|
translationKey,
|
||||||
vars,
|
vars,
|
||||||
className,
|
className,
|
||||||
|
id,
|
||||||
defaultText,
|
defaultText,
|
||||||
count,
|
count,
|
||||||
}) => {
|
}) => {
|
||||||
@@ -55,7 +57,9 @@ export const Translation: FC<TranslationProps> = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return <span className={className} dangerouslySetInnerHTML={{ __html: translatedText }} />;
|
return (
|
||||||
|
<span className={className} id={id} dangerouslySetInnerHTML={{ __html: translatedText }} />
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Translation;
|
export default Translation;
|
||||||
|
|||||||
@@ -118,6 +118,12 @@
|
|||||||
"contribute": "Contribute",
|
"contribute": "Contribute",
|
||||||
"source": "Source"
|
"source": "Source"
|
||||||
},
|
},
|
||||||
|
"Chat": {
|
||||||
|
"userJoined": "joined the chat.",
|
||||||
|
"userLeft": "left the chat.",
|
||||||
|
"nameChangeText": "is now known as",
|
||||||
|
"moderatorNotification": "You are now a moderator."
|
||||||
|
,
|
||||||
"FollowModal": {
|
"FollowModal": {
|
||||||
"description": "By following this stream you'll get notified on the Fediverse when it goes live. Now is a great time to",
|
"description": "By following this stream you'll get notified on the Fediverse when it goes live. Now is a great time to",
|
||||||
"learnFediverse": "learn about the Fediverse",
|
"learnFediverse": "learn about the Fediverse",
|
||||||
|
|||||||
@@ -100,6 +100,14 @@ export const Localization = {
|
|||||||
source: 'Frontend.Footer.source',
|
source: 'Frontend.Footer.source',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Chat message components
|
||||||
|
Chat: {
|
||||||
|
userJoined: 'Frontend.Chat.userJoined',
|
||||||
|
userLeft: 'Frontend.Chat.userLeft',
|
||||||
|
nameChangeText: 'Frontend.Chat.nameChangeText',
|
||||||
|
moderatorNotification: 'Frontend.Chat.moderatorNotification',
|
||||||
|
},
|
||||||
|
|
||||||
// Follow modal component
|
// Follow modal component
|
||||||
FollowModal: {
|
FollowModal: {
|
||||||
description: 'Frontend.FollowModal.description',
|
description: 'Frontend.FollowModal.description',
|
||||||
|
|||||||
Reference in New Issue
Block a user