remove i18n from props everywhere where possible

This commit is contained in:
Audric Ackermann 2021-06-16 15:26:00 +10:00
parent 4b9d2c0692
commit dd9341a196
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4
45 changed files with 183 additions and 370 deletions

View File

@ -53,7 +53,6 @@ const NoImage = (props: {
<ClosedGroupAvatar
size={size}
memberAvatars={memberAvatars}
i18n={window.i18n}
onAvatarClick={props.onAvatarClick}
/>
);

View File

@ -1,12 +1,10 @@
import React from 'react';
import { Avatar, AvatarSize } from '../Avatar';
import { LocalizerType } from '../../types/Util';
import { ConversationAvatar } from '../session/usingClosedConversationDetails';
interface Props {
size: number;
memberAvatars: Array<ConversationAvatar>; // this is added by usingClosedConversationDetails
i18n: LocalizerType;
onAvatarClick?: () => void;
}

View File

@ -4,15 +4,12 @@ import classNames from 'classnames';
import { Avatar, AvatarSize } from './Avatar';
import { Emojify } from './conversation/Emojify';
import { LocalizerType } from '../types/Util';
interface Props {
phoneNumber: string;
isMe?: boolean;
name?: string;
profileName?: string;
avatarPath?: string;
i18n: LocalizerType;
onClick?: () => void;
}
@ -28,16 +25,16 @@ export class ContactListItem extends React.Component<Props> {
}
public render() {
const { i18n, name, onClick, isMe, phoneNumber, profileName } = this.props;
const { name, onClick, isMe, phoneNumber, profileName } = this.props;
const title = name ? name : phoneNumber;
const displayName = isMe ? i18n('me') : title;
const displayName = isMe ? window.i18n('me') : title;
const profileElement =
!isMe && profileName && !name ? (
<span className="module-contact-list-item__text__profile-name">
~
<Emojify text={profileName} i18n={i18n} key={`emojify-list-item-${phoneNumber}`} />
<Emojify text={profileName} key={`emojify-list-item-${phoneNumber}`} />
</span>
) : null;
@ -55,7 +52,7 @@ export class ContactListItem extends React.Component<Props> {
{this.renderAvatar()}
<div className="module-contact-list-item__text">
<div className="module-contact-list-item__text__name">
<Emojify text={displayName} i18n={i18n} /> {profileElement}
<Emojify text={displayName} /> {profileElement}
</div>
</div>
</div>

View File

@ -9,8 +9,6 @@ import { Timestamp } from './conversation/Timestamp';
import { ContactName } from './conversation/ContactName';
import { TypingAnimation } from './conversation/TypingAnimation';
import { LocalizerType } from '../types/Util';
import {
ConversationAvatar,
usingClosedConversationDetails,
@ -31,7 +29,6 @@ export interface ConversationListItemProps extends ConversationType {
}
type PropsHousekeeping = {
i18n: LocalizerType;
style?: Object;
onClick?: (id: string) => void;
onDeleteMessages?: () => void;
@ -120,7 +117,7 @@ class ConversationListItem extends React.PureComponent<Props> {
}
public renderMessage() {
const { lastMessage, isTyping, unreadCount, i18n } = this.props;
const { lastMessage, isTyping, unreadCount } = this.props;
if (!lastMessage && !isTyping) {
return null;
@ -140,15 +137,9 @@ class ConversationListItem extends React.PureComponent<Props> {
)}
>
{isTyping ? (
<TypingAnimation i18n={i18n} />
<TypingAnimation />
) : (
<MessageBody
isGroup={true}
text={text}
disableJumbomoji={true}
disableLinks={true}
i18n={i18n}
/>
<MessageBody isGroup={true} text={text} disableJumbomoji={true} disableLinks={true} />
)}
</div>
{lastMessage && lastMessage.status ? (
@ -221,12 +212,12 @@ class ConversationListItem extends React.PureComponent<Props> {
}
private renderUser() {
const { name, phoneNumber, profileName, isMe, i18n } = this.props;
const { name, phoneNumber, profileName, isMe } = this.props;
const shortenedPubkey = PubKey.shorten(phoneNumber);
const displayedPubkey = profileName ? shortenedPubkey : phoneNumber;
const displayName = isMe ? i18n('noteToSelf') : profileName;
const displayName = isMe ? window.i18n('noteToSelf') : profileName;
let shouldShowPubkey = false;
if ((!name || name.length === 0) && (!displayName || displayName.length === 0)) {
@ -240,7 +231,6 @@ class ConversationListItem extends React.PureComponent<Props> {
name={name}
profileName={displayName}
module="module-conversation__user"
i18n={window.i18n}
boldProfileName={true}
shouldShowPubkey={shouldShowPubkey}
/>

View File

@ -1,13 +1,12 @@
import React from 'react';
import { LocalizerType, RenderTextCallbackType } from '../types/Util';
import { RenderTextCallbackType } from '../types/Util';
type FullJSX = Array<JSX.Element | string> | JSX.Element | string;
interface Props {
/** The translation string id */
id: string;
i18n: LocalizerType;
components?: Array<FullJSX>;
renderText?: RenderTextCallbackType;
}
@ -31,9 +30,9 @@ export class Intl extends React.Component<Props> {
}
public render() {
const { id, i18n, renderText } = this.props;
const { id, renderText } = this.props;
const text = i18n(id);
const text = window.i18n(id);
const results: Array<any> = [];
const FIND_REPLACEMENTS = /\$[^$]+\$/g;

View File

@ -6,11 +6,10 @@ import { AddNewLines } from './conversation/AddNewLines';
import { SizeClassType } from '../util/emoji';
import { LocalizerType, RenderTextCallbackType } from '../types/Util';
import { RenderTextCallbackType } from '../types/Util';
interface Props {
text: string;
i18n: LocalizerType;
}
const renderNewLines: RenderTextCallbackType = ({ text, key }) => (
@ -18,30 +17,20 @@ const renderNewLines: RenderTextCallbackType = ({ text, key }) => (
);
const renderEmoji = ({
i18n,
text,
key,
sizeClass,
renderNonEmoji,
}: {
i18n: LocalizerType;
text: string;
key: number;
sizeClass?: SizeClassType;
renderNonEmoji: RenderTextCallbackType;
}) => (
<Emojify
i18n={i18n}
key={key}
text={text}
sizeClass={sizeClass}
renderNonEmoji={renderNonEmoji}
/>
);
}) => <Emojify key={key} text={text} sizeClass={sizeClass} renderNonEmoji={renderNonEmoji} />;
export class MessageBodyHighlight extends React.Component<Props> {
public render() {
const { text, i18n } = this.props;
const { text } = this.props;
const results: Array<any> = [];
const FIND_BEGIN_END = /<<left>>(.+?)<<right>>/g;
@ -50,7 +39,7 @@ export class MessageBodyHighlight extends React.Component<Props> {
let count = 1;
if (!match) {
return <MessageBody disableJumbomoji={true} disableLinks={true} text={text} i18n={i18n} />;
return <MessageBody disableJumbomoji={true} disableLinks={true} text={text} />;
}
const sizeClass = '';
@ -63,7 +52,6 @@ export class MessageBodyHighlight extends React.Component<Props> {
text: beforeText,
sizeClass,
key: count++,
i18n,
renderNonEmoji: renderNewLines,
})
);
@ -76,7 +64,6 @@ export class MessageBodyHighlight extends React.Component<Props> {
text: toHighlight,
sizeClass,
key: count++,
i18n,
renderNonEmoji: renderNewLines,
})}
</span>
@ -93,7 +80,6 @@ export class MessageBodyHighlight extends React.Component<Props> {
text: text.slice(last),
sizeClass,
key: count++,
i18n,
renderNonEmoji: renderNewLines,
})
);

View File

@ -6,7 +6,6 @@ import { MessageBodyHighlight } from './MessageBodyHighlight';
import { Timestamp } from './conversation/Timestamp';
import { ContactName } from './conversation/ContactName';
import { LocalizerType } from '../types/Util';
import { DefaultTheme, withTheme } from 'styled-components';
export type MessageSearchResultProps = {
@ -37,7 +36,6 @@ export type MessageSearchResultProps = {
type PropsHousekeeping = {
isSelected?: boolean;
theme: DefaultTheme;
i18n: LocalizerType;
onClick: (conversationId: string, messageId?: string) => void;
};
@ -45,15 +43,19 @@ type Props = MessageSearchResultProps & PropsHousekeeping;
class MessageSearchResultInner extends React.PureComponent<Props> {
public renderFromName() {
const { from, i18n, to } = this.props;
const { from, to } = this.props;
if (from.isMe && to.isMe) {
return (
<span className="module-message-search-result__header__name">{i18n('noteToSelf')}</span>
<span className="module-message-search-result__header__name">
{window.i18n('noteToSelf')}
</span>
);
}
if (from.isMe) {
return <span className="module-message-search-result__header__name">{i18n('you')}</span>;
return (
<span className="module-message-search-result__header__name">{window.i18n('you')}</span>
);
}
return (
@ -61,7 +63,6 @@ class MessageSearchResultInner extends React.PureComponent<Props> {
phoneNumber={from.phoneNumber}
name={from.name}
profileName={from.profileName}
i18n={i18n}
module="module-message-search-result__header__name"
shouldShowPubkey={false}
/>
@ -69,19 +70,18 @@ class MessageSearchResultInner extends React.PureComponent<Props> {
}
public renderFrom() {
const { i18n, to } = this.props;
const { to } = this.props;
const fromName = this.renderFromName();
if (!to.isMe) {
return (
<div className="module-message-search-result__header__from">
{fromName} {i18n('to')}{' '}
{fromName} {window.i18n('to')}{' '}
<span className="module-mesages-search-result__header__group">
<ContactName
phoneNumber={to.phoneNumber}
name={to.name}
profileName={to.profileName}
i18n={i18n}
shouldShowPubkey={false}
/>
</span>
@ -107,17 +107,7 @@ class MessageSearchResultInner extends React.PureComponent<Props> {
}
public render() {
const {
from,
i18n,
id,
isSelected,
conversationId,
onClick,
receivedAt,
snippet,
to,
} = this.props;
const { from, id, isSelected, conversationId, onClick, receivedAt, snippet, to } = this.props;
if (!from || !to) {
return null;
@ -145,7 +135,7 @@ class MessageSearchResultInner extends React.PureComponent<Props> {
</div>
</div>
<div className="module-message-search-result__body">
<MessageBodyHighlight text={snippet} i18n={i18n} />
<MessageBodyHighlight text={snippet} />
</div>
</div>
</div>

View File

@ -2,8 +2,6 @@ import React from 'react';
import { ConversationListItemProps, ConversationListItemWithDetails } from './ConversationListItem';
import { MessageSearchResult, MessageSearchResultProps } from './MessageSearchResult';
import { LocalizerType } from '../types/Util';
export type SearchResultsProps = {
contacts: Array<ConversationListItemProps>;
conversations: Array<ConversationListItemProps>;
@ -13,7 +11,6 @@ export type SearchResultsProps = {
};
type PropsHousekeeping = {
i18n: LocalizerType;
openConversationExternal: (id: string, messageId?: string) => void;
};
@ -25,7 +22,6 @@ export class SearchResults extends React.Component<Props> {
conversations,
contacts,
hideMessagesHeader,
i18n,
messages,
openConversationExternal,
searchTerm,
@ -40,37 +36,37 @@ export class SearchResults extends React.Component<Props> {
<div className="module-search-results">
{noResults ? (
<div className="module-search-results__no-results">
{i18n('noSearchResults', [searchTerm])}
{window.i18n('noSearchResults', [searchTerm])}
</div>
) : null}
{haveConversations ? (
<div className="module-search-results__conversations">
<div className="module-search-results__conversations-header">
{i18n('conversationsHeader')}
{window.i18n('conversationsHeader')}
</div>
{conversations.map(conversation => (
<ConversationListItemWithDetails
key={conversation.phoneNumber}
{...conversation}
onClick={openConversationExternal}
i18n={i18n}
/>
))}
</div>
) : null}
{haveContacts ? this.renderContacts(i18n('contactsHeader'), contacts) : null}
{haveContacts ? this.renderContacts(window.i18n('contactsHeader'), contacts) : null}
{haveMessages ? (
<div className="module-search-results__messages">
{hideMessagesHeader ? null : (
<div className="module-search-results__messages-header">{i18n('messagesHeader')}</div>
<div className="module-search-results__messages-header">
{window.i18n('messagesHeader')}
</div>
)}
{messages.map(message => (
<MessageSearchResult
key={message.id}
{...message}
onClick={openConversationExternal}
i18n={i18n}
/>
))}
</div>
@ -79,7 +75,7 @@ export class SearchResults extends React.Component<Props> {
);
}
private renderContacts(header: string, items: Array<ConversationListItemProps>) {
const { i18n, openConversationExternal } = this.props;
const { openConversationExternal } = this.props;
return (
<div className="module-search-results__contacts">
@ -89,7 +85,6 @@ export class SearchResults extends React.Component<Props> {
key={contact.phoneNumber}
{...contact}
onClick={openConversationExternal}
i18n={i18n}
/>
))}
</div>

View File

@ -58,7 +58,6 @@ export class AttachmentList extends React.Component<Props> {
<Image
key={imageKey}
alt={window.i18n('stagedImageAttachment', [attachment.fileName])}
i18n={window.i18n}
attachment={attachment}
softCorners={true}
playIconOverlay={isVideoAttachment(attachment)}
@ -78,7 +77,6 @@ export class AttachmentList extends React.Component<Props> {
<StagedGenericAttachment
key={genericKey}
attachment={attachment}
i18n={window.i18n}
onClose={onCloseAttachment}
/>
);

View File

@ -2,13 +2,11 @@ import React from 'react';
import classNames from 'classnames';
import { Emojify } from './Emojify';
import { LocalizerType } from '../../types/Util';
type Props = {
phoneNumber: string;
name?: string;
profileName?: string;
i18n: LocalizerType;
module?: string;
boldProfileName?: Boolean;
compact?: Boolean;
@ -20,7 +18,6 @@ export const ContactName = (props: Props) => {
phoneNumber,
name,
profileName,
i18n,
module,
boldProfileName,
compact,
@ -35,16 +32,16 @@ export const ContactName = (props: Props) => {
fontWeight: 'bold',
}
: {}) as React.CSSProperties;
const textProfile = profileName || name || i18n('anonymous');
const textProfile = profileName || name || window.i18n('anonymous');
const profileElement = shouldShowProfile ? (
<span style={styles} className={`${prefix}__profile-name`}>
<Emojify text={textProfile} i18n={i18n} />
<Emojify text={textProfile} />
</span>
) : null;
const pubKeyElement = shouldShowPubkey ? (
<span className={`${prefix}__profile-number`}>
<Emojify text={title} i18n={i18n} />
<Emojify text={title} />
</span>
) : null;

View File

@ -1,11 +1,8 @@
import React from 'react';
import classNames from 'classnames';
import is from '@sindresorhus/is';
import { getRegex, SizeClassType } from '../../util/emoji';
import { LocalizerType, RenderTextCallbackType } from '../../types/Util';
import { RenderTextCallbackType } from '../../types/Util';
import { Twemoji } from 'react-emoji-render';
interface Props {
@ -14,7 +11,6 @@ interface Props {
sizeClass?: SizeClassType;
/** Allows you to customize now non-newlines are rendered. Simplest is just a <span>. */
renderNonEmoji?: RenderTextCallbackType;
i18n: LocalizerType;
isGroup?: boolean;
convoId: string;
}
@ -26,7 +22,7 @@ export class Emojify extends React.Component<Props> {
};
public render() {
const { text, sizeClass, renderNonEmoji, i18n, isGroup, convoId } = this.props;
const { text, sizeClass, renderNonEmoji, isGroup, convoId } = this.props;
const results: Array<any> = [];
const regex = getRegex();

View File

@ -26,7 +26,6 @@ type Props = {
export const GroupNotification = (props: Props) => {
function renderChange(change: Change) {
const { isMe, contacts, type, newName } = change;
const { i18n } = window;
const people = compact(
flatten(
@ -47,7 +46,7 @@ export const GroupNotification = (props: Props) => {
switch (type) {
case 'name':
return `${i18n('titleIsNow', [newName || ''])}.`;
return `${window.i18n('titleIsNow', [newName || ''])}.`;
case 'add':
if (!contacts || !contacts.length) {
throw new Error('Group update add is missing contacts');
@ -55,10 +54,10 @@ export const GroupNotification = (props: Props) => {
const joinKey = contacts.length > 1 ? 'multipleJoinedTheGroup' : 'joinedTheGroup';
return <Intl i18n={i18n} id={joinKey} components={[people]} />;
return <Intl id={joinKey} components={[people]} />;
case 'remove':
if (isMe) {
return i18n('youLeftTheGroup');
return window.i18n('youLeftTheGroup');
}
if (!contacts || !contacts.length) {
@ -67,10 +66,10 @@ export const GroupNotification = (props: Props) => {
const leftKey = contacts.length > 1 ? 'multipleLeftTheGroup' : 'leftTheGroup';
return <Intl i18n={i18n} id={leftKey} components={[people]} />;
return <Intl id={leftKey} components={[people]} />;
case 'kicked':
if (isMe) {
return i18n('youGotKickedFromGroup');
return window.i18n('youGotKickedFromGroup');
}
if (!contacts || !contacts.length) {
@ -79,9 +78,9 @@ export const GroupNotification = (props: Props) => {
const kickedKey = contacts.length > 1 ? 'multipleKickedFromTheGroup' : 'kickedFromTheGroup';
return <Intl i18n={i18n} id={kickedKey} components={[people]} />;
return <Intl id={kickedKey} components={[people]} />;
case 'general':
return i18n('updatedTheGroup');
return window.i18n('updatedTheGroup');
default:
throw missingCaseError(type);
}

View File

@ -2,7 +2,6 @@ import React from 'react';
import classNames from 'classnames';
import { Spinner } from '../basic/Spinner';
import { LocalizerType } from '../../types/Util';
import { AttachmentType } from '../../types/Attachment';
import { useEncryptedFileFetch } from '../../hooks/useEncryptedFileFetch';
@ -29,7 +28,6 @@ type Props = {
playIconOverlay?: boolean;
softCorners?: boolean;
i18n: LocalizerType;
onClick?: (attachment: AttachmentType) => void;
onClickClose?: (attachment: AttachmentType) => void;
onError?: () => void;
@ -48,7 +46,6 @@ export const Image = (props: Props) => {
curveTopRight,
darkOverlay,
height,
i18n,
onClick,
onClickClose,
onError,
@ -114,7 +111,7 @@ export const Image = (props: Props) => {
<img
className="module-image__caption-icon"
src="images/caption-shadow.svg"
alt={i18n('imageCaptionIconAlt')}
alt={window.i18n('imageCaptionIconAlt')}
/>
) : null}
<div

View File

@ -13,16 +13,12 @@ import {
import { Image } from './Image';
import { LocalizerType } from '../../types/Util';
type Props = {
attachments: Array<AttachmentType>;
withContentAbove?: boolean;
withContentBelow?: boolean;
bottomOverlay?: boolean;
i18n: LocalizerType;
onError: () => void;
onClickAttachment?: (attachment: AttachmentType) => void;
};
@ -32,7 +28,6 @@ export const ImageGrid = (props: Props) => {
const {
attachments,
bottomOverlay,
i18n,
onError,
onClickAttachment,
withContentAbove,
@ -58,8 +53,7 @@ export const ImageGrid = (props: Props) => {
return (
<div className={classNames('module-image-grid', 'module-image-grid--one-image')}>
<Image
alt={getAlt(attachments[0], i18n)}
i18n={i18n}
alt={getAlt(attachments[0])}
bottomOverlay={withBottomOverlay}
curveTopLeft={curveTopLeft}
curveTopRight={curveTopRight}
@ -81,8 +75,7 @@ export const ImageGrid = (props: Props) => {
return (
<div className="module-image-grid">
<Image
alt={getAlt(attachments[0], i18n)}
i18n={i18n}
alt={getAlt(attachments[0])}
attachment={attachments[0]}
bottomOverlay={withBottomOverlay}
curveTopLeft={curveTopLeft}
@ -95,8 +88,7 @@ export const ImageGrid = (props: Props) => {
onError={onError}
/>
<Image
alt={getAlt(attachments[1], i18n)}
i18n={i18n}
alt={getAlt(attachments[1])}
bottomOverlay={withBottomOverlay}
curveTopRight={curveTopRight}
curveBottomRight={curveBottomRight}
@ -116,8 +108,7 @@ export const ImageGrid = (props: Props) => {
return (
<div className="module-image-grid">
<Image
alt={getAlt(attachments[0], i18n)}
i18n={i18n}
alt={getAlt(attachments[0])}
bottomOverlay={withBottomOverlay}
curveTopLeft={curveTopLeft}
curveBottomLeft={curveBottomLeft}
@ -131,8 +122,7 @@ export const ImageGrid = (props: Props) => {
/>
<div className="module-image-grid__column">
<Image
alt={getAlt(attachments[1], i18n)}
i18n={i18n}
alt={getAlt(attachments[1])}
curveTopRight={curveTopRight}
height={99}
width={99}
@ -143,8 +133,7 @@ export const ImageGrid = (props: Props) => {
onError={onError}
/>
<Image
alt={getAlt(attachments[2], i18n)}
i18n={i18n}
alt={getAlt(attachments[2])}
bottomOverlay={withBottomOverlay}
curveBottomRight={curveBottomRight}
height={99}
@ -166,8 +155,7 @@ export const ImageGrid = (props: Props) => {
<div className="module-image-grid__column">
<div className="module-image-grid__row">
<Image
alt={getAlt(attachments[0], i18n)}
i18n={i18n}
alt={getAlt(attachments[0])}
curveTopLeft={curveTopLeft}
attachment={attachments[0]}
playIconOverlay={isVideoAttachment(attachments[0])}
@ -178,8 +166,7 @@ export const ImageGrid = (props: Props) => {
onError={onError}
/>
<Image
alt={getAlt(attachments[1], i18n)}
i18n={i18n}
alt={getAlt(attachments[1])}
curveTopRight={curveTopRight}
playIconOverlay={isVideoAttachment(attachments[1])}
height={149}
@ -192,8 +179,7 @@ export const ImageGrid = (props: Props) => {
</div>
<div className="module-image-grid__row">
<Image
alt={getAlt(attachments[2], i18n)}
i18n={i18n}
alt={getAlt(attachments[2])}
bottomOverlay={withBottomOverlay}
curveBottomLeft={curveBottomLeft}
playIconOverlay={isVideoAttachment(attachments[2])}
@ -205,8 +191,7 @@ export const ImageGrid = (props: Props) => {
onError={onError}
/>
<Image
alt={getAlt(attachments[3], i18n)}
i18n={i18n}
alt={getAlt(attachments[3])}
bottomOverlay={withBottomOverlay}
curveBottomRight={curveBottomRight}
playIconOverlay={isVideoAttachment(attachments[3])}
@ -231,8 +216,7 @@ export const ImageGrid = (props: Props) => {
<div className="module-image-grid__column">
<div className="module-image-grid__row">
<Image
alt={getAlt(attachments[0], i18n)}
i18n={i18n}
alt={getAlt(attachments[0])}
curveTopLeft={curveTopLeft}
attachment={attachments[0]}
playIconOverlay={isVideoAttachment(attachments[0])}
@ -243,8 +227,7 @@ export const ImageGrid = (props: Props) => {
onError={onError}
/>
<Image
alt={getAlt(attachments[1], i18n)}
i18n={i18n}
alt={getAlt(attachments[1])}
curveTopRight={curveTopRight}
playIconOverlay={isVideoAttachment(attachments[1])}
height={149}
@ -257,8 +240,7 @@ export const ImageGrid = (props: Props) => {
</div>
<div className="module-image-grid__row">
<Image
alt={getAlt(attachments[2], i18n)}
i18n={i18n}
alt={getAlt(attachments[2])}
bottomOverlay={withBottomOverlay}
curveBottomLeft={curveBottomLeft}
playIconOverlay={isVideoAttachment(attachments[2])}
@ -270,8 +252,7 @@ export const ImageGrid = (props: Props) => {
onError={onError}
/>
<Image
alt={getAlt(attachments[3], i18n)}
i18n={i18n}
alt={getAlt(attachments[3])}
bottomOverlay={withBottomOverlay}
playIconOverlay={isVideoAttachment(attachments[3])}
height={99}
@ -282,8 +263,7 @@ export const ImageGrid = (props: Props) => {
onError={onError}
/>
<Image
alt={getAlt(attachments[4], i18n)}
i18n={i18n}
alt={getAlt(attachments[4])}
bottomOverlay={withBottomOverlay}
curveBottomRight={curveBottomRight}
playIconOverlay={isVideoAttachment(attachments[4])}

View File

@ -216,7 +216,6 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> {
withContentAbove={withContentAbove}
withContentBelow={withContentBelow}
bottomOverlay={!collapseMetadata}
i18n={window.i18n}
onError={this.handleImageErrorBound}
onClickAttachment={(attachment: AttachmentType) => {
if (multiSelectMode) {
@ -358,7 +357,6 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> {
withContentAbove={withContentAbove}
withContentBelow={true}
onError={this.handleImageErrorBound}
i18n={window.i18n}
/>
) : null}
<div
@ -380,7 +378,6 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> {
url={first.image.url}
attachment={first.image}
onError={this.handleImageErrorBound}
i18n={window.i18n}
/>
</div>
) : null}
@ -423,7 +420,6 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> {
return (
<Quote
i18n={window.i18n}
onClick={(e: any) => {
e.preventDefault();
e.stopPropagation();
@ -519,7 +515,6 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> {
>
<MessageBody
text={contents || ''}
i18n={window.i18n}
isGroup={conversationType === 'group'}
convoId={convoId}
disableLinks={multiSelectMode}
@ -872,7 +867,6 @@ class MessageInner extends React.PureComponent<MessageRegularProps, State> {
name={authorName}
profileName={authorProfileName}
module="module-message__author"
i18n={window.i18n}
boldProfileName={true}
shouldShowPubkey={Boolean(isPublic)}
/>

View File

@ -6,7 +6,7 @@ import { AddNewLines } from './AddNewLines';
import { AddMentions } from './AddMentions';
import { Linkify } from './Linkify';
import { LocalizerType, RenderTextCallbackType } from '../../types/Util';
import { RenderTextCallbackType } from '../../types/Util';
interface Props {
text: string;
@ -15,7 +15,6 @@ interface Props {
/** If set, links will be left alone instead of turned into clickable `<a>` tags. */
disableLinks?: boolean;
isGroup?: boolean;
i18n: LocalizerType;
convoId: string;
}
@ -44,7 +43,6 @@ const renderNewLines: RenderTextCallbackType = ({
};
const renderEmoji = ({
i18n,
text,
key,
sizeClass,
@ -52,7 +50,6 @@ const renderEmoji = ({
isGroup,
convoId,
}: {
i18n: LocalizerType;
text: string;
key: number;
sizeClass?: SizeClassType;
@ -61,7 +58,6 @@ const renderEmoji = ({
convoId?: string;
}) => (
<Emojify
i18n={i18n}
key={key}
text={text}
sizeClass={sizeClass}
@ -87,13 +83,12 @@ export class MessageBody extends React.Component<Props> {
}
public render() {
const { text, disableJumbomoji, disableLinks, i18n, isGroup, convoId } = this.props;
const { text, disableJumbomoji, disableLinks, isGroup, convoId } = this.props;
const sizeClass = disableJumbomoji ? undefined : getSizeClass(text);
if (disableLinks) {
return this.renderJsxSelectable(
renderEmoji({
i18n,
text,
sizeClass,
key: 0,
@ -109,7 +104,6 @@ export class MessageBody extends React.Component<Props> {
text={text}
renderNonLink={({ key, text: nonLinkText }) => {
return renderEmoji({
i18n,
text: nonLinkText,
sizeClass,
key,

View File

@ -60,7 +60,6 @@ export class MessageDetail extends React.Component<Props> {
}
public renderContact(contact: Contact) {
const { i18n } = window;
const errors = contact.errors || [];
const statusComponent = !contact.isOutgoingKeyError ? (
@ -81,7 +80,6 @@ export class MessageDetail extends React.Component<Props> {
phoneNumber={contact.phoneNumber}
name={contact.name}
profileName={contact.profileName}
i18n={i18n}
shouldShowPubkey={true}
/>
</div>

View File

@ -7,7 +7,6 @@ import * as MIME from '../../../ts/types/MIME';
import * as GoogleChrome from '../../../ts/util/GoogleChrome';
import { MessageBody } from './MessageBody';
import { ColorType, LocalizerType } from '../../types/Util';
import { ContactName } from './ContactName';
import { PubKey } from '../../session/types';
import { ConversationTypeEnum } from '../../models/conversation';
@ -19,7 +18,6 @@ interface QuoteProps {
authorPhoneNumber: string;
authorProfileName?: string;
authorName?: string;
i18n: LocalizerType;
isFromMe: boolean;
isIncoming: boolean;
conversationType: ConversationTypeEnum;
@ -66,25 +64,23 @@ function getObjectUrl(thumbnail: Attachment | undefined): string | undefined {
}
function getTypeLabel({
i18n,
contentType,
isVoiceMessage,
}: {
i18n: LocalizerType;
contentType: MIME.MIMEType;
isVoiceMessage: boolean;
}): string | undefined {
if (GoogleChrome.isVideoTypeSupported(contentType)) {
return i18n('video');
return window.i18n('video');
}
if (GoogleChrome.isImageTypeSupported(contentType)) {
return i18n('photo');
return window.i18n('photo');
}
if (MIME.isAudio(contentType) && isVoiceMessage) {
return i18n('voiceMessage');
return window.i18n('voiceMessage');
}
if (MIME.isAudio(contentType)) {
return i18n('audio');
return window.i18n('audio');
}
return;
@ -109,7 +105,7 @@ export const QuoteIcon = (props: any) => {
};
export const QuoteImage = (props: any) => {
const { url, i18n, icon, contentType, handleImageErrorBound } = props;
const { url, icon, contentType, handleImageErrorBound } = props;
const { loading, urlToLoad } = useEncryptedFileFetch(url, contentType);
const srcData = !loading ? urlToLoad : '';
@ -129,7 +125,7 @@ export const QuoteImage = (props: any) => {
return (
<div className="module-quote__icon-container">
<img src={srcData} alt={i18n('quoteThumbnailAlt')} onError={handleImageErrorBound} />
<img src={srcData} alt={window.i18n('quoteThumbnailAlt')} onError={handleImageErrorBound} />
{iconElement}
</div>
);
@ -168,7 +164,7 @@ export const QuoteGenericFile = (props: any) => {
};
export const QuoteIconContainer = (props: any) => {
const { attachment, i18n, imageBroken, handleImageErrorBound } = props;
const { attachment, imageBroken, handleImageErrorBound } = props;
if (!attachment) {
return null;
@ -179,7 +175,7 @@ export const QuoteIconContainer = (props: any) => {
if (GoogleChrome.isVideoTypeSupported(contentType)) {
return objectUrl && !imageBroken ? (
<QuoteImage url={objectUrl} i18n={i18n} icon={'play'} />
<QuoteImage url={objectUrl} icon={'play'} />
) : (
<QuoteIcon icon="movie" />
);
@ -188,7 +184,6 @@ export const QuoteIconContainer = (props: any) => {
return objectUrl && !imageBroken ? (
<QuoteImage
url={objectUrl}
i18n={i18n}
contentType={contentType}
handleImageErrorBound={handleImageErrorBound}
/>
@ -203,7 +198,7 @@ export const QuoteIconContainer = (props: any) => {
};
export const QuoteText = (props: any) => {
const { i18n, text, attachment, isIncoming, conversationType, convoId } = props;
const { text, attachment, isIncoming, conversationType, convoId } = props;
const isGroup = conversationType === ConversationTypeEnum.GROUP;
if (text) {
@ -215,13 +210,7 @@ export const QuoteText = (props: any) => {
isIncoming ? 'module-quote__primary__text--incoming' : null
)}
>
<MessageBody
isGroup={isGroup}
convoId={convoId}
text={text}
disableLinks={true}
i18n={i18n}
/>
<MessageBody isGroup={isGroup} convoId={convoId} text={text} disableLinks={true} />
</div>
);
}
@ -232,7 +221,7 @@ export const QuoteText = (props: any) => {
const { contentType, isVoiceMessage } = attachment;
const typeLabel = getTypeLabel({ i18n, contentType, isVoiceMessage });
const typeLabel = getTypeLabel({ contentType, isVoiceMessage });
if (typeLabel) {
return (
<div
@ -254,7 +243,6 @@ export const QuoteAuthor = (props: any) => {
authorProfileName,
authorPhoneNumber,
authorName,
i18n,
isFromMe,
isIncoming,
isPublic,
@ -268,13 +256,12 @@ export const QuoteAuthor = (props: any) => {
)}
>
{isFromMe ? (
i18n('you')
window.i18n('you')
) : (
<ContactName
phoneNumber={PubKey.shorten(authorPhoneNumber)}
name={authorName}
profileName={authorProfileName}
i18n={i18n}
compact={true}
shouldShowPubkey={Boolean(isPublic)}
/>
@ -284,7 +271,7 @@ export const QuoteAuthor = (props: any) => {
};
export const QuoteReferenceWarning = (props: any) => {
const { i18n, isIncoming, referencedMessageNotFound } = props;
const { isIncoming, referencedMessageNotFound } = props;
if (!referencedMessageNotFound) {
return null;
@ -309,7 +296,7 @@ export const QuoteReferenceWarning = (props: any) => {
isIncoming ? 'module-quote__reference-warning__text--incoming' : null
)}
>
{i18n('originalMessageNotFound')}
{window.i18n('originalMessageNotFound')}
</div>
</div>
);

View File

@ -1,12 +1,10 @@
import React from 'react';
import { AttachmentType, getExtensionForDisplay } from '../../types/Attachment';
import { LocalizerType } from '../../types/Util';
interface Props {
attachment: AttachmentType;
onClose: (attachment: AttachmentType) => void;
i18n: LocalizerType;
}
export class StagedGenericAttachment extends React.Component<Props> {

View File

@ -20,7 +20,6 @@ export const StagedLinkPreview = (props: Props) => {
const { isLoaded, onClose, title, image, domain, description, url } = props;
const isImage = image && isImageAttachment(image);
const i18n = window.i18n;
if (isLoaded && !(title && domain)) {
return <></>;
}
@ -33,18 +32,17 @@ export const StagedLinkPreview = (props: Props) => {
)}
>
{!isLoaded ? (
<div className="module-staged-link-preview__loading">{i18n('loading')}</div>
<div className="module-staged-link-preview__loading">{window.i18n('loading')}</div>
) : null}
{isLoaded && image && isImage ? (
<div className="module-staged-link-preview__icon-container">
<Image
alt={i18n('stagedPreviewThumbnail', [domain])}
alt={window.i18n('stagedPreviewThumbnail', [domain])}
softCorners={true}
height={72}
width={72}
url={image.url}
attachment={image}
i18n={i18n}
/>
</div>
) : null}
@ -65,7 +63,7 @@ export const StagedLinkPreview = (props: Props) => {
onClick={() => {
onClose(url || '');
}}
aria-label={i18n('close')}
aria-label={window.i18n('close')}
/>
</div>
);

View File

@ -28,7 +28,7 @@ export const TimerNotification = (props: Props) => {
switch (type) {
case 'fromOther':
return <Intl i18n={window.i18n} id={changeKey} components={[contact, timespan]} />;
return <Intl id={changeKey} components={[contact, timespan]} />;
case 'fromMe':
return disabled
? window.i18n('youDisabledDisappearingMessages')

View File

@ -68,7 +68,7 @@ export const Timestamp = (props: Props) => {
let dateString;
if (messageAgeInDays > daysBeforeRelativeTiming) {
dateString = formatRelativeTime(timestamp, { i18n: window.i18n, extended });
dateString = formatRelativeTime(timestamp, { extended });
} else {
dateString = moment(timestamp).fromNow();
// Prevent times reading "NOW AGO"

View File

@ -1,19 +1,16 @@
import React from 'react';
import classNames from 'classnames';
import { LocalizerType } from '../../types/Util';
interface Props {
i18n: LocalizerType;
color?: string;
}
export class TypingAnimation extends React.Component<Props> {
public render() {
const { i18n, color } = this.props;
const { color } = this.props;
return (
<div className="module-typing-animation" title={i18n('typingAlt')}>
<div className="module-typing-animation" title={window.i18n('typingAlt')}>
<div
className={classNames(
'module-typing-animation__dot',

View File

@ -31,7 +31,7 @@ export const TypingBubble = (props: TypingBubbleProps) => {
return (
<TypingBubbleContainer {...props}>
<TypingAnimation i18n={window.i18n} />
<TypingAnimation />
</TypingBubbleContainer>
);
};

View File

@ -6,7 +6,6 @@ import { SessionButton, SessionButtonColor, SessionButtonType } from '../session
import { ContactType, SessionMemberListItem } from '../session/SessionMemberListItem';
import { DefaultTheme } from 'styled-components';
import { ToastUtils } from '../../session/utils';
import { LocalizerType } from '../../types/Util';
import autoBind from 'auto-bind';
import { ConversationController } from '../../session/conversations';
@ -25,7 +24,6 @@ interface Props {
existingZombies: Array<string>;
admins: Array<string>; // used for closed group
i18n: LocalizerType;
onSubmit: (membersLeft: Array<string>) => void;
onClose: () => void;
theme: DefaultTheme;

View File

@ -5,10 +5,8 @@ import { ItemClickEvent } from './types/ItemClickEvent';
import { MediaGridItem } from './MediaGridItem';
import { MediaItemType } from '../../LightboxGallery';
import { missingCaseError } from '../../../util/missingCaseError';
import { LocalizerType } from '../../../types/Util';
interface Props {
i18n: LocalizerType;
type: 'media' | 'documents';
mediaItems: Array<MediaItemType>;
onItemClick?: (event: ItemClickEvent) => void;
@ -28,7 +26,7 @@ export class AttachmentSection extends React.Component<Props> {
}
private renderItems() {
const { i18n, mediaItems, type } = this.props;
const { mediaItems, type } = this.props;
return mediaItems.map((mediaItem, position, array) => {
const shouldShowSeparator = position < array.length - 1;
@ -38,12 +36,7 @@ export class AttachmentSection extends React.Component<Props> {
switch (type) {
case 'media':
return (
<MediaGridItem
key={`${message.id}-${index}`}
mediaItem={mediaItem}
onClick={onClick}
i18n={i18n}
/>
<MediaGridItem key={`${message.id}-${index}`} mediaItem={mediaItem} onClick={onClick} />
);
case 'documents':
return (

View File

@ -114,7 +114,6 @@ export class MediaGallery extends React.Component<Props, State> {
<div className="module-media-gallery__sections">
<AttachmentSection
key="mediaItems"
i18n={window.i18n}
type={type}
mediaItems={mediaItems}
onItemClick={onItemClick}

View File

@ -2,18 +2,17 @@ import React, { useState } from 'react';
import classNames from 'classnames';
import { isImageTypeSupported, isVideoTypeSupported } from '../../../util/GoogleChrome';
import { LocalizerType } from '../../../types/Util';
import { MediaItemType } from '../../LightboxGallery';
import { useEncryptedFileFetch } from '../../../hooks/useEncryptedFileFetch';
type Props = {
mediaItem: MediaItemType;
onClick?: () => void;
i18n: LocalizerType;
};
const MediaGridItemContent = (props: Props) => {
const { mediaItem, i18n } = props;
const { mediaItem } = props;
const i18n = window.i18n;
const { attachment, contentType } = mediaItem;
const urlToDecrypt = mediaItem.thumbnailObjectUrl || '';

View File

@ -144,12 +144,12 @@ const showResetSessionIDDialogIfNeeded = async () => {
const cleanUpMediasInterval = DURATION.MINUTES * 30;
const setupTheme = (dispatch: Dispatch<any>) => {
const setupTheme = () => {
const theme = window.Events.getThemeSetting();
window.setTheme(theme);
const newThemeObject = theme === 'dark' ? darkTheme : lightTheme;
dispatch(applyTheme(newThemeObject));
window?.inboxStore?.dispatch(applyTheme(newThemeObject));
};
// Do this only if we created a new Session ID, or if we already received the initial configuration message
@ -273,7 +273,7 @@ const triggerAvatarReUploadIfNeeded = async () => {
/**
* This function is called only once: on app startup with a logged in user
*/
const doAppStartUp = (dispatch: Dispatch<any>) => {
const doAppStartUp = () => {
if (window.lokiFeatureFlags.useOnionRequests || window.lokiFeatureFlags.useFileOnionRequests) {
// Initialize paths for onion requests
void OnionPaths.buildNewOnionPathsOneAtATime();
@ -282,7 +282,7 @@ const doAppStartUp = (dispatch: Dispatch<any>) => {
// init the messageQueue. In the constructor, we add all not send messages
// this call does nothing except calling the constructor, which will continue sending message in the pipeline
void getMessageQueue().processAllPending();
void setupTheme(dispatch);
void setupTheme();
// keep that one to make sure our users upgrade to new sessionIDS
void showResetSessionIDDialogIfNeeded();
@ -310,7 +310,6 @@ const doAppStartUp = (dispatch: Dispatch<any>) => {
* The panel with buttons to switch between the message/contact/settings/theme views
*/
export const ActionsPanel = () => {
const dispatch = useDispatch();
const [startCleanUpMedia, setStartCleanUpMedia] = useState(false);
const ourPrimaryConversation = useSelector(getOurPrimaryConversation);
@ -318,7 +317,7 @@ export const ActionsPanel = () => {
// this maxi useEffect is called only once: when the component is mounted.
// For the action panel, it means this is called only one per app start/with a user loggedin
useEffect(() => {
void doAppStartUp(dispatch);
void doAppStartUp();
}, []);
// wait for cleanUpMediasInterval and then start cleaning up medias

View File

@ -42,7 +42,6 @@ export class LeftPaneContactSection extends React.Component<Props> {
key={item.id}
style={style}
{...item}
i18n={window.i18n}
onClick={this.props.openConversationExternal}
/>
);

View File

@ -93,7 +93,6 @@ export class LeftPaneMessageSection extends React.Component<Props, State> {
style={style}
{...conversation}
onClick={openConversationExternal}
i18n={window.i18n}
/>
);
};
@ -108,7 +107,6 @@ export class LeftPaneMessageSection extends React.Component<Props, State> {
{...searchResults}
contacts={contacts}
openConversationExternal={openConversationExternal}
i18n={window.i18n}
/>
);
}

View File

@ -154,7 +154,7 @@ class SessionPasswordModalInner extends React.Component<Props, State> {
*/
private validatePassword(firstPassword: string) {
// if user did not fill the first password field, we can't do anything
const errorFirstInput = PasswordUtil.validatePassword(firstPassword, window.i18n);
const errorFirstInput = PasswordUtil.validatePassword(firstPassword);
if (errorFirstInput !== null) {
this.setState({
error: errorFirstInput,

View File

@ -83,8 +83,7 @@ export const SessionQuotedMessageComposition = (props: Props) => {
{hasImageAttachment && (
<Image
alt={getAlt(firstImageAttachment, window.i18n)}
i18n={window.i18n}
alt={getAlt(firstImageAttachment)}
attachment={firstImageAttachment}
height={100}
width={100}

View File

@ -93,8 +93,7 @@ export const ConversationHeaderMenu = (props: PropsConversationHeaderMenu) => {
left,
isBlocked,
timerOptions,
onSetDisappearingMessages,
window.i18n
onSetDisappearingMessages
)}
{getNotificationForConvoMenuItem(
isKickedFromGroup,
@ -102,31 +101,22 @@ export const ConversationHeaderMenu = (props: PropsConversationHeaderMenu) => {
isBlocked,
notificationForConvo,
currentNotificationSetting,
onSetNotificationForConvo,
window.i18n
onSetNotificationForConvo
)}
{getBlockMenuItem(isMe, isPrivate, isBlocked, onBlockUser, onUnblockUser, window.i18n)}
{getBlockMenuItem(isMe, isPrivate, isBlocked, onBlockUser, onUnblockUser)}
{getCopyMenuItem(isPublic, isGroup, onCopyPublicKey, window.i18n)}
{getMarkAllReadMenuItem(onMarkAllRead, window.i18n)}
{getChangeNicknameMenuItem(isMe, onChangeNickname, isGroup, window.i18n)}
{getClearNicknameMenuItem(isMe, hasNickname, onClearNickname, isGroup, window.i18n)}
{getDeleteMessagesMenuItem(isPublic, onDeleteMessages, window.i18n)}
{getAddModeratorsMenuItem(isAdmin, isKickedFromGroup, onAddModerators, window.i18n)}
{getRemoveModeratorsMenuItem(isAdmin, isKickedFromGroup, onRemoveModerators, window.i18n)}
{getUpdateGroupNameMenuItem(isAdmin, isKickedFromGroup, left, onUpdateGroupName, window.i18n)}
{getLeaveGroupMenuItem(isKickedFromGroup, left, isGroup, isPublic, onLeaveGroup, window.i18n)}
{getCopyMenuItem(isPublic, isGroup, onCopyPublicKey)}
{getMarkAllReadMenuItem(onMarkAllRead)}
{getChangeNicknameMenuItem(isMe, onChangeNickname, isGroup)}
{getClearNicknameMenuItem(isMe, hasNickname, onClearNickname, isGroup)}
{getDeleteMessagesMenuItem(isPublic, onDeleteMessages)}
{getAddModeratorsMenuItem(isAdmin, isKickedFromGroup, onAddModerators)}
{getRemoveModeratorsMenuItem(isAdmin, isKickedFromGroup, onRemoveModerators)}
{getUpdateGroupNameMenuItem(isAdmin, isKickedFromGroup, left, onUpdateGroupName)}
{getLeaveGroupMenuItem(isKickedFromGroup, left, isGroup, isPublic, onLeaveGroup)}
{/* TODO: add delete group */}
{getInviteContactMenuItem(isGroup, isPublic, onInviteContacts, window.i18n)}
{getDeleteContactMenuItem(
isMe,
isGroup,
isPublic,
left,
isKickedFromGroup,
onDeleteContact,
window.i18n
)}
{getInviteContactMenuItem(isGroup, isPublic, onInviteContacts)}
{getDeleteContactMenuItem(isMe, isGroup, isPublic, left, isKickedFromGroup, onDeleteContact)}
</Menu>
);
};

View File

@ -67,26 +67,17 @@ export const ConversationListItemContextMenu = (props: PropsContextConversationI
type === ConversationTypeEnum.PRIVATE,
isBlocked,
onBlockContact,
onUnblockContact,
window.i18n
onUnblockContact
)}
{getCopyMenuItem(isPublic, isGroup, onCopyPublicKey, window.i18n)}
{getMarkAllReadMenuItem(onMarkAllRead, window.i18n)}
{getChangeNicknameMenuItem(isMe, onChangeNickname, isGroup, window.i18n)}
{getClearNicknameMenuItem(isMe, hasNickname, onClearNickname, isGroup, window.i18n)}
{getCopyMenuItem(isPublic, isGroup, onCopyPublicKey)}
{getMarkAllReadMenuItem(onMarkAllRead)}
{getChangeNicknameMenuItem(isMe, onChangeNickname, isGroup)}
{getClearNicknameMenuItem(isMe, hasNickname, onClearNickname, isGroup)}
{getDeleteMessagesMenuItem(isPublic, onDeleteMessages, window.i18n)}
{getInviteContactMenuItem(isGroup, isPublic, onInviteContacts, window.i18n)}
{getDeleteContactMenuItem(
isMe,
isGroup,
isPublic,
left,
isKickedFromGroup,
onDeleteContact,
window.i18n
)}
{getLeaveGroupMenuItem(isKickedFromGroup, left, isGroup, isPublic, onLeaveGroup, window.i18n)}
{getDeleteMessagesMenuItem(isPublic, onDeleteMessages)}
{getInviteContactMenuItem(isGroup, isPublic, onInviteContacts)}
{getDeleteContactMenuItem(isMe, isGroup, isPublic, left, isKickedFromGroup, onDeleteContact)}
{getLeaveGroupMenuItem(isKickedFromGroup, left, isGroup, isPublic, onLeaveGroup)}
</Menu>
);
};

View File

@ -1,11 +1,7 @@
import React from 'react';
import { LocalizerType } from '../../../types/Util';
import { NotificationForConvoOption, TimerOption } from '../../conversation/ConversationHeader';
import { Item, Submenu } from 'react-contexify';
import {
ConversationNotificationSetting,
ConversationNotificationSettingType,
} from '../../../models/conversation';
import { ConversationNotificationSettingType } from '../../../models/conversation';
function showTimerOptions(
isPublic: boolean,
@ -90,11 +86,10 @@ function showInviteContact(isGroup: boolean, isPublic: boolean): boolean {
export function getInviteContactMenuItem(
isGroup: boolean | undefined,
isPublic: boolean | undefined,
action: any,
i18n: LocalizerType
action: any
): JSX.Element | null {
if (showInviteContact(Boolean(isGroup), Boolean(isPublic))) {
return <Item onClick={action}>{i18n('inviteContacts')}</Item>;
return <Item onClick={action}>{window.i18n('inviteContacts')}</Item>;
}
return null;
}
@ -105,8 +100,7 @@ export function getDeleteContactMenuItem(
isPublic: boolean | undefined,
isLeft: boolean | undefined,
isKickedFromGroup: boolean | undefined,
action: any,
i18n: LocalizerType
action: any
): JSX.Element | null {
if (
showDeleteContact(
@ -118,9 +112,9 @@ export function getDeleteContactMenuItem(
)
) {
if (isPublic) {
return <Item onClick={action}>{i18n('leaveGroup')}</Item>;
return <Item onClick={action}>{window.i18n('leaveGroup')}</Item>;
}
return <Item onClick={action}>{i18n('delete')}</Item>;
return <Item onClick={action}>{window.i18n('delete')}</Item>;
}
return null;
}
@ -130,13 +124,12 @@ export function getLeaveGroupMenuItem(
left: boolean | undefined,
isGroup: boolean | undefined,
isPublic: boolean | undefined,
action: any,
i18n: LocalizerType
action: any
): JSX.Element | null {
if (
showLeaveGroup(Boolean(isKickedFromGroup), Boolean(left), Boolean(isGroup), Boolean(isPublic))
) {
return <Item onClick={action}>{i18n('leaveGroup')}</Item>;
return <Item onClick={action}>{window.i18n('leaveGroup')}</Item>;
}
return null;
}
@ -145,11 +138,10 @@ export function getUpdateGroupNameMenuItem(
isAdmin: boolean | undefined,
isKickedFromGroup: boolean | undefined,
left: boolean | undefined,
action: any,
i18n: LocalizerType
action: any
): JSX.Element | null {
if (showUpdateGroupName(Boolean(isAdmin), Boolean(isKickedFromGroup), Boolean(left))) {
return <Item onClick={action}>{i18n('editGroup')}</Item>;
return <Item onClick={action}>{window.i18n('editGroup')}</Item>;
}
return null;
}
@ -157,11 +149,10 @@ export function getUpdateGroupNameMenuItem(
export function getRemoveModeratorsMenuItem(
isAdmin: boolean | undefined,
isKickedFromGroup: boolean | undefined,
action: any,
i18n: LocalizerType
action: any
): JSX.Element | null {
if (showRemoveModerators(Boolean(isAdmin), Boolean(isKickedFromGroup))) {
return <Item onClick={action}>{i18n('removeModerators')}</Item>;
return <Item onClick={action}>{window.i18n('removeModerators')}</Item>;
}
return null;
}
@ -169,11 +160,10 @@ export function getRemoveModeratorsMenuItem(
export function getAddModeratorsMenuItem(
isAdmin: boolean | undefined,
isKickedFromGroup: boolean | undefined,
action: any,
i18n: LocalizerType
action: any
): JSX.Element | null {
if (showAddModerators(Boolean(isAdmin), Boolean(isKickedFromGroup))) {
return <Item onClick={action}>{i18n('addModerators')}</Item>;
return <Item onClick={action}>{window.i18n('addModerators')}</Item>;
}
return null;
}
@ -181,18 +171,17 @@ export function getAddModeratorsMenuItem(
export function getCopyMenuItem(
isPublic: boolean | undefined,
isGroup: boolean | undefined,
action: any,
i18n: LocalizerType
action: any
): JSX.Element | null {
if (showCopyId(Boolean(isPublic), Boolean(isGroup))) {
const copyIdLabel = isPublic ? i18n('copyOpenGroupURL') : i18n('copySessionID');
const copyIdLabel = isPublic ? window.i18n('copyOpenGroupURL') : window.i18n('copySessionID');
return <Item onClick={action}>{copyIdLabel}</Item>;
}
return null;
}
export function getMarkAllReadMenuItem(action: any, i18n: LocalizerType): JSX.Element | null {
return <Item onClick={action}>{i18n('markAllAsRead')}</Item>;
export function getMarkAllReadMenuItem(action: any): JSX.Element | null {
return <Item onClick={action}>{window.i18n('markAllAsRead')}</Item>;
}
export function getDisappearingMenuItem(
@ -201,8 +190,7 @@ export function getDisappearingMenuItem(
left: boolean | undefined,
isBlocked: boolean | undefined,
timerOptions: Array<TimerOption>,
action: any,
i18n: LocalizerType
action: any
): JSX.Element | null {
if (
showTimerOptions(
@ -216,7 +204,7 @@ export function getDisappearingMenuItem(
return (
// Remove the && false to make context menu work with RTL support
<Submenu
label={i18n('disappearingMessages') as any}
label={window.i18n('disappearingMessages') as any}
// rtl={isRtlMode && false}
>
{(timerOptions || []).map(item => (
@ -241,15 +229,14 @@ export function getNotificationForConvoMenuItem(
isBlocked: boolean | undefined,
notificationForConvoOptions: Array<NotificationForConvoOption>,
currentNotificationSetting: ConversationNotificationSettingType,
action: (selected: ConversationNotificationSettingType) => any,
i18n: LocalizerType
action: (selected: ConversationNotificationSettingType) => any
): JSX.Element | null {
if (showNotificationConvo(Boolean(isKickedFromGroup), Boolean(left), Boolean(isBlocked))) {
// const isRtlMode = isRtlBody();
return (
// Remove the && false to make context menu work with RTL support
<Submenu
label={i18n('notificationForConvo') as any}
label={window.i18n('notificationForConvo') as any}
// rtl={isRtlMode && false}
>
{(notificationForConvoOptions || []).map(item => (
@ -277,11 +264,10 @@ export function isRtlBody(): boolean {
export function getShowMemberMenuItem(
isPublic: boolean | undefined,
isGroup: boolean | undefined,
action: any,
i18n: LocalizerType
action: any
): JSX.Element | null {
if (showMemberMenu(Boolean(isPublic), Boolean(isGroup))) {
return <Item onClick={action}>{i18n('groupMembers')}</Item>;
return <Item onClick={action}>{window.i18n('groupMembers')}</Item>;
}
return null;
}
@ -291,11 +277,10 @@ export function getBlockMenuItem(
isPrivate: boolean | undefined,
isBlocked: boolean | undefined,
actionBlock: any,
actionUnblock: any,
i18n: LocalizerType
actionUnblock: any
): JSX.Element | null {
if (showBlock(Boolean(isMe), Boolean(isPrivate))) {
const blockTitle = isBlocked ? i18n('unblockUser') : i18n('blockUser');
const blockTitle = isBlocked ? window.i18n('unblockUser') : window.i18n('blockUser');
const blockHandler = isBlocked ? actionUnblock : actionBlock;
return <Item onClick={blockHandler}>{blockTitle}</Item>;
}
@ -306,11 +291,10 @@ export function getClearNicknameMenuItem(
isMe: boolean | undefined,
hasNickname: boolean | undefined,
action: any,
isGroup: boolean | undefined,
i18n: LocalizerType
isGroup: boolean | undefined
): JSX.Element | null {
if (showClearNickname(Boolean(isMe), Boolean(hasNickname), Boolean(isGroup))) {
return <Item onClick={action}>{i18n('clearNickname')}</Item>;
return <Item onClick={action}>{window.i18n('clearNickname')}</Item>;
}
return null;
}
@ -318,22 +302,20 @@ export function getClearNicknameMenuItem(
export function getChangeNicknameMenuItem(
isMe: boolean | undefined,
action: any,
isGroup: boolean | undefined,
i18n: LocalizerType
isGroup: boolean | undefined
): JSX.Element | null {
if (showChangeNickname(Boolean(isMe), Boolean(isGroup))) {
return <Item onClick={action}>{i18n('changeNickname')}</Item>;
return <Item onClick={action}>{window.i18n('changeNickname')}</Item>;
}
return null;
}
export function getDeleteMessagesMenuItem(
isPublic: boolean | undefined,
action: any,
i18n: LocalizerType
action: any
): JSX.Element | null {
if (showDeleteMessages(Boolean(isPublic))) {
return <Item onClick={action}>{i18n('deleteMessages')}</Item>;
return <Item onClick={action}>{window.i18n('deleteMessages')}</Item>;
}
return null;
}

View File

@ -38,7 +38,7 @@ export function validatePassword(password: string, verifyPassword: string) {
};
}
const error = PasswordUtil.validatePassword(trimmedPassword, window.i18n);
const error = PasswordUtil.validatePassword(trimmedPassword);
if (error) {
return {
passwordErrorString: error,

View File

@ -1,4 +1,3 @@
import { LocalizerType } from '../../types/Util';
import { fromHexToArray } from '../utils/String';
export class PubKey {
@ -100,20 +99,17 @@ export class PubKey {
/**
* Returns a localized string of the error, or undefined in the given pubkey is valid.
*/
public static validateWithError(
pubkey: string,
i18n: LocalizerType = window.i18n
): string | undefined {
public static validateWithError(pubkey: string): string | undefined {
// Check if it's hex
const isHex = pubkey.replace(/[\s]*/g, '').match(/^[0-9a-fA-F]+$/);
if (!isHex) {
return i18n('invalidSessionId');
return window.i18n('invalidSessionId');
}
// Check if the pubkey length is 33 and leading with 05 or of length 32
const len = pubkey.length;
if ((len !== 33 * 2 || !/^05/.test(pubkey)) && len !== 32 * 2) {
return i18n('invalidPubkeyFormat');
return window.i18n('invalidPubkeyFormat');
}
return undefined;
}

View File

@ -82,18 +82,6 @@ export interface ConversationType {
avatarPath?: string; // absolute filepath to the avatar
groupAdmins?: Array<string>; // admins for closed groups and moderators for open groups
members?: Array<string>; // members for closed groups only
onClick?: () => void;
onBlockContact?: () => void;
onUnblockContact?: () => void;
onCopyPublicKey?: () => void;
onDeleteContact?: () => void;
onLeaveGroup?: () => void;
onDeleteMessages?: () => void;
onInviteContacts?: () => void;
onMarkAllRead?: () => void;
onClearNickname?: () => void;
onChangeNickname?: () => void;
}
export type ConversationLookupType = {

View File

@ -1,10 +1,7 @@
import { LocalizerType } from '../../types/Util';
// State
export type UserStateType = {
ourNumber: string;
i18n: LocalizerType;
};
// Actions
@ -37,7 +34,6 @@ function userChanged(attributes: { ourNumber: string; ourPrimary: string }): Use
function getEmptyState(): UserStateType {
return {
ourNumber: 'missing',
i18n: () => 'missing',
};
}

View File

@ -10,8 +10,8 @@ import {
import { getIntl, getOurNumber } from './user';
import { BlockedNumberController } from '../../util';
import { LocalizerType } from '../../types/Util';
import { ConversationTypeEnum } from '../../models/conversation';
import { LocalizerType } from '../../types/Util';
export const getConversations = (state: StateType): ConversationsStateType => state.conversations;
@ -49,20 +49,20 @@ export const getMessagesOfSelectedConversation = createSelector(
(state: ConversationsStateType): Array<MessageTypeInConvo> => state.messages
);
function getConversationTitle(conversation: ConversationType, i18n: LocalizerType): string {
function getConversationTitle(conversation: ConversationType, testingi18n?: LocalizerType): string {
if (conversation.name) {
return conversation.name;
}
if (conversation.type === 'group') {
return i18n('unknown');
return (testingi18n || window.i18n)('unknown');
}
return conversation.id;
}
const collator = new Intl.Collator();
export const _getConversationComparator = (i18n: LocalizerType) => {
export const _getConversationComparator = (testingi18n?: LocalizerType) => {
return (left: ConversationType, right: ConversationType): number => {
const leftActiveAt = left.activeAt;
const rightActiveAt = right.activeAt;
@ -75,8 +75,8 @@ export const _getConversationComparator = (i18n: LocalizerType) => {
if (leftActiveAt && rightActiveAt && leftActiveAt !== rightActiveAt) {
return rightActiveAt - leftActiveAt;
}
const leftTitle = getConversationTitle(left, i18n || window?.i18n).toLowerCase();
const rightTitle = getConversationTitle(right, i18n || window?.i18n).toLowerCase();
const leftTitle = getConversationTitle(left, testingi18n).toLowerCase();
const rightTitle = getConversationTitle(right, testingi18n).toLowerCase();
return collator.compare(leftTitle, rightTitle);
};
@ -120,7 +120,7 @@ export const _getLeftPaneLists = (
};
}
conversation.index = index;
// conversation.index = index;
// Add Open Group to list as soon as the name has been set
if (conversation.isPublic && (!conversation.name || conversation.name === 'Unknown group')) {

View File

@ -12,4 +12,7 @@ export const getOurNumber = createSelector(
(state: UserStateType): string => state.ourNumber
);
export const getIntl = createSelector(getUser, (state: UserStateType): LocalizerType => state.i18n);
export const getIntl = createSelector(
getUser,
(state: UserStateType): LocalizerType => window.i18n
);

View File

@ -6,7 +6,6 @@ import * as MIME from './MIME';
import { saveURLAsFile } from '../util/saveURLAsFile';
import { SignalService } from '../protobuf';
import { isImageTypeSupported, isVideoTypeSupported } from '../util/GoogleChrome';
import { LocalizerType } from './Util';
import { fromHexToArray } from '../session/utils/String';
import { getSodium } from '../session/crypto';
@ -225,8 +224,10 @@ export function getGridDimensions(attachments?: Array<AttachmentType>): null | D
};
}
export function getAlt(attachment: AttachmentType, i18n: LocalizerType): string {
return isVideoAttachment(attachment) ? i18n('videoAttachmentAlt') : i18n('imageAttachmentAlt');
export function getAlt(attachment: AttachmentType): string {
return isVideoAttachment(attachment)
? window.i18n('videoAttachmentAlt')
: window.i18n('imageAttachmentAlt');
}
// Migration-related attachment stuff

View File

@ -1,14 +1,13 @@
import moment from 'moment';
import { LocalizerType } from '../types/Util';
const getExtendedFormats = (i18n: LocalizerType) => ({
const getExtendedFormats = () => ({
y: 'lll',
M: `${i18n('timestampFormat_M') || 'MMM D'} LT`,
M: `${window.i18n('timestampFormat_M') || 'MMM D'} LT`,
d: 'ddd LT',
});
const getShortFormats = (i18n: LocalizerType) => ({
const getShortFormats = () => ({
y: 'll',
M: i18n('timestampFormat_M') || 'MMM D',
M: window.i18n('timestampFormat_M') || 'MMM D',
d: 'ddd',
});
@ -19,13 +18,9 @@ function isYear(timestamp: moment.Moment) {
return year === targetYear;
}
export function formatRelativeTime(
rawTimestamp: number | Date,
options: { extended?: boolean; i18n: LocalizerType }
) {
const { extended, i18n } = options;
const formats = extended ? getExtendedFormats(i18n) : getShortFormats(i18n);
export function formatRelativeTime(rawTimestamp: number | Date, options: { extended?: boolean }) {
const { extended } = options;
const formats = extended ? getExtendedFormats() : getShortFormats();
const timestamp = moment(rawTimestamp);
const now = moment();
const diff = moment.duration(now.diff(timestamp));

View File

@ -19,24 +19,24 @@ export const generateHash = (phrase: string) => phrase && sha512(phrase.trim());
export const matchesHash = (phrase: string | null, hash: string) =>
phrase && sha512(phrase.trim()) === hash.trim();
export const validatePassword = (phrase: string, i18n?: LocalizerType) => {
export const validatePassword = (phrase: string) => {
if (typeof phrase !== 'string') {
return i18n ? i18n('passwordTypeError') : ERRORS.TYPE;
return window?.i18n ? window?.i18n('passwordTypeError') : ERRORS.TYPE;
}
const trimmed = phrase.trim();
if (trimmed.length === 0) {
return i18n ? i18n('noGivenPassword') : ERRORS.LENGTH;
return window?.i18n ? window?.i18n('noGivenPassword') : ERRORS.LENGTH;
}
if (trimmed.length < 6 || trimmed.length > MAX_PASSWORD_LENGTH) {
return i18n ? i18n('passwordLengthError') : ERRORS.LENGTH;
return window?.i18n ? window?.i18n('passwordLengthError') : ERRORS.LENGTH;
}
// Restrict characters to letters, numbers and symbols
const characterRegex = /^[a-zA-Z0-9-!()._`~@#$%^&*+=[\]{}|<>,;: ]+$/;
if (!characterRegex.test(trimmed)) {
return i18n ? i18n('passwordCharacterError') : ERRORS.CHARACTER;
return window?.i18n ? window?.i18n('passwordCharacterError') : ERRORS.CHARACTER;
}
return null;