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"
},
"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"
},
"icu:Preferences--advanced": {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -22,7 +22,7 @@ import { ContactPills } from './ContactPills';
import { ContactPill } from './ContactPill';
import { ConversationList, RowType } from './ConversationList';
import { Input } from './Input';
import { Intl } from './Intl';
import { I18n } from './I18n';
import { MY_STORY_ID, getStoryDistributionListName } from '../types/Stories';
import { PagedModal, ModalPage } from './Modal';
import { SearchInput } from './SearchInput';
@ -836,13 +836,13 @@ export function EditMyStoryPrivacy({
const disclaimerElement = (
<div className="StoriesSettingsModal__disclaimer">
{kind === 'mine' ? (
<Intl
<I18n
components={{ learnMoreLink }}
i18n={i18n}
id="icu:StoriesSettings__mine__disclaimer--link"
/>
) : (
<Intl
<I18n
components={{ learnMoreLink }}
i18n={i18n}
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 { ContactName } from './conversation/ContactName';
import { ContextMenu } from './ContextMenu';
import { Intl } from './Intl';
import { I18n } from './I18n';
import { Modal } from './Modal';
import { SendStatus } from '../messages/MessageSendState';
import { Theme } from '../util/theme';
@ -246,7 +246,7 @@ export function StoryDetailsModal({
theme={Theme.Dark}
>
<div>
<Intl
<I18n
i18n={i18n}
id="icu:StoryDetailsModal__sent-time"
components={{
@ -263,7 +263,7 @@ export function StoryDetailsModal({
</div>
{attachment && (
<div>
<Intl
<I18n
i18n={i18n}
id="icu:StoryDetailsModal__file-size"
components={{
@ -278,7 +278,7 @@ export function StoryDetailsModal({
)}
{timeRemaining && timeRemaining > 0 && (
<div>
<Intl
<I18n
i18n={i18n}
id="icu:StoryDetailsModal__disappears-in"
components={{

View file

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

View file

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

View file

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

View file

@ -6,7 +6,7 @@ import React from 'react';
import moment from 'moment';
import { Modal } from './Modal';
import { Intl } from './Intl';
import { I18n } from './I18n';
import type { LocalizerType } from '../types/Util';
export type PropsType = {
@ -42,7 +42,7 @@ export function WhatsNewModal({
const releaseNotes: ReleaseNotesType = {
date: new Date(window.getBuildCreation?.() || Date.now()),
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) {

View file

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

View file

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

View file

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

View file

@ -9,7 +9,7 @@ import { Button, ButtonSize, ButtonVariant } from '../Button';
import { SystemMessage } from './SystemMessage';
import { Emojify } from './Emojify';
import { Modal } from '../Modal';
import { Intl } from '../Intl';
import { I18n } from '../I18n';
export type PropsDataType = {
conversationTitle: string;
@ -71,7 +71,7 @@ export function ConversationMergeNotification(props: PropsType): JSX.Element {
<div className="module-conversation-merge-notification__dialog__image">
<img src="images/merged-chat.svg" alt="" />
<div className="module-conversation-merge-notification__dialog__text-1">
<Intl
<I18n
i18n={i18n}
id="icu:ConversationMerge--explainer-dialog--line-1"
components={{
@ -81,7 +81,7 @@ export function ConversationMergeNotification(props: PropsType): JSX.Element {
/>
</div>
<div className="module-conversation-merge-notification__dialog__text-2">
<Intl
<I18n
i18n={i18n}
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 type { ConversationType } from '../../state/ducks/conversations';
import { Modal } from '../Modal';
import { Intl } from '../Intl';
import { I18n } from '../I18n';
import { Emojify } from './Emojify';
import { useRestoreFocus } from '../../hooks/useRestoreFocus';
@ -76,13 +76,13 @@ export function DeliveryIssueDialog(props: PropsType): React.ReactElement {
</div>
<div className="module-delivery-issue-dialog__description">
{inGroup ? (
<Intl
<I18n
id="icu:DeliveryIssue--summary--group"
components={{ sender: senderTitle }}
i18n={i18n}
/>
) : (
<Intl
<I18n
id="icu:DeliveryIssue--summary"
components={{ sender: senderTitle }}
i18n={i18n}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -9,7 +9,7 @@ import {
MessageRequestActionsConfirmation,
MessageRequestState,
} from './MessageRequestActionsConfirmation';
import { Intl } from '../Intl';
import { I18n } from '../I18n';
import type { LocalizerType } from '../../types/Util';
import { strictAssert } from '../../util/assert';
@ -55,7 +55,7 @@ export function MessageRequestActions({
if (isBlocked) {
message = (
<Intl
<I18n
i18n={i18n}
id="icu:MessageRequests--message-direct-blocked"
components={{ name }}
@ -63,7 +63,7 @@ export function MessageRequestActions({
);
} else if (isHidden) {
message = (
<Intl
<I18n
i18n={i18n}
id="icu:MessageRequests--message-direct-hidden"
components={{ name }}
@ -71,7 +71,7 @@ export function MessageRequestActions({
);
} else {
message = (
<Intl
<I18n
i18n={i18n}
id="icu:MessageRequests--message-direct"
components={{ name }}
@ -81,10 +81,10 @@ export function MessageRequestActions({
} else if (conversationType === 'group') {
if (isBlocked) {
message = (
<Intl i18n={i18n} id="icu:MessageRequests--message-group-blocked" />
<I18n i18n={i18n} id="icu:MessageRequests--message-group-blocked" />
);
} 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 { ContactName } from './ContactName';
import { ConfirmationDialog } from '../ConfirmationDialog';
import { Intl } from '../Intl';
import { I18n } from '../I18n';
import type { LocalizerType } from '../../types/Util';
export enum MessageRequestState {
@ -65,7 +65,7 @@ export function MessageRequestActionsConfirmation({
}}
title={
conversationType === 'direct' ? (
<Intl
<I18n
i18n={i18n}
id="icu:MessageRequests--block-direct-confirm-title"
components={{
@ -79,7 +79,7 @@ export function MessageRequestActionsConfirmation({
}}
/>
) : (
<Intl
<I18n
i18n={i18n}
id="icu:MessageRequests--block-group-confirm-title"
components={{
@ -147,7 +147,7 @@ export function MessageRequestActionsConfirmation({
'icu:MessageRequests--ReportAndMaybeBlockModal-body--group--unknown-contact'
)
) : (
<Intl
<I18n
i18n={i18n}
id="icu:MessageRequests--ReportAndMaybeBlockModal-body--group"
components={{
@ -170,7 +170,7 @@ export function MessageRequestActionsConfirmation({
onChangeState(MessageRequestState.default);
}}
title={
<Intl
<I18n
i18n={i18n}
id="icu:MessageRequests--unblock-direct-confirm-title"
components={{
@ -207,12 +207,12 @@ export function MessageRequestActionsConfirmation({
}}
title={
conversationType === 'direct' ? (
<Intl
<I18n
i18n={i18n}
id="icu:MessageRequests--delete-direct-confirm-title"
/>
) : (
<Intl
<I18n
i18n={i18n}
id="icu:MessageRequests--delete-group-confirm-title"
components={{
@ -269,7 +269,7 @@ export function MessageRequestActionsConfirmation({
},
]}
>
<Intl
<I18n
i18n={i18n}
id="icu:MessageRequests--AcceptedOptionsModal--body"
components={{

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -50,11 +50,27 @@ const messageKeys = Object.keys(globalMessages).sort((a, b) => {
return a.localeCompare(b);
}) as Array<keyof typeof globalMessages>;
function generateType(
name: string,
stringType: ts.TypeNode,
componentType: ts.TypeNode
): ts.Statement {
function filterDefaultParams(params: Map<string, ICUMessageParamType>) {
const filteredParams = new Map<string, ICUMessageParamType>();
for (const [key, value] of params) {
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>();
for (const key of messageKeys) {
if (key === 'smartling') {
@ -70,7 +86,21 @@ function generateType(
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;
if (params.size === 0) {
@ -193,21 +223,9 @@ statements.push(
)
);
statements.push(
generateType(
'ICUJSXMessageParamsByKeyType',
ts.factory.createTypeReferenceNode('ComponentOrString'),
ts.factory.createTypeReferenceNode('Component')
)
);
statements.push(generateType('ICUJSXMessageParamsByKeyType', true));
statements.push(
generateType(
'ICUStringMessageParamsByKeyType',
ts.factory.createToken(ts.SyntaxKind.StringKeyword),
ts.factory.createToken(ts.SyntaxKind.NeverKeyword)
)
);
statements.push(generateType('ICUStringMessageParamsByKeyType', false));
const root = ts.factory.createSourceFile(
statements,

View file

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