Make ICU types stricter for inline JSX

This commit is contained in:
Jamie Kyle 2024-05-15 14:48:02 -07:00 committed by GitHub
parent 9e7a6ea8bc
commit 6655bfc576
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
52 changed files with 220 additions and 200 deletions

View file

@ -5775,7 +5775,7 @@
"description": "Title for the auto convert emoji setting" "description": "Title for the auto convert emoji setting"
}, },
"icu:Preferences__auto-convert-emoji--description": { "icu:Preferences__auto-convert-emoji--description": {
"messageformat": "For example, :-) will be converted to 🙂", "messageformat": "For example, :-) will be converted to <emojify>🙂</emojify>",
"description": "Description for the auto convert emoji setting" "description": "Description for the auto convert emoji setting"
}, },
"icu:Preferences--advanced": { "icu:Preferences--advanced": {

View file

@ -6,7 +6,7 @@ import type {
ConversationType, ConversationType,
ShowConversationType, ShowConversationType,
} from '../state/ducks/conversations'; } from '../state/ducks/conversations';
import { Intl } from './Intl'; import { I18n } from './I18n';
import type { LocalizerType, ThemeType } from '../types/Util'; import type { LocalizerType, ThemeType } from '../types/Util';
import { Modal } from './Modal'; import { Modal } from './Modal';
import { ConversationListItem } from './conversationList/ConversationListItem'; import { ConversationListItem } from './conversationList/ConversationListItem';
@ -51,7 +51,7 @@ export function AnnouncementsOnlyGroupBanner({
</Modal> </Modal>
)} )}
<div className="AnnouncementsOnlyGroupBanner__banner"> <div className="AnnouncementsOnlyGroupBanner__banner">
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:AnnouncementsOnlyGroupBanner--announcements-only" id="icu:AnnouncementsOnlyGroupBanner--announcements-only"
components={{ components={{

View file

@ -5,7 +5,7 @@ import React, { useRef, useEffect } from 'react';
import type { LocalizerType } from '../types/Util'; import type { LocalizerType } from '../types/Util';
import { AvatarColors } from '../types/Colors'; import { AvatarColors } from '../types/Colors';
import { Avatar, AvatarSize } from './Avatar'; import { Avatar, AvatarSize } from './Avatar';
import { Intl } from './Intl'; import { I18n } from './I18n';
import { ContactName } from './conversation/ContactName'; import { ContactName } from './conversation/ContactName';
import type { ConversationType } from '../state/ducks/conversations'; import type { ConversationType } from '../state/ducks/conversations';
@ -61,7 +61,7 @@ export function CallNeedPermissionScreen({
/> />
<p className="module-call-need-permission-screen__text"> <p className="module-call-need-permission-screen__text">
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:callNeedPermission" id="icu:callNeedPermission"
components={{ components={{

View file

@ -36,7 +36,7 @@ import { refMerger } from '../util/refMerger';
import { drop } from '../util/drop'; import { drop } from '../util/drop';
import { strictAssert } from '../util/assert'; import { strictAssert } from '../util/assert';
import { UserText } from './UserText'; import { UserText } from './UserText';
import { Intl } from './Intl'; import { I18n } from './I18n';
import { NavSidebarSearchHeader } from './NavSidebar'; import { NavSidebarSearchHeader } from './NavSidebar';
import { SizeObserver } from '../hooks/useSizeObserver'; import { SizeObserver } from '../hooks/useSizeObserver';
import { formatCallHistoryGroup } from '../util/callDisposition'; import { formatCallHistoryGroup } from '../util/callDisposition';
@ -535,7 +535,7 @@ export function CallsList({
{currentQuery === '' ? ( {currentQuery === '' ? (
i18n('icu:CallsList__EmptyState--noQuery') i18n('icu:CallsList__EmptyState--noQuery')
) : ( ) : (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:CallsList__EmptyState--hasQuery" id="icu:CallsList__EmptyState--hasQuery"
components={{ components={{

View file

@ -15,7 +15,7 @@ import { ListTile } from './ListTile';
import { strictAssert } from '../util/assert'; import { strictAssert } from '../util/assert';
import { UserText } from './UserText'; import { UserText } from './UserText';
import { Avatar, AvatarSize } from './Avatar'; import { Avatar, AvatarSize } from './Avatar';
import { Intl } from './Intl'; import { I18n } from './I18n';
import { SizeObserver } from '../hooks/useSizeObserver'; import { SizeObserver } from '../hooks/useSizeObserver';
import { CallType } from '../types/CallDisposition'; import { CallType } from '../types/CallDisposition';
@ -244,7 +244,7 @@ export function CallsNewCall({
{query === '' ? ( {query === '' ? (
i18n('icu:CallsNewCall__EmptyState--noQuery') i18n('icu:CallsNewCall__EmptyState--noQuery')
) : ( ) : (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:CallsNewCall__EmptyState--hasQuery" id="icu:CallsNewCall__EmptyState--hasQuery"
components={{ components={{

View file

@ -1,11 +1,11 @@
// Copyright 2021 Signal Messenger, LLC // Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import type { ReactNode } from 'react';
import React, { forwardRef, useMemo } from 'react'; import React, { forwardRef, useMemo } from 'react';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import { getClassNamesFor } from '../util/getClassNamesFor'; import { getClassNamesFor } from '../util/getClassNamesFor';
import { Emojify } from './conversation/Emojify';
export type PropsType = { export type PropsType = {
checked?: boolean; checked?: boolean;
@ -15,7 +15,7 @@ export type PropsType = {
labelNode: JSX.Element; labelNode: JSX.Element;
checked?: boolean; checked?: boolean;
}) => JSX.Element; }) => JSX.Element;
description?: string; description?: ReactNode;
disabled?: boolean; disabled?: boolean;
isRadio?: boolean; isRadio?: boolean;
label: string; label: string;
@ -62,9 +62,7 @@ export const Checkbox = forwardRef(function CheckboxInner(
<div> <div>
<label htmlFor={id}> <label htmlFor={id}>
<div>{label}</div> <div>{label}</div>
<div className={getClassName('__description')}> <div className={getClassName('__description')}>{description}</div>
<Emojify text={description ?? ''} />
</div>
</label> </label>
</div> </div>
); );

View file

@ -7,7 +7,7 @@ import { isBeta } from '../util/version';
import { DialogType } from '../types/Dialogs'; import { DialogType } from '../types/Dialogs';
import type { LocalizerType } from '../types/Util'; import type { LocalizerType } from '../types/Util';
import { PRODUCTION_DOWNLOAD_URL, BETA_DOWNLOAD_URL } from '../types/support'; import { PRODUCTION_DOWNLOAD_URL, BETA_DOWNLOAD_URL } from '../types/support';
import { Intl } from './Intl'; import { I18n } from './I18n';
import { LeftPaneDialog } from './LeftPaneDialog'; import { LeftPaneDialog } from './LeftPaneDialog';
import type { WidthBreakpoint } from './_util'; import type { WidthBreakpoint } from './_util';
import { formatFileSize } from '../util/formatFileSize'; import { formatFileSize } from '../util/formatFileSize';
@ -48,7 +48,7 @@ export function DialogUpdate({
title={i18n('icu:cannotUpdate')} title={i18n('icu:cannotUpdate')}
> >
<span> <span>
<Intl <I18n
components={{ components={{
retry: ( retry: (
<button <button
@ -100,7 +100,7 @@ export function DialogUpdate({
title={i18n('icu:cannotUpdate')} title={i18n('icu:cannotUpdate')}
> >
<span> <span>
<Intl <I18n
components={{ components={{
url: ( url: (
<a <a
@ -142,7 +142,7 @@ export function DialogUpdate({
type="warning" type="warning"
> >
<span> <span>
<Intl <I18n
components={{ components={{
app: <strong key="app">Signal.app</strong>, app: <strong key="app">Signal.app</strong>,
folder: <strong key="folder">/Applications</strong>, folder: <strong key="folder">/Applications</strong>,

View file

@ -22,7 +22,7 @@ import {
} from './CallingAudioIndicator'; } from './CallingAudioIndicator';
import { Avatar, AvatarSize } from './Avatar'; import { Avatar, AvatarSize } from './Avatar';
import { ConfirmationDialog } from './ConfirmationDialog'; import { ConfirmationDialog } from './ConfirmationDialog';
import { Intl } from './Intl'; import { I18n } from './I18n';
import { ContactName } from './conversation/ContactName'; import { ContactName } from './conversation/ContactName';
import { useIntersectionObserver } from '../hooks/useIntersectionObserver'; import { useIntersectionObserver } from '../hooks/useIntersectionObserver';
import { MAX_FRAME_HEIGHT, MAX_FRAME_WIDTH } from '../calling/constants'; import { MAX_FRAME_HEIGHT, MAX_FRAME_WIDTH } from '../calling/constants';
@ -408,7 +408,7 @@ export const GroupCallRemoteParticipant: React.FC<PropsType> = React.memo(
if (isBlocked) { if (isBlocked) {
setErrorDialogTitle( setErrorDialogTitle(
<div className="module-ongoing-call__group-call-remote-participant__more-info-modal-title"> <div className="module-ongoing-call__group-call-remote-participant__more-info-modal-title">
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:calling__you-have-blocked" id="icu:calling__you-have-blocked"
components={{ components={{
@ -421,7 +421,7 @@ export const GroupCallRemoteParticipant: React.FC<PropsType> = React.memo(
} else if (showMissingMediaKeys) { } else if (showMissingMediaKeys) {
setErrorDialogTitle( setErrorDialogTitle(
<div className="module-ongoing-call__group-call-remote-participant__more-info-modal-title"> <div className="module-ongoing-call__group-call-remote-participant__more-info-modal-title">
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:calling__missing-media-keys" id="icu:calling__missing-media-keys"
components={{ components={{

View file

@ -4,16 +4,16 @@
import * as React from 'react'; import * as React from 'react';
import type { ComponentMeta } from '../storybook/types'; import type { ComponentMeta } from '../storybook/types';
import type { Props } from './Intl'; import type { Props } from './I18n';
import { Intl } from './Intl'; import { I18n } from './I18n';
import { setupI18n } from '../util/setupI18n'; import { setupI18n } from '../util/setupI18n';
import enMessages from '../../_locales/en/messages.json'; import enMessages from '../../_locales/en/messages.json';
const i18n = setupI18n('en', enMessages); const i18n = setupI18n('en', enMessages);
export default { export default {
title: 'Components/Intl', title: 'Components/I18n',
component: Intl, component: I18n,
args: { args: {
i18n, i18n,
id: 'icu:ok', id: 'icu:ok',
@ -24,14 +24,14 @@ export default {
export function NoReplacements( export function NoReplacements(
args: Props<'icu:deleteAndRestart'> args: Props<'icu:deleteAndRestart'>
): JSX.Element { ): JSX.Element {
return <Intl {...args} id="icu:deleteAndRestart" />; return <I18n {...args} id="icu:deleteAndRestart" />;
} }
export function SingleStringReplacement( export function SingleStringReplacement(
args: Props<'icu:leftTheGroup'> args: Props<'icu:leftTheGroup'>
): JSX.Element { ): JSX.Element {
return ( return (
<Intl {...args} id="icu:leftTheGroup" components={{ name: 'Theodora' }} /> <I18n {...args} id="icu:leftTheGroup" components={{ name: 'Theodora' }} />
); );
} }
@ -39,7 +39,7 @@ export function SingleTagReplacement(
args: Props<'icu:leftTheGroup'> args: Props<'icu:leftTheGroup'>
): JSX.Element { ): JSX.Element {
return ( return (
<Intl <I18n
{...args} {...args}
id="icu:leftTheGroup" id="icu:leftTheGroup"
components={{ components={{
@ -57,7 +57,7 @@ export function MultipleStringReplacement(
args: Props<'icu:changedRightAfterVerify'> args: Props<'icu:changedRightAfterVerify'>
): JSX.Element { ): JSX.Element {
return ( return (
<Intl <I18n
{...args} {...args}
id="icu:changedRightAfterVerify" id="icu:changedRightAfterVerify"
components={{ name1: 'Fred', name2: 'The Fredster' }} components={{ name1: 'Fred', name2: 'The Fredster' }}
@ -69,7 +69,7 @@ export function MultipleTagReplacement(
args: Props<'icu:changedRightAfterVerify'> args: Props<'icu:changedRightAfterVerify'>
): JSX.Element { ): JSX.Element {
return ( return (
<Intl <I18n
{...args} {...args}
id="icu:changedRightAfterVerify" id="icu:changedRightAfterVerify"
components={{ name1: <b>Fred</b>, name2: <b>The Fredster</b> }} components={{ name1: <b>Fred</b>, name2: <b>The Fredster</b> }}
@ -81,7 +81,7 @@ export function Emoji(
args: Props<'icu:Message__reaction-emoji-label--you'> args: Props<'icu:Message__reaction-emoji-label--you'>
): JSX.Element { ): JSX.Element {
return ( return (
<Intl <I18n
{...args} {...args}
id="icu:Message__reaction-emoji-label--you" id="icu:Message__reaction-emoji-label--you"
components={{ emoji: '😛' }} components={{ emoji: '😛' }}

View file

@ -21,14 +21,14 @@ export type Props<Key extends keyof ICUJSXMessageParamsByKeyType> = {
components: ICUJSXMessageParamsByKeyType[Key]; components: ICUJSXMessageParamsByKeyType[Key];
}); });
export function Intl<Key extends keyof ICUJSXMessageParamsByKeyType>({ export function I18n<Key extends keyof ICUJSXMessageParamsByKeyType>({
components, components,
id, id,
// Indirection for linter/migration tooling // Indirection for linter/migration tooling
i18n: localizer, i18n: localizer,
}: Props<Key>): JSX.Element | null { }: Props<Key>): JSX.Element | null {
if (!id) { if (!id) {
log.error('Error: Intl id prop not provided'); log.error('Error: <I18n> id prop not provided');
return null; return null;
} }

View file

@ -5,7 +5,7 @@ import type { ReactChild } from 'react';
import React, { useCallback, useEffect, useRef } from 'react'; import React, { useCallback, useEffect, useRef } from 'react';
import { Avatar, AvatarSize } from './Avatar'; import { Avatar, AvatarSize } from './Avatar';
import { Tooltip } from './Tooltip'; import { Tooltip } from './Tooltip';
import { Intl } from './Intl'; import { I18n } from './I18n';
import { Theme } from '../util/theme'; import { Theme } from '../util/theme';
import { getParticipantName } from '../util/callingGetParticipantName'; import { getParticipantName } from '../util/callingGetParticipantName';
import { ContactName } from './conversation/ContactName'; import { ContactName } from './conversation/ContactName';
@ -124,7 +124,7 @@ function GroupCallMessage({
switch (otherMembersRung.length) { switch (otherMembersRung.length) {
case 0: case 0:
return ( return (
<Intl <I18n
id="icu:incomingGroupCall__ringing-you" id="icu:incomingGroupCall__ringing-you"
i18n={i18n} i18n={i18n}
components={{ ringer: ringerNode }} components={{ ringer: ringerNode }}
@ -132,7 +132,7 @@ function GroupCallMessage({
); );
case 1: case 1:
return ( return (
<Intl <I18n
id="icu:incomingGroupCall__ringing-1-other" id="icu:incomingGroupCall__ringing-1-other"
i18n={i18n} i18n={i18n}
components={{ components={{
@ -143,7 +143,7 @@ function GroupCallMessage({
); );
case 2: case 2:
return ( return (
<Intl <I18n
id="icu:incomingGroupCall__ringing-2-others" id="icu:incomingGroupCall__ringing-2-others"
i18n={i18n} i18n={i18n}
components={{ components={{
@ -155,7 +155,7 @@ function GroupCallMessage({
); );
case 3: case 3:
return ( return (
<Intl <I18n
id="icu:incomingGroupCall__ringing-3-others" id="icu:incomingGroupCall__ringing-3-others"
i18n={i18n} i18n={i18n}
components={{ components={{
@ -167,7 +167,7 @@ function GroupCallMessage({
); );
default: default:
return ( return (
<Intl <I18n
id="icu:incomingGroupCall__ringing-many" id="icu:incomingGroupCall__ringing-many"
i18n={i18n} i18n={i18n}
components={{ components={{

View file

@ -7,7 +7,7 @@ import React from 'react';
import type { LocalizerType, ThemeType } from '../types/Util'; import type { LocalizerType, ThemeType } from '../types/Util';
import type { ConversationType } from '../state/ducks/conversations'; import type { ConversationType } from '../state/ducks/conversations';
import type { PreferredBadgeSelectorType } from '../state/selectors/badges'; import type { PreferredBadgeSelectorType } from '../state/selectors/badges';
import { Intl } from './Intl'; import { I18n } from './I18n';
import { ContactName } from './conversation/ContactName'; import { ContactName } from './conversation/ContactName';
import { GroupDialog } from './GroupDialog'; import { GroupDialog } from './GroupDialog';
import { openLinkInWebBrowser } from '../util/openLinkInWebBrowser'; import { openLinkInWebBrowser } from '../util/openLinkInWebBrowser';
@ -34,7 +34,7 @@ export function NewlyCreatedGroupInvitedContactsDialog({
body = ( body = (
<> <>
<GroupDialog.Paragraph> <GroupDialog.Paragraph>
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:NewlyCreatedGroupInvitedContactsDialog--body--user-paragraph--one" id="icu:NewlyCreatedGroupInvitedContactsDialog--body--user-paragraph--one"
components={{ name: <ContactName title={contact.title} /> }} components={{ name: <ContactName title={contact.title} /> }}

View file

@ -66,6 +66,7 @@ import { Modal } from './Modal';
import { SearchInput } from './SearchInput'; import { SearchInput } from './SearchInput';
import { removeDiacritics } from '../util/removeDiacritics'; import { removeDiacritics } from '../util/removeDiacritics';
import { assertDev } from '../util/assert'; import { assertDev } from '../util/assert';
import { I18n } from './I18n';
type CheckboxChangeHandlerType = (value: boolean) => unknown; type CheckboxChangeHandlerType = (value: boolean) => unknown;
type SelectChangeHandlerType<T = string | number> = (value: T) => unknown; type SelectChangeHandlerType<T = string | number> = (value: T) => unknown;
@ -865,9 +866,12 @@ export function Preferences({
/> />
<Checkbox <Checkbox
checked={hasAutoConvertEmoji} checked={hasAutoConvertEmoji}
description={i18n( description={
'icu:Preferences__auto-convert-emoji--description' <I18n
)} i18n={i18n}
id="icu:Preferences__auto-convert-emoji--description"
/>
}
label={i18n('icu:Preferences__auto-convert-emoji--title')} label={i18n('icu:Preferences__auto-convert-emoji--title')}
moduleClassName="Preferences__checkbox" moduleClassName="Preferences__checkbox"
name="autoConvertEmoji" name="autoConvertEmoji"

View file

@ -5,7 +5,7 @@ import React from 'react';
import { Button, ButtonVariant } from './Button'; import { Button, ButtonVariant } from './Button';
import { Modal } from './Modal'; import { Modal } from './Modal';
import { Intl } from './Intl'; import { I18n } from './I18n';
import { openLinkInWebBrowser } from '../util/openLinkInWebBrowser'; import { openLinkInWebBrowser } from '../util/openLinkInWebBrowser';
import type { LocalizerType } from '../types/Util'; import type { LocalizerType } from '../types/Util';
import { SAFETY_NUMBER_URL } from '../types/support'; import { SAFETY_NUMBER_URL } from '../types/support';
@ -26,15 +26,15 @@ export function SafetyNumberNotReady({
return ( return (
<div className="module-SafetyNumberNotReady"> <div className="module-SafetyNumberNotReady">
<div> <div>
<Intl i18n={i18n} id="icu:SafetyNumberNotReady__body" /> <I18n i18n={i18n} id="icu:SafetyNumberNotReady__body" />
</div> </div>
<Modal.ButtonFooter> <Modal.ButtonFooter>
<Button onClick={onLearnMore} variant={ButtonVariant.Secondary}> <Button onClick={onLearnMore} variant={ButtonVariant.Secondary}>
<Intl i18n={i18n} id="icu:SafetyNumberNotReady__learn-more" /> <I18n i18n={i18n} id="icu:SafetyNumberNotReady__learn-more" />
</Button> </Button>
<Button onClick={onClose} variant={ButtonVariant.Secondary}> <Button onClick={onClose} variant={ButtonVariant.Secondary}>
<Intl i18n={i18n} id="icu:ok" /> <I18n i18n={i18n} id="icu:ok" />
</Button> </Button>
</Modal.ButtonFooter> </Modal.ButtonFooter>
</div> </div>

View file

@ -6,7 +6,7 @@ import React from 'react';
import { Button, ButtonVariant } from './Button'; import { Button, ButtonVariant } from './Button';
import { QrCode } from './QrCode'; import { QrCode } from './QrCode';
import type { ConversationType } from '../state/ducks/conversations'; import type { ConversationType } from '../state/ducks/conversations';
import { Intl } from './Intl'; import { I18n } from './I18n';
import { Emojify } from './conversation/Emojify'; import { Emojify } from './conversation/Emojify';
import type { LocalizerType } from '../types/Util'; import type { LocalizerType } from '../types/Util';
import type { SafetyNumberType } from '../types/safetyNumber'; import type { SafetyNumberType } from '../types/safetyNumber';
@ -95,14 +95,14 @@ export function SafetyNumberViewer({
{safetyNumberCard} {safetyNumberCard}
<div className="module-SafetyNumberViewer__help"> <div className="module-SafetyNumberViewer__help">
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:SafetyNumberViewer__hint" id="icu:SafetyNumberViewer__hint"
components={{ name: boldName }} components={{ name: boldName }}
/> />
<br /> <br />
<a href={SAFETY_NUMBER_URL} rel="noreferrer" target="_blank"> <a href={SAFETY_NUMBER_URL} rel="noreferrer" target="_blank">
<Intl i18n={i18n} id="icu:SafetyNumberViewer__learn_more" /> <I18n i18n={i18n} id="icu:SafetyNumberViewer__learn_more" />
</a> </a>
</div> </div>

View file

@ -4,7 +4,7 @@
import React from 'react'; import React from 'react';
import { take } from 'lodash'; import { take } from 'lodash';
import { Intl } from './Intl'; import { I18n } from './I18n';
import type { LocalizerType } from '../types/Util'; import type { LocalizerType } from '../types/Util';
import { UserText } from './UserText'; import { UserText } from './UserText';
@ -30,7 +30,7 @@ export function SharedGroupNames({
if (sharedGroupNames.length >= 5) { if (sharedGroupNames.length >= 5) {
const remainingCount = sharedGroupNames.length - 3; const remainingCount = sharedGroupNames.length - 3;
return ( return (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:member-of-more-than-3-groups--multiple-more" id="icu:member-of-more-than-3-groups--multiple-more"
components={{ components={{
@ -44,7 +44,7 @@ export function SharedGroupNames({
} }
if (sharedGroupNames.length === 4) { if (sharedGroupNames.length === 4) {
return ( return (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:member-of-more-than-3-groups--one-more" id="icu:member-of-more-than-3-groups--one-more"
components={{ components={{
@ -57,7 +57,7 @@ export function SharedGroupNames({
} }
if (firstThreeGroups.length === 3) { if (firstThreeGroups.length === 3) {
return ( return (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:member-of-3-groups" id="icu:member-of-3-groups"
components={{ components={{
@ -70,7 +70,7 @@ export function SharedGroupNames({
} }
if (firstThreeGroups.length >= 2) { if (firstThreeGroups.length >= 2) {
return ( return (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:member-of-2-groups" id="icu:member-of-2-groups"
components={{ components={{
@ -82,7 +82,7 @@ export function SharedGroupNames({
} }
if (firstThreeGroups.length >= 1) { if (firstThreeGroups.length >= 1) {
return ( return (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:member-of-1-group" id="icu:member-of-1-group"
components={{ components={{

View file

@ -4,7 +4,7 @@
import React from 'react'; import React from 'react';
import type { LocalizerType } from '../types/Util'; import type { LocalizerType } from '../types/Util';
import { Intl } from './Intl'; import { I18n } from './I18n';
import { Modal } from './Modal'; import { Modal } from './Modal';
export type PropsType = Readonly<{ export type PropsType = Readonly<{
@ -27,7 +27,7 @@ export function SignalConnectionsModal({
<i className="SignalConnectionsModal__icon" /> <i className="SignalConnectionsModal__icon" />
<div className="SignalConnectionsModal__description"> <div className="SignalConnectionsModal__description">
<Intl <I18n
components={{ components={{
connections: ( connections: (
<strong>{i18n('icu:SignalConnectionsModal__title')}</strong> <strong>{i18n('icu:SignalConnectionsModal__title')}</strong>

View file

@ -22,7 +22,7 @@ import { ContactPills } from './ContactPills';
import { ContactPill } from './ContactPill'; import { ContactPill } from './ContactPill';
import { ConversationList, RowType } from './ConversationList'; import { ConversationList, RowType } from './ConversationList';
import { Input } from './Input'; import { Input } from './Input';
import { Intl } from './Intl'; import { I18n } from './I18n';
import { MY_STORY_ID, getStoryDistributionListName } from '../types/Stories'; import { MY_STORY_ID, getStoryDistributionListName } from '../types/Stories';
import { PagedModal, ModalPage } from './Modal'; import { PagedModal, ModalPage } from './Modal';
import { SearchInput } from './SearchInput'; import { SearchInput } from './SearchInput';
@ -836,13 +836,13 @@ export function EditMyStoryPrivacy({
const disclaimerElement = ( const disclaimerElement = (
<div className="StoriesSettingsModal__disclaimer"> <div className="StoriesSettingsModal__disclaimer">
{kind === 'mine' ? ( {kind === 'mine' ? (
<Intl <I18n
components={{ learnMoreLink }} components={{ learnMoreLink }}
i18n={i18n} i18n={i18n}
id="icu:StoriesSettings__mine__disclaimer--link" id="icu:StoriesSettings__mine__disclaimer--link"
/> />
) : ( ) : (
<Intl <I18n
components={{ learnMoreLink }} components={{ learnMoreLink }}
i18n={i18n} i18n={i18n}
id="icu:SendStoryModal__privacy-disclaimer--link" id="icu:SendStoryModal__privacy-disclaimer--link"

View file

@ -8,7 +8,7 @@ import type { StorySendStateType, StoryViewType } from '../types/Stories';
import { Avatar, AvatarSize } from './Avatar'; import { Avatar, AvatarSize } from './Avatar';
import { ContactName } from './conversation/ContactName'; import { ContactName } from './conversation/ContactName';
import { ContextMenu } from './ContextMenu'; import { ContextMenu } from './ContextMenu';
import { Intl } from './Intl'; import { I18n } from './I18n';
import { Modal } from './Modal'; import { Modal } from './Modal';
import { SendStatus } from '../messages/MessageSendState'; import { SendStatus } from '../messages/MessageSendState';
import { Theme } from '../util/theme'; import { Theme } from '../util/theme';
@ -246,7 +246,7 @@ export function StoryDetailsModal({
theme={Theme.Dark} theme={Theme.Dark}
> >
<div> <div>
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:StoryDetailsModal__sent-time" id="icu:StoryDetailsModal__sent-time"
components={{ components={{
@ -263,7 +263,7 @@ export function StoryDetailsModal({
</div> </div>
{attachment && ( {attachment && (
<div> <div>
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:StoryDetailsModal__file-size" id="icu:StoryDetailsModal__file-size"
components={{ components={{
@ -278,7 +278,7 @@ export function StoryDetailsModal({
)} )}
{timeRemaining && timeRemaining > 0 && ( {timeRemaining && timeRemaining > 0 && (
<div> <div>
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:StoryDetailsModal__disappears-in" id="icu:StoryDetailsModal__disappears-in"
components={{ components={{

View file

@ -30,7 +30,7 @@ import { AnimatedEmojiGalore } from './AnimatedEmojiGalore';
import { Avatar, AvatarSize } from './Avatar'; import { Avatar, AvatarSize } from './Avatar';
import { ConfirmationDialog } from './ConfirmationDialog'; import { ConfirmationDialog } from './ConfirmationDialog';
import { ContextMenu } from './ContextMenu'; import { ContextMenu } from './ContextMenu';
import { Intl } from './Intl'; import { I18n } from './I18n';
import { MessageTimestamp } from './conversation/MessageTimestamp'; import { MessageTimestamp } from './conversation/MessageTimestamp';
import { SendStatus } from '../messages/MessageSendState'; import { SendStatus } from '../messages/MessageSendState';
import { Spinner } from './Spinner'; import { Spinner } from './Spinner';
@ -946,7 +946,7 @@ export function StoryViewer({
<>{i18n('icu:StoryViewer__views-off')}</> <>{i18n('icu:StoryViewer__views-off')}</>
)} )}
{isSent && hasViewReceiptSetting && ( {isSent && hasViewReceiptSetting && (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:MyStories__views--strong" id="icu:MyStories__views--strong"
components={{ components={{
@ -957,7 +957,7 @@ export function StoryViewer({
)} )}
{(isSent || viewCount > 0) && replyCount > 0 && ' '} {(isSent || viewCount > 0) && replyCount > 0 && ' '}
{replyCount > 0 && ( {replyCount > 0 && (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:MyStories__replies" id="icu:MyStories__replies"
components={{ replyCount, strong: renderStrong }} components={{ replyCount, strong: renderStrong }}

View file

@ -8,7 +8,7 @@ import type { LocalizerType } from '../types/Util';
import { UNSUPPORTED_OS_URL } from '../types/support'; import { UNSUPPORTED_OS_URL } from '../types/support';
import { missingCaseError } from '../util/missingCaseError'; import { missingCaseError } from '../util/missingCaseError';
import type { WidthBreakpoint } from './_util'; import type { WidthBreakpoint } from './_util';
import { Intl } from './Intl'; import { I18n } from './I18n';
import { LeftPaneDialog } from './LeftPaneDialog'; import { LeftPaneDialog } from './LeftPaneDialog';
@ -41,7 +41,7 @@ export function UnsupportedOSDialog({
let body: JSX.Element; let body: JSX.Element;
if (type === 'error') { if (type === 'error') {
body = ( body = (
<Intl <I18n
id="icu:UnsupportedOSErrorDialog__body" id="icu:UnsupportedOSErrorDialog__body"
i18n={i18n} i18n={i18n}
components={{ components={{
@ -52,7 +52,7 @@ export function UnsupportedOSDialog({
); );
} else if (type === 'warning') { } else if (type === 'warning') {
body = ( body = (
<Intl <I18n
id="icu:UnsupportedOSWarningDialog__body" id="icu:UnsupportedOSWarningDialog__body"
i18n={i18n} i18n={i18n}
components={{ components={{

View file

@ -3,7 +3,7 @@
import React from 'react'; import React from 'react';
import { Intl } from './Intl'; import { I18n } from './I18n';
import type { LocalizerType } from '../types/Util'; import type { LocalizerType } from '../types/Util';
@ -16,7 +16,7 @@ export function WhatsNewLink(props: PropsType): JSX.Element {
const { i18n, showWhatsNewModal } = props; const { i18n, showWhatsNewModal } = props;
return ( return (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:whatsNew" id="icu:whatsNew"
components={{ components={{

View file

@ -6,7 +6,7 @@ import React from 'react';
import moment from 'moment'; import moment from 'moment';
import { Modal } from './Modal'; import { Modal } from './Modal';
import { Intl } from './Intl'; import { I18n } from './I18n';
import type { LocalizerType } from '../types/Util'; import type { LocalizerType } from '../types/Util';
export type PropsType = { export type PropsType = {
@ -42,7 +42,7 @@ export function WhatsNewModal({
const releaseNotes: ReleaseNotesType = { const releaseNotes: ReleaseNotesType = {
date: new Date(window.getBuildCreation?.() || Date.now()), date: new Date(window.getBuildCreation?.() || Date.now()),
version: window.getVersion?.(), version: window.getVersion?.(),
features: [<Intl i18n={i18n} id="icu:WhatsNew__bugfixes--2" />], features: [<I18n i18n={i18n} id="icu:WhatsNew__bugfixes--2" />],
}; };
if (releaseNotes.features.length === 1 && !releaseNotes.header) { if (releaseNotes.features.length === 1 && !releaseNotes.header) {

View file

@ -11,7 +11,7 @@ import { Modal } from '../Modal';
import { UserText } from '../UserText'; import { UserText } from '../UserText';
import { SharedGroupNames } from '../SharedGroupNames'; import { SharedGroupNames } from '../SharedGroupNames';
import { About } from './About'; import { About } from './About';
import { Intl } from '../Intl'; import { I18n } from '../I18n';
import { import {
areNicknamesEnabled, areNicknamesEnabled,
canHaveNicknameAndNote, canHaveNicknameAndNote,
@ -154,7 +154,7 @@ export function AboutContactModal({
(conversation.nicknameGivenName || conversation.nicknameFamilyName) && (conversation.nicknameGivenName || conversation.nicknameFamilyName) &&
conversation.titleNoNickname ? ( conversation.titleNoNickname ? (
<span> <span>
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:AboutContactModal__TitleAndTitleWithoutNickname" id="icu:AboutContactModal__TitleAndTitleWithoutNickname"
components={{ components={{
@ -164,7 +164,7 @@ export function AboutContactModal({
className="AboutContactModal__TitleWithoutNickname__Tooltip" className="AboutContactModal__TitleWithoutNickname__Tooltip"
direction={TooltipPlacement.Top} direction={TooltipPlacement.Top}
content={ content={
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:AboutContactModal__TitleWithoutNickname__Tooltip" id="icu:AboutContactModal__TitleWithoutNickname__Tooltip"
components={{ components={{

View file

@ -5,7 +5,7 @@ import React from 'react';
import type { ConversationType } from '../../state/ducks/conversations'; import type { ConversationType } from '../../state/ducks/conversations';
import type { LocalizerType } from '../../types/Util'; import type { LocalizerType } from '../../types/Util';
import { Intl } from '../Intl'; import { I18n } from '../I18n';
import { SystemMessage } from './SystemMessage'; import { SystemMessage } from './SystemMessage';
import { MessageTimestamp } from './MessageTimestamp'; import { MessageTimestamp } from './MessageTimestamp';
@ -29,7 +29,7 @@ export function ChangeNumberNotification(props: Props): JSX.Element {
<SystemMessage <SystemMessage
contents={ contents={
<> <>
<Intl <I18n
id="icu:ChangeNumber--notification" id="icu:ChangeNumber--notification"
components={{ components={{
sender: ( sender: (

View file

@ -13,7 +13,7 @@ import { Avatar, AvatarSize } from '../Avatar';
import { ContactName } from './ContactName'; import { ContactName } from './ContactName';
import { SharedGroupNames } from '../SharedGroupNames'; import { SharedGroupNames } from '../SharedGroupNames';
import { UserText } from '../UserText'; import { UserText } from '../UserText';
import { Intl } from '../Intl'; import { I18n } from '../I18n';
export type PropsType = Readonly<{ export type PropsType = Readonly<{
children?: ReactNode; children?: ReactNode;
@ -58,7 +58,7 @@ export function ContactSpoofingReviewDialogPerson({
<div className="module-ContactSpoofingReviewDialogPerson__info__property"> <div className="module-ContactSpoofingReviewDialogPerson__info__property">
<i className="module-ContactSpoofingReviewDialogPerson__info__property__icon module-ContactSpoofingReviewDialogPerson__info__property__icon--person" /> <i className="module-ContactSpoofingReviewDialogPerson__info__property__icon module-ContactSpoofingReviewDialogPerson__info__property__icon--person" />
<div> <div>
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:ContactSpoofingReviewDialog__group__name-change-info" id="icu:ContactSpoofingReviewDialog__group__name-change-info"
components={{ components={{

View file

@ -9,7 +9,7 @@ import { Button, ButtonSize, ButtonVariant } from '../Button';
import { SystemMessage } from './SystemMessage'; import { SystemMessage } from './SystemMessage';
import { Emojify } from './Emojify'; import { Emojify } from './Emojify';
import { Modal } from '../Modal'; import { Modal } from '../Modal';
import { Intl } from '../Intl'; import { I18n } from '../I18n';
export type PropsDataType = { export type PropsDataType = {
conversationTitle: string; conversationTitle: string;
@ -71,7 +71,7 @@ export function ConversationMergeNotification(props: PropsType): JSX.Element {
<div className="module-conversation-merge-notification__dialog__image"> <div className="module-conversation-merge-notification__dialog__image">
<img src="images/merged-chat.svg" alt="" /> <img src="images/merged-chat.svg" alt="" />
<div className="module-conversation-merge-notification__dialog__text-1"> <div className="module-conversation-merge-notification__dialog__text-1">
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:ConversationMerge--explainer-dialog--line-1" id="icu:ConversationMerge--explainer-dialog--line-1"
components={{ components={{
@ -81,7 +81,7 @@ export function ConversationMergeNotification(props: PropsType): JSX.Element {
/> />
</div> </div>
<div className="module-conversation-merge-notification__dialog__text-2"> <div className="module-conversation-merge-notification__dialog__text-2">
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:ConversationMerge--explainer-dialog--line-2" id="icu:ConversationMerge--explainer-dialog--line-2"
/> />

View file

@ -6,7 +6,7 @@ import * as React from 'react';
import { Button, ButtonSize, ButtonVariant } from '../Button'; import { Button, ButtonSize, ButtonVariant } from '../Button';
import type { ConversationType } from '../../state/ducks/conversations'; import type { ConversationType } from '../../state/ducks/conversations';
import { Modal } from '../Modal'; import { Modal } from '../Modal';
import { Intl } from '../Intl'; import { I18n } from '../I18n';
import { Emojify } from './Emojify'; import { Emojify } from './Emojify';
import { useRestoreFocus } from '../../hooks/useRestoreFocus'; import { useRestoreFocus } from '../../hooks/useRestoreFocus';
@ -76,13 +76,13 @@ export function DeliveryIssueDialog(props: PropsType): React.ReactElement {
</div> </div>
<div className="module-delivery-issue-dialog__description"> <div className="module-delivery-issue-dialog__description">
{inGroup ? ( {inGroup ? (
<Intl <I18n
id="icu:DeliveryIssue--summary--group" id="icu:DeliveryIssue--summary--group"
components={{ sender: senderTitle }} components={{ sender: senderTitle }}
i18n={i18n} i18n={i18n}
/> />
) : ( ) : (
<Intl <I18n
id="icu:DeliveryIssue--summary" id="icu:DeliveryIssue--summary"
components={{ sender: senderTitle }} components={{ sender: senderTitle }}
i18n={i18n} i18n={i18n}

View file

@ -8,7 +8,7 @@ import { Button, ButtonSize, ButtonVariant } from '../Button';
import { SystemMessage } from './SystemMessage'; import { SystemMessage } from './SystemMessage';
import type { ConversationType } from '../../state/ducks/conversations'; import type { ConversationType } from '../../state/ducks/conversations';
import type { LocalizerType } from '../../types/Util'; import type { LocalizerType } from '../../types/Util';
import { Intl } from '../Intl'; import { I18n } from '../I18n';
import { DeliveryIssueDialog } from './DeliveryIssueDialog'; import { DeliveryIssueDialog } from './DeliveryIssueDialog';
import { UserText } from '../UserText'; import { UserText } from '../UserText';
@ -45,7 +45,7 @@ export function DeliveryIssueNotification(
<> <>
<SystemMessage <SystemMessage
contents={ contents={
<Intl <I18n
id="icu:DeliveryIssue--notification" id="icu:DeliveryIssue--notification"
components={{ components={{
sender: <UserText text={sender.firstName || sender.title} />, sender: <UserText text={sender.firstName || sender.title} />,

View file

@ -7,7 +7,7 @@ import { compact, flatten } from 'lodash';
import { ContactName } from './ContactName'; import { ContactName } from './ContactName';
import { SystemMessage } from './SystemMessage'; import { SystemMessage } from './SystemMessage';
import { Intl } from '../Intl'; import { I18n } from '../I18n';
import type { LocalizerType } from '../../types/Util'; import type { LocalizerType } from '../../types/Util';
import { missingCaseError } from '../../util/missingCaseError'; import { missingCaseError } from '../../util/missingCaseError';
@ -69,14 +69,14 @@ function GroupNotificationChange({
switch (type) { switch (type) {
case 'name': case 'name':
return ( return (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:titleIsNow" id="icu:titleIsNow"
components={{ name: newName || '' }} components={{ name: newName || '' }}
/> />
); );
case 'avatar': case 'avatar':
return <Intl i18n={i18n} id="icu:updatedGroupAvatar" />; return <I18n i18n={i18n} id="icu:updatedGroupAvatar" />;
case 'add': case 'add':
if (!contacts || !contacts.length) { if (!contacts || !contacts.length) {
throw new Error('Group update is missing contacts'); throw new Error('Group update is missing contacts');
@ -87,13 +87,13 @@ function GroupNotificationChange({
{otherPeople.length > 0 && ( {otherPeople.length > 0 && (
<> <>
{otherPeople.length === 1 ? ( {otherPeople.length === 1 ? (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:joinedTheGroup" id="icu:joinedTheGroup"
components={{ name: otherPeople[0] }} components={{ name: otherPeople[0] }}
/> />
) : ( ) : (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:multipleJoinedTheGroup" id="icu:multipleJoinedTheGroup"
components={{ names: otherPeopleWithCommas }} components={{ names: otherPeopleWithCommas }}
@ -103,7 +103,7 @@ function GroupNotificationChange({
)} )}
{contactsIncludesMe && ( {contactsIncludesMe && (
<div className="module-group-notification__change"> <div className="module-group-notification__change">
<Intl i18n={i18n} id="icu:youJoinedTheGroup" /> <I18n i18n={i18n} id="icu:youJoinedTheGroup" />
</div> </div>
)} )}
</> </>
@ -118,13 +118,13 @@ function GroupNotificationChange({
} }
return contacts.length > 1 ? ( return contacts.length > 1 ? (
<Intl <I18n
id="icu:multipleLeftTheGroup" id="icu:multipleLeftTheGroup"
i18n={i18n} i18n={i18n}
components={{ name: otherPeople[0] }} components={{ name: otherPeople[0] }}
/> />
) : ( ) : (
<Intl <I18n
id="icu:leftTheGroup" id="icu:leftTheGroup"
i18n={i18n} i18n={i18n}
components={{ name: otherPeopleWithCommas }} components={{ name: otherPeopleWithCommas }}
@ -151,9 +151,9 @@ export function GroupNotification({
const isLeftOnly = changes.length === 1 && firstChange?.type === 'remove'; const isLeftOnly = changes.length === 1 && firstChange?.type === 'remove';
const fromLabel = from.isMe ? ( const fromLabel = from.isMe ? (
<Intl i18n={i18n} id="icu:youUpdatedTheGroup" /> <I18n i18n={i18n} id="icu:youUpdatedTheGroup" />
) : ( ) : (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:updatedTheGroup" id="icu:updatedTheGroup"
components={{ name: <ContactName title={from.title} /> }} components={{ name: <ContactName title={from.title} /> }}

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import * as React from 'react'; import * as React from 'react';
import { Intl } from '../Intl'; import { I18n } from '../I18n';
import type { LocalizerType } from '../../types/Util'; import type { LocalizerType } from '../../types/Util';
export type PropsType = { export type PropsType = {
@ -19,7 +19,7 @@ export function GroupV1DisabledActions({
return ( return (
<div className="module-group-v1-disabled-actions"> <div className="module-group-v1-disabled-actions">
<p className="module-group-v1-disabled-actions__message"> <p className="module-group-v1-disabled-actions__message">
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:GroupV1--Migration--disabled--link" id="icu:GroupV1--Migration--disabled--link"
components={{ components={{

View file

@ -8,7 +8,7 @@ import { SystemMessage } from './SystemMessage';
import type { LocalizerType, ThemeType } from '../../types/Util'; import type { LocalizerType, ThemeType } from '../../types/Util';
import type { ConversationType } from '../../state/ducks/conversations'; import type { ConversationType } from '../../state/ducks/conversations';
import type { PreferredBadgeSelectorType } from '../../state/selectors/badges'; import type { PreferredBadgeSelectorType } from '../../state/selectors/badges';
import { Intl } from '../Intl'; import { I18n } from '../I18n';
import { ContactName } from './ContactName'; import { ContactName } from './ContactName';
import { GroupV1MigrationDialog } from '../GroupV1MigrationDialog'; import { GroupV1MigrationDialog } from '../GroupV1MigrationDialog';
import * as log from '../../logging/log'; import * as log from '../../logging/log';
@ -130,14 +130,14 @@ function renderUsers({
return ( return (
<p> <p>
{kind === 'invited' && ( {kind === 'invited' && (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:GroupV1--Migration--invited--one" id="icu:GroupV1--Migration--invited--one"
components={{ contact }} components={{ contact }}
/> />
)} )}
{kind === 'removed' && ( {kind === 'removed' && (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:GroupV1--Migration--removed--one" id="icu:GroupV1--Migration--removed--one"
components={{ contact }} components={{ contact }}
@ -150,14 +150,14 @@ function renderUsers({
return ( return (
<p> <p>
{kind === 'invited' && ( {kind === 'invited' && (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:GroupV1--Migration--invited--many" id="icu:GroupV1--Migration--invited--many"
components={{ count }} components={{ count }}
/> />
)} )}
{kind === 'removed' && ( {kind === 'removed' && (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:GroupV1--Migration--removed--many" id="icu:GroupV1--Migration--removed--many"
components={{ count }} components={{ count }}

View file

@ -6,7 +6,7 @@ import React, { useState } from 'react';
import { get } from 'lodash'; import { get } from 'lodash';
import * as log from '../../logging/log'; import * as log from '../../logging/log';
import { Intl } from '../Intl'; import { I18n } from '../I18n';
import type { import type {
LocalizerType, LocalizerType,
ICUJSXMessageParamsByKeyType, ICUJSXMessageParamsByKeyType,
@ -62,7 +62,7 @@ function renderStringToIntl<Key extends keyof ICUJSXMessageParamsByKeyType>(
i18n: LocalizerType, i18n: LocalizerType,
components: ICUJSXMessageParamsByKeyType[Key] components: ICUJSXMessageParamsByKeyType[Key]
): JSX.Element { ): JSX.Element {
return <Intl id={id} i18n={i18n} components={components} />; return <I18n id={id} i18n={i18n} components={components} />;
} }
enum ModalState { enum ModalState {
@ -229,7 +229,7 @@ function GroupV2Detail({
i18n={i18n} i18n={i18n}
onClose={() => setModalState(ModalState.None)} onClose={() => setModalState(ModalState.None)}
> >
<Intl <I18n
id="icu:PendingRequests--block--contents" id="icu:PendingRequests--block--contents"
i18n={i18n} i18n={i18n}
components={{ components={{

View file

@ -9,7 +9,7 @@ import {
MessageRequestActionsConfirmation, MessageRequestActionsConfirmation,
MessageRequestState, MessageRequestState,
} from './MessageRequestActionsConfirmation'; } from './MessageRequestActionsConfirmation';
import { Intl } from '../Intl'; import { I18n } from '../I18n';
import type { LocalizerType } from '../../types/Util'; import type { LocalizerType } from '../../types/Util';
export type Props = { export type Props = {
@ -92,13 +92,13 @@ export function MandatoryProfileSharingActions({
<div className="module-message-request-actions"> <div className="module-message-request-actions">
<p className="module-message-request-actions__message"> <p className="module-message-request-actions__message">
{conversationType === 'direct' ? ( {conversationType === 'direct' ? (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:MessageRequests--profile-sharing--direct--link" id="icu:MessageRequests--profile-sharing--direct--link"
components={{ firstName: firstNameContact, learnMoreLink }} components={{ firstName: firstNameContact, learnMoreLink }}
/> />
) : ( ) : (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:MessageRequests--profile-sharing--group--link" id="icu:MessageRequests--profile-sharing--group--link"
components={{ learnMoreLink }} components={{ learnMoreLink }}

View file

@ -9,7 +9,7 @@ import {
MessageRequestActionsConfirmation, MessageRequestActionsConfirmation,
MessageRequestState, MessageRequestState,
} from './MessageRequestActionsConfirmation'; } from './MessageRequestActionsConfirmation';
import { Intl } from '../Intl'; import { I18n } from '../I18n';
import type { LocalizerType } from '../../types/Util'; import type { LocalizerType } from '../../types/Util';
import { strictAssert } from '../../util/assert'; import { strictAssert } from '../../util/assert';
@ -55,7 +55,7 @@ export function MessageRequestActions({
if (isBlocked) { if (isBlocked) {
message = ( message = (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:MessageRequests--message-direct-blocked" id="icu:MessageRequests--message-direct-blocked"
components={{ name }} components={{ name }}
@ -63,7 +63,7 @@ export function MessageRequestActions({
); );
} else if (isHidden) { } else if (isHidden) {
message = ( message = (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:MessageRequests--message-direct-hidden" id="icu:MessageRequests--message-direct-hidden"
components={{ name }} components={{ name }}
@ -71,7 +71,7 @@ export function MessageRequestActions({
); );
} else { } else {
message = ( message = (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:MessageRequests--message-direct" id="icu:MessageRequests--message-direct"
components={{ name }} components={{ name }}
@ -81,10 +81,10 @@ export function MessageRequestActions({
} else if (conversationType === 'group') { } else if (conversationType === 'group') {
if (isBlocked) { if (isBlocked) {
message = ( message = (
<Intl i18n={i18n} id="icu:MessageRequests--message-group-blocked" /> <I18n i18n={i18n} id="icu:MessageRequests--message-group-blocked" />
); );
} else { } else {
message = <Intl i18n={i18n} id="icu:MessageRequests--message-group" />; message = <I18n i18n={i18n} id="icu:MessageRequests--message-group" />;
} }
} }

View file

@ -5,7 +5,7 @@ import * as React from 'react';
import type { ContactNameData } from './ContactName'; import type { ContactNameData } from './ContactName';
import { ContactName } from './ContactName'; import { ContactName } from './ContactName';
import { ConfirmationDialog } from '../ConfirmationDialog'; import { ConfirmationDialog } from '../ConfirmationDialog';
import { Intl } from '../Intl'; import { I18n } from '../I18n';
import type { LocalizerType } from '../../types/Util'; import type { LocalizerType } from '../../types/Util';
export enum MessageRequestState { export enum MessageRequestState {
@ -65,7 +65,7 @@ export function MessageRequestActionsConfirmation({
}} }}
title={ title={
conversationType === 'direct' ? ( conversationType === 'direct' ? (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:MessageRequests--block-direct-confirm-title" id="icu:MessageRequests--block-direct-confirm-title"
components={{ components={{
@ -79,7 +79,7 @@ export function MessageRequestActionsConfirmation({
}} }}
/> />
) : ( ) : (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:MessageRequests--block-group-confirm-title" id="icu:MessageRequests--block-group-confirm-title"
components={{ components={{
@ -147,7 +147,7 @@ export function MessageRequestActionsConfirmation({
'icu:MessageRequests--ReportAndMaybeBlockModal-body--group--unknown-contact' 'icu:MessageRequests--ReportAndMaybeBlockModal-body--group--unknown-contact'
) )
) : ( ) : (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:MessageRequests--ReportAndMaybeBlockModal-body--group" id="icu:MessageRequests--ReportAndMaybeBlockModal-body--group"
components={{ components={{
@ -170,7 +170,7 @@ export function MessageRequestActionsConfirmation({
onChangeState(MessageRequestState.default); onChangeState(MessageRequestState.default);
}} }}
title={ title={
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:MessageRequests--unblock-direct-confirm-title" id="icu:MessageRequests--unblock-direct-confirm-title"
components={{ components={{
@ -207,12 +207,12 @@ export function MessageRequestActionsConfirmation({
}} }}
title={ title={
conversationType === 'direct' ? ( conversationType === 'direct' ? (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:MessageRequests--delete-direct-confirm-title" id="icu:MessageRequests--delete-direct-confirm-title"
/> />
) : ( ) : (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:MessageRequests--delete-group-confirm-title" id="icu:MessageRequests--delete-group-confirm-title"
components={{ components={{
@ -269,7 +269,7 @@ export function MessageRequestActionsConfirmation({
}, },
]} ]}
> >
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:MessageRequests--AcceptedOptionsModal--body" id="icu:MessageRequests--AcceptedOptionsModal--body"
components={{ components={{

View file

@ -8,7 +8,7 @@ import type { LocalizerType } from '../../types/Util';
import { isAccessControlEnabled } from '../../groups/util'; import { isAccessControlEnabled } from '../../groups/util';
import { ConfirmationDialog } from '../ConfirmationDialog'; import { ConfirmationDialog } from '../ConfirmationDialog';
import { Intl } from '../Intl'; import { I18n } from '../I18n';
import { ContactName } from './ContactName'; import { ContactName } from './ContactName';
type PropsType = { type PropsType = {
@ -46,13 +46,13 @@ export function RemoveGroupMemberConfirmationDialog({
onClose={onClose} onClose={onClose}
title={ title={
accessControlEnabled ? ( accessControlEnabled ? (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:RemoveGroupMemberConfirmation__description__with-link" id="icu:RemoveGroupMemberConfirmation__description__with-link"
components={{ name: contactName }} components={{ name: contactName }}
/> />
) : ( ) : (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:RemoveGroupMemberConfirmation__description" id="icu:RemoveGroupMemberConfirmation__description"
components={{ name: contactName }} components={{ name: contactName }}

View file

@ -6,7 +6,7 @@ import React from 'react';
import { Button, ButtonSize, ButtonVariant } from '../Button'; import { Button, ButtonSize, ButtonVariant } from '../Button';
import { SystemMessage } from './SystemMessage'; import { SystemMessage } from './SystemMessage';
import { ContactName } from './ContactName'; import { ContactName } from './ContactName';
import { Intl } from '../Intl'; import { I18n } from '../I18n';
import type { LocalizerType } from '../../types/Util'; import type { LocalizerType } from '../../types/Util';
export type ContactType = { export type ContactType = {
@ -51,13 +51,13 @@ export function SafetyNumberNotification({
icon="safety-number" icon="safety-number"
contents={ contents={
isGroup ? ( isGroup ? (
<Intl <I18n
id="icu:safetyNumberChangedGroup" id="icu:safetyNumberChangedGroup"
components={{ name }} components={{ name }}
i18n={i18n} i18n={i18n}
/> />
) : ( ) : (
<Intl id="icu:safetyNumberChanged" i18n={i18n} /> <I18n id="icu:safetyNumberChanged" i18n={i18n} />
) )
} }
button={ button={

View file

@ -18,7 +18,7 @@ import { clearTimeoutIfNecessary } from '../../util/clearTimeoutIfNecessary';
import { WidthBreakpoint } from '../_util'; import { WidthBreakpoint } from '../_util';
import { ErrorBoundary } from './ErrorBoundary'; import { ErrorBoundary } from './ErrorBoundary';
import { Intl } from '../Intl'; import { I18n } from '../I18n';
import { TimelineWarning } from './TimelineWarning'; import { TimelineWarning } from './TimelineWarning';
import { TimelineWarnings } from './TimelineWarnings'; import { TimelineWarnings } from './TimelineWarnings';
import { NewlyCreatedGroupInvitedContactsDialog } from '../NewlyCreatedGroupInvitedContactsDialog'; import { NewlyCreatedGroupInvitedContactsDialog } from '../NewlyCreatedGroupInvitedContactsDialog';
@ -995,7 +995,7 @@ export class Timeline extends React.Component<
switch (warning.type) { switch (warning.type) {
case ContactSpoofingType.DirectConversationWithSameTitle: case ContactSpoofingType.DirectConversationWithSameTitle:
text = ( text = (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:ContactSpoofing__same-name--link" id="icu:ContactSpoofing__same-name--link"
components={{ components={{
@ -1037,7 +1037,7 @@ export class Timeline extends React.Component<
); );
} }
text = ( text = (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:ContactSpoofing__same-name-in-group--link" id="icu:ContactSpoofing__same-name-in-group--link"
components={{ components={{
@ -1048,7 +1048,7 @@ export class Timeline extends React.Component<
); );
} else { } else {
text = ( text = (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:ContactSpoofing__same-names-in-group--link" id="icu:ContactSpoofing__same-names-in-group--link"
components={{ components={{

View file

@ -6,7 +6,7 @@ import React from 'react';
import { ContactName } from './ContactName'; import { ContactName } from './ContactName';
import { SystemMessage } from './SystemMessage'; import { SystemMessage } from './SystemMessage';
import { Intl } from '../Intl'; import { I18n } from '../I18n';
import type { LocalizerType } from '../../types/Util'; import type { LocalizerType } from '../../types/Util';
import * as expirationTimer from '../../util/expirationTimer'; import * as expirationTimer from '../../util/expirationTimer';
import type { DurationInSeconds } from '../../util/durations'; import type { DurationInSeconds } from '../../util/durations';
@ -54,13 +54,13 @@ export function TimerNotification(props: Props): JSX.Element {
switch (type) { switch (type) {
case 'fromOther': case 'fromOther':
message = disabled ? ( message = disabled ? (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:disabledDisappearingMessages" id="icu:disabledDisappearingMessages"
components={{ name }} components={{ name }}
/> />
) : ( ) : (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:theyChangedTheTimer" id="icu:theyChangedTheTimer"
components={{ name, time: timespan }} components={{ name, time: timespan }}

View file

@ -4,7 +4,7 @@
import React from 'react'; import React from 'react';
import type { LocalizerType } from '../../types/Util'; import type { LocalizerType } from '../../types/Util';
import { Intl } from '../Intl'; import { I18n } from '../I18n';
import { SystemMessage } from './SystemMessage'; import { SystemMessage } from './SystemMessage';
import { UserText } from '../UserText'; import { UserText } from '../UserText';
@ -25,7 +25,7 @@ export function TitleTransitionNotification(props: Props): JSX.Element {
return ( return (
<SystemMessage <SystemMessage
contents={ contents={
<Intl <I18n
id="icu:TitleTransition--notification" id="icu:TitleTransition--notification"
components={{ components={{
oldTitle: <UserText text={oldTitle} />, oldTitle: <UserText text={oldTitle} />,

View file

@ -6,7 +6,7 @@ import React from 'react';
import { SystemMessage } from './SystemMessage'; import { SystemMessage } from './SystemMessage';
import { Button, ButtonSize, ButtonVariant } from '../Button'; import { Button, ButtonSize, ButtonVariant } from '../Button';
import { ContactName } from './ContactName'; import { ContactName } from './ContactName';
import { Intl } from '../Intl'; import { I18n } from '../I18n';
import type { LocalizerType } from '../../types/Util'; import type { LocalizerType } from '../../types/Util';
import { openLinkInWebBrowser } from '../../util/openLinkInWebBrowser'; import { openLinkInWebBrowser } from '../../util/openLinkInWebBrowser';
@ -43,25 +43,25 @@ function UnsupportedMessageContents({ canProcessNow, contact, i18n }: Props) {
if (isMe) { if (isMe) {
if (canProcessNow) { if (canProcessNow) {
return ( return (
<Intl <I18n
id="icu:Message--unsupported-message-ask-to-resend" id="icu:Message--unsupported-message-ask-to-resend"
components={{ contact: contactName }} components={{ contact: contactName }}
i18n={i18n} i18n={i18n}
/> />
); );
} }
return <Intl id="icu:Message--from-me-unsupported-message" i18n={i18n} />; return <I18n id="icu:Message--from-me-unsupported-message" i18n={i18n} />;
} }
if (canProcessNow) { if (canProcessNow) {
return ( return (
<Intl <I18n
id="icu:Message--from-me-unsupported-message-ask-to-resend" id="icu:Message--from-me-unsupported-message-ask-to-resend"
i18n={i18n} i18n={i18n}
/> />
); );
} }
return ( return (
<Intl <I18n
id="icu:Message--unsupported-message" id="icu:Message--unsupported-message"
i18n={i18n} i18n={i18n}
components={{ components={{

View file

@ -5,7 +5,7 @@ import React from 'react';
import { SystemMessage } from './SystemMessage'; import { SystemMessage } from './SystemMessage';
import { ContactName } from './ContactName'; import { ContactName } from './ContactName';
import { Intl } from '../Intl'; import { I18n } from '../I18n';
import type { LocalizerType } from '../../types/Util'; import type { LocalizerType } from '../../types/Util';
import { missingCaseError } from '../../util/missingCaseError'; import { missingCaseError } from '../../util/missingCaseError';
@ -41,9 +41,9 @@ function VerificationNotificationContents({
switch (type) { switch (type) {
case 'markVerified': case 'markVerified':
return isLocal ? ( return isLocal ? (
<Intl id="icu:youMarkedAsVerified" components={{ name }} i18n={i18n} /> <I18n id="icu:youMarkedAsVerified" components={{ name }} i18n={i18n} />
) : ( ) : (
<Intl <I18n
id="icu:youMarkedAsVerifiedOtherDevice" id="icu:youMarkedAsVerifiedOtherDevice"
components={{ name }} components={{ name }}
i18n={i18n} i18n={i18n}
@ -51,13 +51,13 @@ function VerificationNotificationContents({
); );
case 'markNotVerified': case 'markNotVerified':
return isLocal ? ( return isLocal ? (
<Intl <I18n
id="icu:youMarkedAsNotVerified" id="icu:youMarkedAsNotVerified"
components={{ name }} components={{ name }}
i18n={i18n} i18n={i18n}
/> />
) : ( ) : (
<Intl <I18n
id="icu:youMarkedAsNotVerifiedOtherDevice" id="icu:youMarkedAsNotVerifiedOtherDevice"
components={{ name }} components={{ name }}
i18n={i18n} i18n={i18n}

View file

@ -11,7 +11,7 @@ import { Button, ButtonVariant } from '../../../Button';
import { Spinner } from '../../../Spinner'; import { Spinner } from '../../../Spinner';
import type { ConversationType } from '../../../../state/ducks/conversations'; import type { ConversationType } from '../../../../state/ducks/conversations';
import { RequestState } from '../util'; import { RequestState } from '../util';
import { Intl } from '../../../Intl'; import { I18n } from '../../../I18n';
import { ContactName } from '../../ContactName'; import { ContactName } from '../../ContactName';
import { UserText } from '../../../UserText'; import { UserText } from '../../../UserText';
@ -45,7 +45,7 @@ export function ConfirmAdditionsModal({
let headerText: ReactNode; let headerText: ReactNode;
if (selectedContacts.length === 1) { if (selectedContacts.length === 1) {
headerText = ( headerText = (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:AddGroupMembersModal--confirm-title--one" id="icu:AddGroupMembersModal--confirm-title--one"
components={{ components={{
@ -56,7 +56,7 @@ export function ConfirmAdditionsModal({
); );
} else { } else {
headerText = ( headerText = (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:AddGroupMembersModal--confirm-title--many" id="icu:AddGroupMembersModal--confirm-title--many"
components={{ components={{

View file

@ -13,7 +13,7 @@ import { About } from '../conversation/About';
import { ListTile } from '../ListTile'; import { ListTile } from '../ListTile';
import { Avatar, AvatarSize } from '../Avatar'; import { Avatar, AvatarSize } from '../Avatar';
import { ContextMenu } from '../ContextMenu'; import { ContextMenu } from '../ContextMenu';
import { Intl } from '../Intl'; import { I18n } from '../I18n';
import { ConfirmationDialog } from '../ConfirmationDialog'; import { ConfirmationDialog } from '../ConfirmationDialog';
import { isSignalConversation } from '../../util/isSignalConversation'; import { isSignalConversation } from '../../util/isSignalConversation';
import { isInSystemContacts } from '../../util/isInSystemContacts'; import { isInSystemContacts } from '../../util/isInSystemContacts';
@ -183,7 +183,7 @@ export const ContactListItem: FunctionComponent<PropsType> = React.memo(
i18n={i18n} i18n={i18n}
onClose={() => setConfirmingBlocking(false)} onClose={() => setConfirmingBlocking(false)}
title={ title={
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:MessageRequests--block-direct-confirm-title" id="icu:MessageRequests--block-direct-confirm-title"
components={{ components={{
@ -215,7 +215,7 @@ export const ContactListItem: FunctionComponent<PropsType> = React.memo(
i18n={i18n} i18n={i18n}
onClose={() => setConfirmingRemoving(false)} onClose={() => setConfirmingRemoving(false)}
title={ title={
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:ContactListItem__remove-system--title" id="icu:ContactListItem__remove-system--title"
components={{ components={{
@ -236,7 +236,7 @@ export const ContactListItem: FunctionComponent<PropsType> = React.memo(
i18n={i18n} i18n={i18n}
onClose={() => setConfirmingRemoving(false)} onClose={() => setConfirmingRemoving(false)}
title={ title={
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:ContactListItem__remove--title" id="icu:ContactListItem__remove--title"
components={{ components={{

View file

@ -16,7 +16,7 @@ import type {
ShowConversationType, ShowConversationType,
} from '../../state/ducks/conversations'; } from '../../state/ducks/conversations';
import type { PreferredBadgeSelectorType } from '../../state/selectors/badges'; import type { PreferredBadgeSelectorType } from '../../state/selectors/badges';
import { Intl } from '../Intl'; import { I18n } from '../I18n';
import { import {
MessageTextRenderer, MessageTextRenderer,
RenderLocation, RenderLocation,
@ -74,7 +74,7 @@ const renderPerson = (
}> }>
): JSX.Element => ): JSX.Element =>
person.isMe ? ( person.isMe ? (
<Intl i18n={i18n} id="icu:you" /> <I18n i18n={i18n} id="icu:you" />
) : ( ) : (
<ContactName title={person.title} /> <ContactName title={person.title} />
); );
@ -112,7 +112,7 @@ export const MessageSearchResult: FunctionComponent<PropsType> = React.memo(
if (to.type === 'group') { if (to.type === 'group') {
headerName = ( headerName = (
<span> <span>
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:searchResultHeader--you-to-group" id="icu:searchResultHeader--you-to-group"
components={{ components={{
@ -124,7 +124,7 @@ export const MessageSearchResult: FunctionComponent<PropsType> = React.memo(
} else { } else {
headerName = ( headerName = (
<span> <span>
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:searchResultHeader--you-to-receiver" id="icu:searchResultHeader--you-to-receiver"
components={{ components={{
@ -139,7 +139,7 @@ export const MessageSearchResult: FunctionComponent<PropsType> = React.memo(
if (to.type === 'group') { if (to.type === 'group') {
headerName = ( headerName = (
<span> <span>
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:searchResultHeader--sender-to-group" id="icu:searchResultHeader--sender-to-group"
components={{ components={{
@ -152,7 +152,7 @@ export const MessageSearchResult: FunctionComponent<PropsType> = React.memo(
} else { } else {
headerName = ( headerName = (
<span> <span>
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:searchResultHeader--sender-to-you" id="icu:searchResultHeader--sender-to-you"
components={{ components={{

View file

@ -10,7 +10,7 @@ import { missingCaseError } from '../../util/missingCaseError';
import type { Loadable } from '../../util/loadable'; import type { Loadable } from '../../util/loadable';
import { LoadingState } from '../../util/loadable'; import { LoadingState } from '../../util/loadable';
import { Intl } from '../Intl'; import { I18n } from '../I18n';
import { Spinner } from '../Spinner'; import { Spinner } from '../Spinner';
import { QrCode } from '../QrCode'; import { QrCode } from '../QrCode';
import { TitlebarDragArea } from '../TitlebarDragArea'; import { TitlebarDragArea } from '../TitlebarDragArea';
@ -75,7 +75,7 @@ export function InstallScreenQrCodeNotScannedStep({
<ol> <ol>
<li>{i18n('icu:Install__instructions__1')}</li> <li>{i18n('icu:Install__instructions__1')}</li>
<li> <li>
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:Install__instructions__2" id="icu:Install__instructions__2"
components={{ components={{
@ -89,7 +89,7 @@ export function InstallScreenQrCodeNotScannedStep({
/> />
</li> </li>
<li> <li>
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:Install__instructions__3" id="icu:Install__instructions__3"
components={{ components={{
@ -130,7 +130,7 @@ function InstallScreenQrCode(
case LoadingState.LoadFailed: case LoadingState.LoadFailed:
contents = ( contents = (
<span className={classNames(getQrCodeClassName('__error-message'))}> <span className={classNames(getQrCodeClassName('__error-message'))}>
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:Install__qr-failed-load" id="icu:Install__qr-failed-load"
components={{ components={{

View file

@ -15,7 +15,7 @@ import type { UpdatesStateType } from '../../state/ducks/updates';
import { isBeta } from '../../util/version'; import { isBeta } from '../../util/version';
import { ConfirmationDialog } from '../ConfirmationDialog'; import { ConfirmationDialog } from '../ConfirmationDialog';
import { Modal } from '../Modal'; import { Modal } from '../Modal';
import { Intl } from '../Intl'; import { I18n } from '../I18n';
import { formatFileSize } from '../../util/formatFileSize'; import { formatFileSize } from '../../util/formatFileSize';
export type PropsType = UpdatesStateType & export type PropsType = UpdatesStateType &
@ -56,7 +56,7 @@ export function InstallScreenUpdateDialog({
noMouseClose noMouseClose
title={i18n('icu:InstallScreenUpdateDialog--unsupported-os__title')} title={i18n('icu:InstallScreenUpdateDialog--unsupported-os__title')}
> >
<Intl <I18n
id="icu:UnsupportedOSErrorDialog__body" id="icu:UnsupportedOSErrorDialog__body"
i18n={i18n} i18n={i18n}
components={{ components={{
@ -85,7 +85,7 @@ export function InstallScreenUpdateDialog({
dialogType === DialogType.FullDownloadReady dialogType === DialogType.FullDownloadReady
) { ) {
actionText = ( actionText = (
<Intl <I18n
id="icu:InstallScreenUpdateDialog--manual-update__action" id="icu:InstallScreenUpdateDialog--manual-update__action"
i18n={i18n} i18n={i18n}
components={{ components={{
@ -159,7 +159,7 @@ export function InstallScreenUpdateDialog({
: PRODUCTION_DOWNLOAD_URL; : PRODUCTION_DOWNLOAD_URL;
const title = i18n('icu:cannotUpdate'); const title = i18n('icu:cannotUpdate');
const body = ( const body = (
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:InstallScreenUpdateDialog--cannot-update__body" id="icu:InstallScreenUpdateDialog--cannot-update__body"
components={{ components={{
@ -218,7 +218,7 @@ export function InstallScreenUpdateDialog({
useFocusTrap={false} useFocusTrap={false}
title={i18n('icu:cannotUpdate')} title={i18n('icu:cannotUpdate')}
> >
<Intl <I18n
components={{ components={{
app: <strong key="app">Signal.app</strong>, app: <strong key="app">Signal.app</strong>,
folder: <strong key="folder">/Applications</strong>, folder: <strong key="folder">/Applications</strong>,

View file

@ -5,7 +5,7 @@ import { last } from 'lodash';
import type { ReactChild } from 'react'; import type { ReactChild } from 'react';
import React from 'react'; import React from 'react';
import { Intl } from '../Intl'; import { I18n } from '../I18n';
import type { ToFindType } from './LeftPaneHelper'; import type { ToFindType } from './LeftPaneHelper';
import type { import type {
ConversationType, ConversationType,
@ -118,7 +118,7 @@ export class LeftPaneInboxHelper extends LeftPaneHelper<LeftPaneInboxPropsType>
return ( return (
<div className="module-left-pane__empty"> <div className="module-left-pane__empty">
<div> <div>
<Intl <I18n
i18n={i18n} i18n={i18n}
id="icu:emptyInboxMessage" id="icu:emptyInboxMessage"
components={{ components={{

View file

@ -17,7 +17,7 @@ import type {
} from '../../state/ducks/conversations'; } from '../../state/ducks/conversations';
import { LeftPaneSearchInput } from '../LeftPaneSearchInput'; import { LeftPaneSearchInput } from '../LeftPaneSearchInput';
import { Intl } from '../Intl'; import { I18n } from '../I18n';
import { assertDev } from '../../util/assert'; import { assertDev } from '../../util/assert';
import { UserText } from '../UserText'; import { UserText } from '../UserText';
@ -147,7 +147,7 @@ export class LeftPaneSearchHelper extends LeftPaneHelper<LeftPaneSearchPropsType
let noResults: ReactChild; let noResults: ReactChild;
if (searchConversationName) { if (searchConversationName) {
noResults = ( noResults = (
<Intl <I18n
id="icu:noSearchResultsInConversation" id="icu:noSearchResultsInConversation"
i18n={i18n} i18n={i18n}
components={{ components={{

View file

@ -50,11 +50,27 @@ const messageKeys = Object.keys(globalMessages).sort((a, b) => {
return a.localeCompare(b); return a.localeCompare(b);
}) as Array<keyof typeof globalMessages>; }) as Array<keyof typeof globalMessages>;
function generateType( function filterDefaultParams(params: Map<string, ICUMessageParamType>) {
name: string, const filteredParams = new Map<string, ICUMessageParamType>();
stringType: ts.TypeNode,
componentType: ts.TypeNode for (const [key, value] of params) {
): ts.Statement { if (key === 'emojify') {
continue;
}
filteredParams.set(key, value);
}
return filteredParams;
}
const ComponentOrStringNode =
ts.factory.createTypeReferenceNode('ComponentOrString');
const ComponentNode = ts.factory.createTypeReferenceNode('Component');
const StringToken = ts.factory.createToken(ts.SyntaxKind.StringKeyword);
const NeverToken = ts.factory.createToken(ts.SyntaxKind.NeverKeyword);
function generateType(name: string, supportsComponents: boolean): ts.Statement {
const props = new Array<ts.TypeElement>(); const props = new Array<ts.TypeElement>();
for (const key of messageKeys) { for (const key of messageKeys) {
if (key === 'smartling') { if (key === 'smartling') {
@ -70,7 +86,21 @@ function generateType(
const { messageformat } = message; const { messageformat } = message;
const params = getICUMessageParams(messageformat); const rawParams = getICUMessageParams(messageformat);
const params = filterDefaultParams(rawParams);
if (!supportsComponents) {
const needsComponents = Array.from(rawParams.values()).some(value => {
return value.type === 'jsx';
});
if (needsComponents) {
continue;
}
}
const stringType = supportsComponents ? ComponentOrStringNode : StringToken;
const componentType = supportsComponents ? ComponentNode : NeverToken;
let paramType: ts.TypeNode; let paramType: ts.TypeNode;
if (params.size === 0) { if (params.size === 0) {
@ -193,21 +223,9 @@ statements.push(
) )
); );
statements.push( statements.push(generateType('ICUJSXMessageParamsByKeyType', true));
generateType(
'ICUJSXMessageParamsByKeyType',
ts.factory.createTypeReferenceNode('ComponentOrString'),
ts.factory.createTypeReferenceNode('Component')
)
);
statements.push( statements.push(generateType('ICUStringMessageParamsByKeyType', false));
generateType(
'ICUStringMessageParamsByKeyType',
ts.factory.createToken(ts.SyntaxKind.StringKeyword),
ts.factory.createToken(ts.SyntaxKind.NeverKeyword)
)
);
const root = ts.factory.createSourceFile( const root = ts.factory.createSourceFile(
statements, statements,

View file

@ -40,7 +40,7 @@ async function main() {
// Find uses in either: // Find uses in either:
// - `i18n('key')` // - `i18n('key')`
// - `<Intl id="key"/>` // - `<I18n id="key"/>`
try { try {
const result = await execa( const result = await execa(