chore: rename I18n component to Localizer

pull/3206/head
Ryan Miller 8 months ago
parent 28cf1a3dd7
commit 70d83c1b7e

@ -2,7 +2,7 @@ import styled from 'styled-components';
import type { import type {
ArgsRecord, ArgsRecord,
GetMessageArgs, GetMessageArgs,
I18nProps, LocalizerComponentProps,
LocalizerDictionary, LocalizerDictionary,
LocalizerToken, LocalizerToken,
} from '../../types/Localizer'; } from '../../types/Localizer';
@ -85,19 +85,17 @@ const StyledHtmlRenderer = styled.span<{ isDarkTheme: boolean }>`
* @param props.token - The token identifying the message to retrieve and an optional record of substitution variables and their replacement values. * @param props.token - The token identifying the message to retrieve and an optional record of substitution variables and their replacement values.
* @param props.args - An optional record of substitution variables and their replacement values. This is required if the string has dynamic parts. * @param props.args - An optional record of substitution variables and their replacement values. This is required if the string has dynamic parts.
* @param props.as - An optional HTML tag to render the component as. Defaults to a fragment, unless the string contains html tags. In that case, it will render as HTML in a div tag. * @param props.as - An optional HTML tag to render the component as. Defaults to a fragment, unless the string contains html tags. In that case, it will render as HTML in a div tag.
* @param props.startTagProps - An optional object of props to pass to the start tag.
* @param props.endTagProps - An optional object of props to pass to the end tag.
* *
* @returns The localized message string with substitutions and formatting applied. * @returns The localized message string with substitutions and formatting applied.
* *
* @example * @example
* ```tsx * ```tsx
* <I18n token="about" /> * <Localizer token="about" />
* <I18n token="about" as='h1' /> * <Localizer token="about" as='h1' />
* <I18n token="disappearingMessagesFollowSettingOn" args={{ time: 10, type: 'mode' }} /> * <Localizer token="disappearingMessagesFollowSettingOn" args={{ time: 10, type: 'mode' }} />
* ``` * ```
*/ */
export const I18n = <T extends LocalizerToken>(props: I18nProps<T>) => { export const Localizer = <T extends LocalizerToken>(props: LocalizerComponentProps<T>) => {
const isDarkMode = useIsDarkTheme(); const isDarkMode = useIsDarkTheme();
const args = 'args' in props ? props.args : undefined; const args = 'args' in props ? props.args : undefined;

@ -1,6 +1,6 @@
import DOMPurify from 'dompurify'; import DOMPurify from 'dompurify';
import { createElement, type ElementType } from 'react'; import { createElement, type ElementType } from 'react';
import { supportedFormattingTags } from './I18n'; import { supportedFormattingTags } from './Localizer';
type ReceivedProps = { type ReceivedProps = {
html: string; html: string;

@ -1,7 +1,7 @@
import styled from 'styled-components'; import styled from 'styled-components';
import { forwardRef } from 'react'; import { forwardRef } from 'react';
import { I18n } from './I18n'; import { Localizer } from './Localizer';
import { I18nProps, LocalizerToken } from '../../types/Localizer'; import { LocalizerComponentProps, LocalizerToken } from '../../types/Localizer';
const StyledI18nSubTextContainer = styled('div')` const StyledI18nSubTextContainer = styled('div')`
font-size: var(--font-size-md); font-size: var(--font-size-md);
@ -15,12 +15,13 @@ const StyledI18nSubTextContainer = styled('div')`
padding-inline: var(--margins-lg); padding-inline: var(--margins-lg);
`; `;
export const StyledI18nSubText = forwardRef<HTMLSpanElement, I18nProps<LocalizerToken>>( export const StyledI18nSubText = forwardRef<
({ className, ...props }) => { HTMLSpanElement,
return ( LocalizerComponentProps<LocalizerToken>
<StyledI18nSubTextContainer className={className}> >(({ className, ...props }) => {
<I18n {...props} /> return (
</StyledI18nSubTextContainer> <StyledI18nSubTextContainer className={className}>
); <Localizer {...props} />
} </StyledI18nSubTextContainer>
); );
});

@ -15,7 +15,7 @@ import {
useSelectedIsPrivate, useSelectedIsPrivate,
useSelectedNicknameOrProfileNameOrShortenedPubkey, useSelectedNicknameOrProfileNameOrShortenedPubkey,
} from '../../state/selectors/selectedConversation'; } from '../../state/selectors/selectedConversation';
import { I18n } from '../basic/I18n'; import { Localizer } from '../basic/Localizer';
const Container = styled.div` const Container = styled.div`
display: flex; display: flex;
@ -99,18 +99,18 @@ export const NoMessageInConversation = () => {
const content = useMemo(() => { const content = useMemo(() => {
if (isMe) { if (isMe) {
return <I18n token="noteToSelfEmpty" />; return <Localizer token="noteToSelfEmpty" />;
} }
if (canWrite) { if (canWrite) {
return <I18n token="groupNoMessages" args={{ group_name: name }} />; return <Localizer token="groupNoMessages" args={{ group_name: name }} />;
} }
if (privateBlindedAndBlockingMsgReqs) { if (privateBlindedAndBlockingMsgReqs) {
return <I18n token="messageRequestsTurnedOff" args={{ name }} />; return <Localizer token="messageRequestsTurnedOff" args={{ name }} />;
} }
return <I18n token="conversationsEmpty" args={{ conversation_name: name }} />; return <Localizer token="conversationsEmpty" args={{ conversation_name: name }} />;
}, [isMe, canWrite, privateBlindedAndBlockingMsgReqs, name]); }, [isMe, canWrite, privateBlindedAndBlockingMsgReqs, name]);
if (!selectedConversation || hasMessages) { if (!selectedConversation || hasMessages) {

@ -24,8 +24,8 @@ import { getConversationController } from '../../session/conversations';
import { updateConfirmModal } from '../../state/ducks/modalDialog'; import { updateConfirmModal } from '../../state/ducks/modalDialog';
import { SessionButtonColor } from '../basic/SessionButton'; import { SessionButtonColor } from '../basic/SessionButton';
import { SessionIcon } from '../icon'; import { SessionIcon } from '../icon';
import { I18n } from '../basic/I18n'; import { Localizer } from '../basic/Localizer';
import { I18nProps, LocalizerToken } from '../../types/Localizer'; import type { LocalizerComponentProps, LocalizerToken } from '../../types/Localizer';
const FollowSettingButton = styled.button` const FollowSettingButton = styled.button`
color: var(--primary-color); color: var(--primary-color);
@ -50,14 +50,14 @@ function useFollowSettingsButtonClick(
const i18nMessage = props.disabled const i18nMessage = props.disabled
? ({ ? ({
token: 'disappearingMessagesFollowSettingOff', token: 'disappearingMessagesFollowSettingOff',
} as I18nProps<'disappearingMessagesFollowSettingOff'>) } as LocalizerComponentProps<'disappearingMessagesFollowSettingOff'>)
: ({ : ({
token: 'disappearingMessagesFollowSettingOn', token: 'disappearingMessagesFollowSettingOn',
args: { args: {
time: props.timespanText, time: props.timespanText,
disappearing_messages_type: localizedMode, disappearing_messages_type: localizedMode,
}, },
} as I18nProps<'disappearingMessagesFollowSettingOn'>); } as LocalizerComponentProps<'disappearingMessagesFollowSettingOn'>);
const okText = props.disabled ? window.i18n('yes') : window.i18n('set'); const okText = props.disabled ? window.i18n('yes') : window.i18n('set');
@ -193,7 +193,7 @@ function useTextToRenderI18nProps(props: PropsForExpirationTimer) {
export const TimerNotification = (props: PropsForExpirationTimer) => { export const TimerNotification = (props: PropsForExpirationTimer) => {
const { messageId } = props; const { messageId } = props;
const i18nProps = useTextToRenderI18nProps(props) as I18nProps<LocalizerToken>; const i18nProps = useTextToRenderI18nProps(props) as LocalizerComponentProps<LocalizerToken>;
const isGroupOrCommunity = useSelectedIsGroupOrCommunity(); const isGroupOrCommunity = useSelectedIsGroupOrCommunity();
const isGroupV2 = useSelectedIsGroupV2(); const isGroupV2 = useSelectedIsGroupV2();
// renderOff is true when the update is put to off, or when we have a legacy group control message (as they are not expiring at all) // renderOff is true when the update is put to off, or when we have a legacy group control message (as they are not expiring at all)
@ -228,7 +228,7 @@ export const TimerNotification = (props: PropsForExpirationTimer) => {
</> </>
)} )}
<TextWithChildren subtle={true}> <TextWithChildren subtle={true}>
<I18n {...i18nProps} /> <Localizer {...i18nProps} />
</TextWithChildren> </TextWithChildren>
<FollowSettingsButton {...props} /> <FollowSettingsButton {...props} />
</Flex> </Flex>

@ -71,17 +71,16 @@ export const ConversationHeaderTitle = (props: ConversationHeaderTitleProps) =>
); );
const memberCountSubtitle = useMemo(() => { const memberCountSubtitle = useMemo(() => {
let memberCount = 0; let count = 0;
if (isGroup) { if (isGroup) {
if (isPublic) { if (isPublic) {
memberCount = subscriberCount || 0; count = subscriberCount || 0;
} else { } else {
memberCount = members.length; count = members.length;
} }
} }
if (isGroup && memberCount > 0 && !isKickedFromGroup) { if (isGroup && count > 0 && !isKickedFromGroup) {
const count = String(memberCount);
return isPublic ? i18n('membersActive', { count }) : i18n('members', { count }); return isPublic ? i18n('membersActive', { count }) : i18n('members', { count });
} }

@ -2,7 +2,7 @@ import { PropsForDataExtractionNotification } from '../../../../models/messageTy
import { SignalService } from '../../../../protobuf'; import { SignalService } from '../../../../protobuf';
import { ExpirableReadableMessage } from './ExpirableReadableMessage'; import { ExpirableReadableMessage } from './ExpirableReadableMessage';
import { NotificationBubble } from './notification-bubble/NotificationBubble'; import { NotificationBubble } from './notification-bubble/NotificationBubble';
import { I18n } from '../../../basic/I18n'; import { Localizer } from '../../../basic/Localizer';
export const DataExtractionNotification = (props: PropsForDataExtractionNotification) => { export const DataExtractionNotification = (props: PropsForDataExtractionNotification) => {
const { name, type, source, messageId } = props; const { name, type, source, messageId } = props;
@ -15,7 +15,7 @@ export const DataExtractionNotification = (props: PropsForDataExtractionNotifica
isControlMessage={true} isControlMessage={true}
> >
<NotificationBubble iconType="save"> <NotificationBubble iconType="save">
<I18n <Localizer
token={ token={
type === SignalService.DataExtractionNotification.Type.MEDIA_SAVED type === SignalService.DataExtractionNotification.Type.MEDIA_SAVED
? 'attachmentsMediaSaved' ? 'attachmentsMediaSaved'

@ -11,12 +11,12 @@ import {
import { useSelectedNicknameOrProfileNameOrShortenedPubkey } from '../../../../state/selectors/selectedConversation'; import { useSelectedNicknameOrProfileNameOrShortenedPubkey } from '../../../../state/selectors/selectedConversation';
import { ExpirableReadableMessage } from './ExpirableReadableMessage'; import { ExpirableReadableMessage } from './ExpirableReadableMessage';
import { NotificationBubble } from './notification-bubble/NotificationBubble'; import { NotificationBubble } from './notification-bubble/NotificationBubble';
import { I18n } from '../../../basic/I18n'; import { Localizer } from '../../../basic/Localizer';
import { type I18nPropsObject } from '../../../../types/Localizer'; import { type LocalizerComponentPropsObject } from '../../../../types/Localizer';
// This component is used to display group updates in the conversation view. // This component is used to display group updates in the conversation view.
const ChangeItemJoined = (added: Array<string>): I18nPropsObject => { const ChangeItemJoined = (added: Array<string>): LocalizerComponentPropsObject => {
const groupName = useSelectedNicknameOrProfileNameOrShortenedPubkey(); const groupName = useSelectedNicknameOrProfileNameOrShortenedPubkey();
if (!added.length) { if (!added.length) {
@ -26,7 +26,7 @@ const ChangeItemJoined = (added: Array<string>): I18nPropsObject => {
return getJoinedGroupUpdateChangeStr(added, groupName); return getJoinedGroupUpdateChangeStr(added, groupName);
}; };
const ChangeItemKicked = (kicked: Array<string>): I18nPropsObject => { const ChangeItemKicked = (kicked: Array<string>): LocalizerComponentPropsObject => {
if (!kicked.length) { if (!kicked.length) {
throw new Error('Group update kicked is missing details'); throw new Error('Group update kicked is missing details');
} }
@ -35,7 +35,7 @@ const ChangeItemKicked = (kicked: Array<string>): I18nPropsObject => {
return getKickedGroupUpdateStr(kicked, groupName); return getKickedGroupUpdateStr(kicked, groupName);
}; };
const ChangeItemLeft = (left: Array<string>): I18nPropsObject => { const ChangeItemLeft = (left: Array<string>): LocalizerComponentPropsObject => {
const groupName = useSelectedNicknameOrProfileNameOrShortenedPubkey(); const groupName = useSelectedNicknameOrProfileNameOrShortenedPubkey();
if (!left.length) { if (!left.length) {
@ -45,7 +45,7 @@ const ChangeItemLeft = (left: Array<string>): I18nPropsObject => {
return getLeftGroupUpdateChangeStr(left, groupName); return getLeftGroupUpdateChangeStr(left, groupName);
}; };
const ChangeItem = (change: PropsForGroupUpdateType): I18nPropsObject => { const ChangeItem = (change: PropsForGroupUpdateType): LocalizerComponentPropsObject => {
const { type } = change; const { type } = change;
switch (type) { switch (type) {
case 'name': case 'name':
@ -79,7 +79,7 @@ export const GroupUpdateMessage = (props: PropsForGroupUpdate) => {
isControlMessage={true} isControlMessage={true}
> >
<NotificationBubble iconType="users"> <NotificationBubble iconType="users">
{!isNull(changeItem) ? <I18n {...changeItem} /> : null} {!isNull(changeItem) ? <Localizer {...changeItem} /> : null}
</NotificationBubble> </NotificationBubble>
</ExpirableReadableMessage> </ExpirableReadableMessage>
); );

@ -2,7 +2,7 @@ import { useNicknameOrProfileNameOrShortenedPubkey } from '../../../../hooks/use
import { PropsForMessageRequestResponse } from '../../../../models/messageType'; import { PropsForMessageRequestResponse } from '../../../../models/messageType';
import { UserUtils } from '../../../../session/utils'; import { UserUtils } from '../../../../session/utils';
import { Flex } from '../../../basic/Flex'; import { Flex } from '../../../basic/Flex';
import { I18n } from '../../../basic/I18n'; import { Localizer } from '../../../basic/Localizer';
import { SpacerSM, TextWithChildren } from '../../../basic/Text'; import { SpacerSM, TextWithChildren } from '../../../basic/Text';
import { ReadableMessage } from './ReadableMessage'; import { ReadableMessage } from './ReadableMessage';
@ -32,14 +32,14 @@ export const MessageRequestResponse = (props: PropsForMessageRequestResponse) =>
<SpacerSM /> <SpacerSM />
<TextWithChildren subtle={true} ellipsisOverflow={false} textAlign="center"> <TextWithChildren subtle={true} ellipsisOverflow={false} textAlign="center">
{isFromSync ? ( {isFromSync ? (
<I18n <Localizer
token="messageRequestYouHaveAccepted" token="messageRequestYouHaveAccepted"
args={{ args={{
name: profileName || window.i18n('unknown'), name: profileName || window.i18n('unknown'),
}} }}
/> />
) : ( ) : (
<I18n token="messageRequestsAccepted" /> <Localizer token="messageRequestsAccepted" />
)} )}
</TextWithChildren> </TextWithChildren>
</Flex> </Flex>

@ -5,7 +5,7 @@ import { LocalizerToken } from '../../../../../types/Localizer';
import { SessionIconType } from '../../../../icon'; import { SessionIconType } from '../../../../icon';
import { ExpirableReadableMessage } from '../ExpirableReadableMessage'; import { ExpirableReadableMessage } from '../ExpirableReadableMessage';
import { NotificationBubble } from './NotificationBubble'; import { NotificationBubble } from './NotificationBubble';
import { I18n } from '../../../../basic/I18n'; import { Localizer } from '../../../../basic/Localizer';
type StyleType = Record< type StyleType = Record<
CallNotificationType, CallNotificationType,
@ -45,7 +45,7 @@ export const CallNotification = (props: PropsForCallNotification) => {
isControlMessage={true} isControlMessage={true}
> >
<NotificationBubble iconType={iconType} iconColor={iconColor}> <NotificationBubble iconType={iconType} iconColor={iconColor}>
<I18n token={notificationTextKey} args={{ name }} /> <Localizer token={notificationTextKey} args={{ name }} />
</NotificationBubble> </NotificationBubble>
</ExpirableReadableMessage> </ExpirableReadableMessage>
); );

@ -3,9 +3,9 @@ import styled from 'styled-components';
import { findAndFormatContact } from '../../../../models/message'; import { findAndFormatContact } from '../../../../models/message';
import { PubKey } from '../../../../session/types/PubKey'; import { PubKey } from '../../../../session/types/PubKey';
import { I18n } from '../../../basic/I18n'; import { Localizer } from '../../../basic/Localizer';
import { nativeEmojiData } from '../../../../util/emoji'; import { nativeEmojiData } from '../../../../util/emoji';
import { type I18nPropsObject } from '../../../../types/Localizer'; import { type LocalizerComponentPropsObject } from '../../../../types/Localizer';
export type TipPosition = 'center' | 'left' | 'right'; export type TipPosition = 'center' | 'left' | 'right';
@ -83,7 +83,7 @@ const getI18nComponentProps = (
numberOfReactors: number, numberOfReactors: number,
emoji: string, emoji: string,
emojiName?: string emojiName?: string
): I18nPropsObject => { ): LocalizerComponentPropsObject => {
const name = contacts[0]; const name = contacts[0];
const other_name = contacts[1]; const other_name = contacts[1];
const emoji_name = emojiName ? `:${emojiName}:` : emoji; const emoji_name = emojiName ? `:${emojiName}:` : emoji;
@ -134,7 +134,7 @@ export const ReactionPopup = (props: Props) => {
return ( return (
<StyledPopupContainer tooltipPosition={tooltipPosition} onClick={onClick}> <StyledPopupContainer tooltipPosition={tooltipPosition} onClick={onClick}>
<I18n {...i18nProps} /> <Localizer {...i18nProps} />
<StyledEmoji role={'img'} aria-label={emojiAriaLabel}> <StyledEmoji role={'img'} aria-label={emojiAriaLabel}>
{emoji} {emoji}
</StyledEmoji> </StyledEmoji>

@ -8,7 +8,7 @@ import { SessionWrapperModal } from '../SessionWrapperModal';
import { Flex } from '../basic/Flex'; import { Flex } from '../basic/Flex';
import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton'; import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton';
import { SpacerMD } from '../basic/Text'; import { SpacerMD } from '../basic/Text';
import { I18n } from '../basic/I18n'; import { Localizer } from '../basic/Localizer';
const StyledDescriptionContainer = styled.div` const StyledDescriptionContainer = styled.div`
width: 280px; width: 280px;
@ -79,7 +79,7 @@ export function HideRecoveryPasswordDialog(props: HideRecoveryPasswordDialogProp
additionalClassName="no-body-padding" additionalClassName="no-body-padding"
> >
<StyledDescriptionContainer> <StyledDescriptionContainer>
<I18n <Localizer
token={ token={
state === 'firstWarning' state === 'firstWarning'
? 'recoveryPasswordHidePermanentlyDescription1' ? 'recoveryPasswordHidePermanentlyDescription1'

@ -27,7 +27,7 @@ import { MessageReactions } from '../conversation/message/message-content/Messag
import { SessionIconButton } from '../icon'; import { SessionIconButton } from '../icon';
import { SessionWrapperModal } from '../SessionWrapperModal'; import { SessionWrapperModal } from '../SessionWrapperModal';
import { findAndFormatContact } from '../../models/message'; import { findAndFormatContact } from '../../models/message';
import { I18n } from '../basic/I18n'; import { Localizer } from '../basic/Localizer';
const StyledReactListContainer = styled(Flex)` const StyledReactListContainer = styled(Flex)`
width: 376px; width: 376px;
@ -187,7 +187,7 @@ const StyledCountText = styled.p`
const CountText = ({ count, emoji }: { count: number; emoji: string }) => { const CountText = ({ count, emoji }: { count: number; emoji: string }) => {
return ( return (
<StyledCountText> <StyledCountText>
<I18n <Localizer
token="emojiReactsCountOthers" token="emojiReactsCountOthers"
args={{ args={{
count: count - Reactions.SOGSReactorsFetchCount, count: count - Reactions.SOGSReactorsFetchCount,

@ -10,13 +10,13 @@ import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/S
import { SessionRadioGroup, SessionRadioItems } from '../basic/SessionRadioGroup'; import { SessionRadioGroup, SessionRadioItems } from '../basic/SessionRadioGroup';
import { SpacerLG } from '../basic/Text'; import { SpacerLG } from '../basic/Text';
import { SessionSpinner } from '../loading'; import { SessionSpinner } from '../loading';
import { type I18nPropsObject } from '../../types/Localizer'; import { type LocalizerComponentPropsObject } from '../../types/Localizer';
import { StyledI18nSubText } from '../basic/StyledI18nSubText'; import { StyledI18nSubText } from '../basic/StyledI18nSubText';
export interface SessionConfirmDialogProps { export interface SessionConfirmDialogProps {
i18nMessage?: I18nPropsObject; i18nMessage?: LocalizerComponentPropsObject;
i18nMessageSub?: I18nPropsObject; i18nMessageSub?: LocalizerComponentPropsObject;
title?: string; title?: string;
radioOptions?: SessionRadioItems; radioOptions?: SessionRadioItems;
onOk?: any; onOk?: any;

@ -11,7 +11,7 @@ import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/S
import { SpacerLG } from '../basic/Text'; import { SpacerLG } from '../basic/Text';
import { useConversationRealName } from '../../hooks/useParamSelector'; import { useConversationRealName } from '../../hooks/useParamSelector';
import { PubKey } from '../../session/types'; import { PubKey } from '../../session/types';
import { I18n } from '../basic/I18n'; import { Localizer } from '../basic/Localizer';
type Props = { type Props = {
conversationId: string; conversationId: string;
@ -66,12 +66,12 @@ export const SessionNicknameDialog = (props: Props) => {
showHeader={true} showHeader={true}
> >
<StyledMaxWidth className="session-modal__centered"> <StyledMaxWidth className="session-modal__centered">
<I18n <Localizer
token="nicknameDescription" token="nicknameDescription"
args={{ args={{
name: displayName || PubKey.shorten(conversationId), name: displayName || PubKey.shorten(conversationId),
}} }}
></I18n> />
<SpacerLG /> <SpacerLG />
</StyledMaxWidth> </StyledMaxWidth>

@ -10,15 +10,15 @@ import { updateBlockOrUnblockModal } from '../../../state/ducks/modalDialog';
import { BlockedNumberController } from '../../../util'; import { BlockedNumberController } from '../../../util';
import { SessionWrapperModal } from '../../SessionWrapperModal'; import { SessionWrapperModal } from '../../SessionWrapperModal';
import { Flex } from '../../basic/Flex'; import { Flex } from '../../basic/Flex';
import { I18n } from '../../basic/I18n'; import { Localizer } from '../../basic/Localizer';
import { SessionButton, SessionButtonColor, SessionButtonType } from '../../basic/SessionButton'; import { SessionButton, SessionButtonColor, SessionButtonType } from '../../basic/SessionButton';
import { StyledModalDescriptionContainer } from '../shared/ModalDescriptionContainer'; import { StyledModalDescriptionContainer } from '../shared/ModalDescriptionContainer';
import { BlockOrUnblockModalState } from './BlockOrUnblockModalState'; import { BlockOrUnblockModalState } from './BlockOrUnblockModalState';
import type { I18nPropsObject } from '../../../types/Localizer'; import type { LocalizerComponentPropsObject } from '../../../types/Localizer';
type ModalState = NonNullable<BlockOrUnblockModalState>; type ModalState = NonNullable<BlockOrUnblockModalState>;
function getUnblockTokenAndArgs(names: Array<string>): I18nPropsObject { function getUnblockTokenAndArgs(names: Array<string>): LocalizerComponentPropsObject {
// multiple unblock is supported // multiple unblock is supported
switch (names.length) { switch (names.length) {
case 1: case 1:
@ -37,7 +37,7 @@ function getUnblockTokenAndArgs(names: Array<string>): I18nPropsObject {
function useBlockUnblockI18nDescriptionArgs({ function useBlockUnblockI18nDescriptionArgs({
action, action,
pubkeys, pubkeys,
}: Pick<ModalState, 'action' | 'pubkeys'>): I18nPropsObject { }: Pick<ModalState, 'action' | 'pubkeys'>): LocalizerComponentPropsObject {
const names = useConversationsNicknameRealNameOrShortenPubkey(pubkeys); const names = useConversationsNicknameRealNameOrShortenPubkey(pubkeys);
if (!pubkeys.length) { if (!pubkeys.length) {
throw new Error('useI18nDescriptionArgsForAction called with empty list of pubkeys'); throw new Error('useI18nDescriptionArgsForAction called with empty list of pubkeys');
@ -82,11 +82,11 @@ export const BlockOrUnblockDialog = ({ pubkeys, action, onConfirmed }: NonNullab
closeModal(); closeModal();
return null; return null;
} }
return ( return (
<SessionWrapperModal showExitIcon={true} title={localizedAction} onClose={closeModal}> <SessionWrapperModal showExitIcon={true} title={localizedAction} onClose={closeModal}>
<StyledModalDescriptionContainer> <StyledModalDescriptionContainer>
<I18n {...args} /> <Localizer {...args} />
</StyledModalDescriptionContainer> </StyledModalDescriptionContainer>
<Flex container={true} flexDirection="column" alignItems="center"> <Flex container={true} flexDirection="column" alignItems="center">
<Flex container={true}> <Flex container={true}>

@ -1,7 +1,7 @@
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import styled from 'styled-components'; import styled from 'styled-components';
import { updateTermsOfServicePrivacyModal } from '../../state/onboarding/ducks/modals'; import { updateTermsOfServicePrivacyModal } from '../../state/onboarding/ducks/modals';
import { I18n } from '../basic/I18n'; import { Localizer } from '../basic/Localizer';
const StyledTermsAndConditions = styled.div` const StyledTermsAndConditions = styled.div`
text-align: center; text-align: center;
@ -24,7 +24,7 @@ export const TermsAndConditions = () => {
onClick={() => dispatch(updateTermsOfServicePrivacyModal({ show: true }))} onClick={() => dispatch(updateTermsOfServicePrivacyModal({ show: true }))}
data-testid="open-url" data-testid="open-url"
> >
<I18n token="onboardingTosPrivacy" /> <Localizer token="onboardingTosPrivacy" />
</StyledTermsAndConditions> </StyledTermsAndConditions>
); );
}; };

@ -17,7 +17,7 @@ import { deleteDbLocally } from '../../../util/accountManager';
import { Flex } from '../../basic/Flex'; import { Flex } from '../../basic/Flex';
import { SessionButtonColor } from '../../basic/SessionButton'; import { SessionButtonColor } from '../../basic/SessionButton';
import { SessionIconButton } from '../../icon'; import { SessionIconButton } from '../../icon';
import { I18nProps, LocalizerToken } from '../../../types/Localizer'; import { LocalizerComponentProps, LocalizerToken } from '../../../types/Localizer';
/** Min height should match the onboarding step with the largest height this prevents the loading spinner from jumping around while still keeping things centered */ /** Min height should match the onboarding step with the largest height this prevents the loading spinner from jumping around while still keeping things centered */
const StyledBackButtonContainer = styled(Flex)` const StyledBackButtonContainer = styled(Flex)`
@ -38,7 +38,7 @@ export const BackButtonWithinContainer = ({
callback?: () => void; callback?: () => void;
onQuitVisible?: () => void; onQuitVisible?: () => void;
shouldQuitOnClick?: boolean; shouldQuitOnClick?: boolean;
quitI18nMessageArgs: I18nProps<LocalizerToken>; quitI18nMessageArgs: LocalizerComponentProps<LocalizerToken>;
}) => { }) => {
return ( return (
<StyledBackButtonContainer <StyledBackButtonContainer
@ -70,7 +70,7 @@ export const BackButton = ({
callback?: () => void; callback?: () => void;
onQuitVisible?: () => void; onQuitVisible?: () => void;
shouldQuitOnClick?: boolean; shouldQuitOnClick?: boolean;
quitI18nMessageArgs: I18nProps<LocalizerToken>; quitI18nMessageArgs: LocalizerComponentProps<LocalizerToken>;
}) => { }) => {
const step = useOnboardStep(); const step = useOnboardStep();
const restorationStep = useOnboardAccountRestorationStep(); const restorationStep = useOnboardAccountRestorationStep();

@ -18,7 +18,7 @@ import { prepareQRCodeForLightBox } from '../../../util/qrCodes';
import { getCurrentRecoveryPhrase } from '../../../util/storage'; import { getCurrentRecoveryPhrase } from '../../../util/storage';
import { QRCodeLogoProps, SessionQRCode } from '../../SessionQRCode'; import { QRCodeLogoProps, SessionQRCode } from '../../SessionQRCode';
import { AnimatedFlex } from '../../basic/Flex'; import { AnimatedFlex } from '../../basic/Flex';
import { I18n } from '../../basic/I18n'; import { Localizer } from '../../basic/Localizer';
import { SessionButtonColor } from '../../basic/SessionButton'; import { SessionButtonColor } from '../../basic/SessionButton';
import { SpacerMD, SpacerSM } from '../../basic/Text'; import { SpacerMD, SpacerSM } from '../../basic/Text';
import { CopyToClipboardIcon } from '../../buttons/CopyToClipboardButton'; import { CopyToClipboardIcon } from '../../buttons/CopyToClipboardButton';
@ -110,7 +110,7 @@ export const SettingsCategoryRecoveryPassword = () => {
iconSize: 18, iconSize: 18,
iconColor: 'var(--text-primary-color)', iconColor: 'var(--text-primary-color)',
}} }}
description={<I18n asTag="p" token="recoveryPasswordDescription" />} description={<Localizer token="recoveryPasswordDescription" />}
inline={false} inline={false}
> >
<SpacerMD /> <SpacerMD />

@ -1,6 +1,6 @@
import { getConversationController } from '../session/conversations'; import { getConversationController } from '../session/conversations';
import { UserUtils } from '../session/utils'; import { UserUtils } from '../session/utils';
import type { I18nPropsObject } from '../types/Localizer'; import type { LocalizerComponentPropsObject } from '../types/Localizer';
// to remove after merge with groups // to remove after merge with groups
function usAndXOthers(arr: Array<string>) { function usAndXOthers(arr: Array<string>) {
@ -12,7 +12,10 @@ function usAndXOthers(arr: Array<string>) {
return { us: false, others: arr }; return { us: false, others: arr };
} }
export function getKickedGroupUpdateStr(kicked: Array<string>, groupName: string): I18nPropsObject { export function getKickedGroupUpdateStr(
kicked: Array<string>,
groupName: string
): LocalizerComponentPropsObject {
const { others, us } = usAndXOthers(kicked); const { others, us } = usAndXOthers(kicked);
const othersNames = others.map( const othersNames = others.map(
getConversationController().getContactProfileNameOrShortenedPubKey getConversationController().getContactProfileNameOrShortenedPubKey
@ -56,7 +59,7 @@ export function getKickedGroupUpdateStr(kicked: Array<string>, groupName: string
export function getLeftGroupUpdateChangeStr( export function getLeftGroupUpdateChangeStr(
left: Array<string>, left: Array<string>,
_groupName: string _groupName: string
): I18nPropsObject { ): LocalizerComponentPropsObject {
const { others, us } = usAndXOthers(left); const { others, us } = usAndXOthers(left);
if (left.length !== 1) { if (left.length !== 1) {
@ -76,7 +79,7 @@ export function getLeftGroupUpdateChangeStr(
export function getJoinedGroupUpdateChangeStr( export function getJoinedGroupUpdateChangeStr(
joined: Array<string>, joined: Array<string>,
_groupName: string _groupName: string
): I18nPropsObject { ): LocalizerComponentPropsObject {
const { others, us } = usAndXOthers(joined); const { others, us } = usAndXOthers(joined);
const othersNames = others.map( const othersNames = others.map(
getConversationController().getContactProfileNameOrShortenedPubKey getConversationController().getContactProfileNameOrShortenedPubKey

@ -46,23 +46,23 @@ export type GetMessageArgs<T extends LocalizerToken> = T extends LocalizerToken
: [T, ArgsRecordExcludingDefaults<T>] : [T, ArgsRecordExcludingDefaults<T>]
: never; : never;
/** Basic props for all calls of the I18n component */ /** Basic props for all calls of the Localizer component */
type I18nBaseProps<T extends LocalizerToken> = { type LocalizerComponentBaseProps<T extends LocalizerToken> = {
token: T; token: T;
asTag?: ElementType; asTag?: ElementType;
className?: string; className?: string;
}; };
/** The props for the localization component */ /** The props for the localization component */
export type I18nProps<T extends LocalizerToken> = T extends LocalizerToken export type LocalizerComponentProps<T extends LocalizerToken> = T extends LocalizerToken
? DynamicArgs<Dictionary[T]> extends never ? DynamicArgs<Dictionary[T]> extends never
? I18nBaseProps<T> ? LocalizerComponentBaseProps<T>
: ArgsRecordExcludingDefaults<T> extends Record<string, never> : ArgsRecordExcludingDefaults<T> extends Record<string, never>
? I18nBaseProps<T> ? LocalizerComponentBaseProps<T>
: I18nBaseProps<T> & { args: ArgsRecordExcludingDefaults<T> } : LocalizerComponentBaseProps<T> & { args: ArgsRecordExcludingDefaults<T> }
: never; : never;
export type I18nPropsObject = I18nProps<LocalizerToken>; export type LocalizerComponentPropsObject = LocalizerComponentProps<LocalizerToken>;
export type I18nMethods = { export type I18nMethods = {
/** @see {@link window.i18n.stripped} */ /** @see {@link window.i18n.stripped} */

@ -1,6 +1,6 @@
/** NOTE: Because of docstring limitations changes MUST be manually synced between {@link setupI18n.stripped } and {@link window.i18n.stripped } */ /** NOTE: Because of docstring limitations changes MUST be manually synced between {@link setupI18n.stripped } and {@link window.i18n.stripped } */
import { deSanitizeHtmlTags, sanitizeArgs } from '../../../components/basic/I18n'; import { deSanitizeHtmlTags, sanitizeArgs } from '../../../components/basic/Localizer';
import { GetMessageArgs, LocalizerDictionary, LocalizerToken } from '../../../types/Localizer'; import { GetMessageArgs, LocalizerDictionary, LocalizerToken } from '../../../types/Localizer';
import { getMessage } from './getMessage'; import { getMessage } from './getMessage';

Loading…
Cancel
Save