Normalize i18n() calls to prepare for ICU migration
This commit is contained in:
parent
7c8e7c1013
commit
c02c8d9640
17 changed files with 377 additions and 273 deletions
10
.eslintrc.js
10
.eslintrc.js
|
@ -213,6 +213,16 @@ const typescriptRules = {
|
|||
|
||||
'@typescript-eslint/consistent-type-imports': 'error',
|
||||
|
||||
// Future: Maybe switch to never and always use `satisfies`
|
||||
'@typescript-eslint/consistent-type-assertions': [
|
||||
'error',
|
||||
{
|
||||
assertionStyle: 'as',
|
||||
// Future: Maybe switch to allow-as-parameter or never
|
||||
objectLiteralTypeAssertions: 'allow',
|
||||
},
|
||||
],
|
||||
|
||||
// Already enforced by TypeScript
|
||||
'consistent-return': 'off',
|
||||
|
||||
|
|
|
@ -1404,7 +1404,7 @@ export class SignalProtocolStore extends EventEmitter {
|
|||
|
||||
const sessionResets = window.storage.get(
|
||||
'sessionResets',
|
||||
<SessionResetsType>{}
|
||||
{} as SessionResetsType
|
||||
);
|
||||
|
||||
const lastReset = sessionResets[id];
|
||||
|
|
|
@ -184,7 +184,7 @@ export function isOverHourIntoPast(timestamp: number): boolean {
|
|||
export async function cleanupSessionResets(): Promise<void> {
|
||||
const sessionResets = window.storage.get(
|
||||
'sessionResets',
|
||||
<SessionResetsType>{}
|
||||
{} as SessionResetsType
|
||||
);
|
||||
|
||||
const keys = Object.keys(sessionResets);
|
||||
|
|
|
@ -21,9 +21,11 @@ export type PropsType = Readonly<{
|
|||
onClose: () => void;
|
||||
}>;
|
||||
|
||||
const UNITS = ['seconds', 'minutes', 'hours', 'days', 'weeks'];
|
||||
const UNITS = ['seconds', 'minutes', 'hours', 'days', 'weeks'] as const;
|
||||
|
||||
const UNIT_TO_SEC = new Map<string, number>([
|
||||
export type Unit = typeof UNITS[number];
|
||||
|
||||
const UNIT_TO_SEC = new Map<Unit, number>([
|
||||
['seconds', 1],
|
||||
['minutes', 60],
|
||||
['hours', 60 * 60],
|
||||
|
@ -31,7 +33,7 @@ const UNIT_TO_SEC = new Map<string, number>([
|
|||
['weeks', 7 * 24 * 60 * 60],
|
||||
]);
|
||||
|
||||
const RANGES = new Map<string, [number, number]>([
|
||||
const RANGES = new Map<Unit, [number, number]>([
|
||||
['seconds', [1, 60]],
|
||||
['minutes', [1, 60]],
|
||||
['hours', [1, 24]],
|
||||
|
@ -48,7 +50,7 @@ export function DisappearingTimeDialog(props: PropsType): JSX.Element {
|
|||
onClose,
|
||||
} = props;
|
||||
|
||||
let initialUnit = 'seconds';
|
||||
let initialUnit: Unit = 'seconds';
|
||||
let initialUnitValue = 1;
|
||||
for (const unit of UNITS) {
|
||||
const sec = UNIT_TO_SEC.get(unit) || 1;
|
||||
|
@ -62,7 +64,7 @@ export function DisappearingTimeDialog(props: PropsType): JSX.Element {
|
|||
}
|
||||
|
||||
const [unitValue, setUnitValue] = useState(initialUnitValue);
|
||||
const [unit, setUnit] = useState(initialUnit);
|
||||
const [unit, setUnit] = useState<Unit>(initialUnit);
|
||||
|
||||
const range = RANGES.get(unit) || [1, 1];
|
||||
|
||||
|
@ -108,9 +110,9 @@ export function DisappearingTimeDialog(props: PropsType): JSX.Element {
|
|||
moduleClassName={`${CSS_MODULE}__time-boxes__units`}
|
||||
value={unit}
|
||||
onChange={newUnit => {
|
||||
setUnit(newUnit);
|
||||
setUnit(newUnit as Unit);
|
||||
|
||||
const ranges = RANGES.get(newUnit);
|
||||
const ranges = RANGES.get(newUnit as Unit);
|
||||
if (!ranges) {
|
||||
return;
|
||||
}
|
||||
|
@ -121,7 +123,13 @@ export function DisappearingTimeDialog(props: PropsType): JSX.Element {
|
|||
options={UNITS.map(unitName => {
|
||||
return {
|
||||
value: unitName,
|
||||
text: i18n(`DisappearingTimeDialog__${unitName}`),
|
||||
text: {
|
||||
seconds: i18n('DisappearingTimeDialog__seconds'),
|
||||
minutes: i18n('DisappearingTimeDialog__minutes'),
|
||||
hours: i18n('DisappearingTimeDialog__hours'),
|
||||
days: i18n('DisappearingTimeDialog__days'),
|
||||
weeks: i18n('DisappearingTimeDialog__weeks'),
|
||||
}[unitName],
|
||||
};
|
||||
})}
|
||||
/>
|
||||
|
|
|
@ -177,9 +177,11 @@ function OverflowAreaScrollMarker({
|
|||
type="button"
|
||||
className={`${baseClassName}__button`}
|
||||
onClick={onClick}
|
||||
aria-label={i18n(
|
||||
`calling__overflow__scroll-${placement === 'top' ? 'up' : 'down'}`
|
||||
)}
|
||||
aria-label={
|
||||
placement === 'top'
|
||||
? i18n('calling__overflow__scroll-up')
|
||||
: i18n('calling__overflow__scroll-down')
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -96,28 +96,30 @@ type DefaultBio = {
|
|||
shortName: string;
|
||||
};
|
||||
|
||||
const DEFAULT_BIOS: Array<DefaultBio> = [
|
||||
{
|
||||
i18nLabel: 'Bio--speak-freely',
|
||||
shortName: 'wave',
|
||||
},
|
||||
{
|
||||
i18nLabel: 'Bio--encrypted',
|
||||
shortName: 'zipper_mouth_face',
|
||||
},
|
||||
{
|
||||
i18nLabel: 'Bio--free-to-chat',
|
||||
shortName: '+1',
|
||||
},
|
||||
{
|
||||
i18nLabel: 'Bio--coffee-lover',
|
||||
shortName: 'coffee',
|
||||
},
|
||||
{
|
||||
i18nLabel: 'Bio--taking-break',
|
||||
shortName: 'mobile_phone_off',
|
||||
},
|
||||
];
|
||||
function getDefaultBios(i18n: LocalizerType): Array<DefaultBio> {
|
||||
return [
|
||||
{
|
||||
i18nLabel: i18n('Bio--speak-freely'),
|
||||
shortName: 'wave',
|
||||
},
|
||||
{
|
||||
i18nLabel: i18n('Bio--encrypted'),
|
||||
shortName: 'zipper_mouth_face',
|
||||
},
|
||||
{
|
||||
i18nLabel: i18n('Bio--free-to-chat'),
|
||||
shortName: '+1',
|
||||
},
|
||||
{
|
||||
i18nLabel: i18n('Bio--coffee-lover'),
|
||||
shortName: 'coffee',
|
||||
},
|
||||
{
|
||||
i18nLabel: i18n('Bio--taking-break'),
|
||||
shortName: 'mobile_phone_off',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function ProfileEditor({
|
||||
aboutEmoji,
|
||||
|
@ -371,6 +373,8 @@ export function ProfileEditor({
|
|||
(stagedProfile.aboutText === fullBio.aboutText &&
|
||||
stagedProfile.aboutEmoji === fullBio.aboutEmoji);
|
||||
|
||||
const defaultBios = getDefaultBios(i18n);
|
||||
|
||||
content = (
|
||||
<>
|
||||
<Input
|
||||
|
@ -415,7 +419,7 @@ export function ProfileEditor({
|
|||
whenToShowRemainingCount={40}
|
||||
/>
|
||||
|
||||
{DEFAULT_BIOS.map(defaultBio => (
|
||||
{defaultBios.map(defaultBio => (
|
||||
<PanelRow
|
||||
className="ProfileEditor__row"
|
||||
key={defaultBio.shortName}
|
||||
|
@ -424,16 +428,14 @@ export function ProfileEditor({
|
|||
<Emoji shortName={defaultBio.shortName} size={24} />
|
||||
</div>
|
||||
}
|
||||
// eslint-disable-next-line local-rules/valid-i18n-keys
|
||||
label={i18n(defaultBio.i18nLabel)}
|
||||
label={defaultBio.i18nLabel}
|
||||
onClick={() => {
|
||||
const emojiData = getEmojiData(defaultBio.shortName, skinTone);
|
||||
|
||||
setStagedProfile(profileData => ({
|
||||
...profileData,
|
||||
aboutEmoji: unifiedToEmoji(emojiData.unified),
|
||||
// eslint-disable-next-line local-rules/valid-i18n-keys
|
||||
aboutText: i18n(defaultBio.i18nLabel),
|
||||
aboutText: defaultBio.i18nLabel,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
|
|
|
@ -44,191 +44,241 @@ type KeyType =
|
|||
| 'Y'
|
||||
| '1 to 9';
|
||||
type ShortcutType = {
|
||||
id: string;
|
||||
description: string;
|
||||
keys: Array<Array<KeyType>>;
|
||||
};
|
||||
|
||||
const NAVIGATION_SHORTCUTS: Array<ShortcutType> = [
|
||||
{
|
||||
description: 'Keyboard--navigate-by-section',
|
||||
keys: [['commandOrCtrl', 'T']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--previous-conversation',
|
||||
keys: [
|
||||
['optionOrAlt', '↑'],
|
||||
['ctrl', 'shift', 'tab'],
|
||||
],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--next-conversation',
|
||||
keys: [
|
||||
['optionOrAlt', '↓'],
|
||||
['ctrl', 'tab'],
|
||||
],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--previous-unread-conversation',
|
||||
keys: [['optionOrAlt', 'shift', '↑']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--next-unread-conversation',
|
||||
keys: [['optionOrAlt', 'shift', '↓']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--conversation-by-index',
|
||||
keys: [['commandOrCtrl', '1 to 9']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--preferences',
|
||||
keys: [['commandOrCtrl', ',']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--open-conversation-menu',
|
||||
keys: [['commandOrCtrl', 'shift', 'L']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--new-conversation',
|
||||
keys: [['commandOrCtrl', 'N']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--search',
|
||||
keys: [['commandOrCtrl', 'F']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--search-in-conversation',
|
||||
keys: [['commandOrCtrl', 'shift', 'F']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--focus-composer',
|
||||
keys: [['commandOrCtrl', 'shift', 'T']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--open-all-media-view',
|
||||
keys: [['commandOrCtrl', 'shift', 'M']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--open-emoji-chooser',
|
||||
keys: [['commandOrCtrl', 'shift', 'J']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--open-sticker-chooser',
|
||||
keys: [['commandOrCtrl', 'shift', 'S']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--begin-recording-voice-note',
|
||||
keys: [['commandOrCtrl', 'shift', 'V']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--archive-conversation',
|
||||
keys: [['commandOrCtrl', 'shift', 'A']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--unarchive-conversation',
|
||||
keys: [['commandOrCtrl', 'shift', 'U']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--scroll-to-top',
|
||||
keys: [['commandOrCtrl', '↑']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--scroll-to-bottom',
|
||||
keys: [['commandOrCtrl', '↓']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--close-curent-conversation',
|
||||
keys: [['commandOrCtrl', 'shift', 'C']],
|
||||
},
|
||||
];
|
||||
function getNavigationShortcuts(i18n: LocalizerType): Array<ShortcutType> {
|
||||
return [
|
||||
{
|
||||
id: 'Keyboard--navigate-by-section',
|
||||
description: i18n('Keyboard--navigate-by-section'),
|
||||
keys: [['commandOrCtrl', 'T']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--previous-conversation',
|
||||
description: i18n('Keyboard--previous-conversation'),
|
||||
keys: [
|
||||
['optionOrAlt', '↑'],
|
||||
['ctrl', 'shift', 'tab'],
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--next-conversation',
|
||||
description: i18n('Keyboard--next-conversation'),
|
||||
keys: [
|
||||
['optionOrAlt', '↓'],
|
||||
['ctrl', 'tab'],
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--previous-unread-conversation',
|
||||
description: i18n('Keyboard--previous-unread-conversation'),
|
||||
keys: [['optionOrAlt', 'shift', '↑']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--next-unread-conversation',
|
||||
description: i18n('Keyboard--next-unread-conversation'),
|
||||
keys: [['optionOrAlt', 'shift', '↓']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--conversation-by-index',
|
||||
description: i18n('Keyboard--conversation-by-index'),
|
||||
keys: [['commandOrCtrl', '1 to 9']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--preferences',
|
||||
description: i18n('Keyboard--preferences'),
|
||||
keys: [['commandOrCtrl', ',']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--open-conversation-menu',
|
||||
description: i18n('Keyboard--open-conversation-menu'),
|
||||
keys: [['commandOrCtrl', 'shift', 'L']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--new-conversation',
|
||||
description: i18n('Keyboard--new-conversation'),
|
||||
keys: [['commandOrCtrl', 'N']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--search',
|
||||
description: i18n('Keyboard--search'),
|
||||
keys: [['commandOrCtrl', 'F']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--search-in-conversation',
|
||||
description: i18n('Keyboard--search-in-conversation'),
|
||||
keys: [['commandOrCtrl', 'shift', 'F']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--focus-composer',
|
||||
description: i18n('Keyboard--focus-composer'),
|
||||
keys: [['commandOrCtrl', 'shift', 'T']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--open-all-media-view',
|
||||
description: i18n('Keyboard--open-all-media-view'),
|
||||
keys: [['commandOrCtrl', 'shift', 'M']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--open-emoji-chooser',
|
||||
description: i18n('Keyboard--open-emoji-chooser'),
|
||||
keys: [['commandOrCtrl', 'shift', 'J']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--open-sticker-chooser',
|
||||
description: i18n('Keyboard--open-sticker-chooser'),
|
||||
keys: [['commandOrCtrl', 'shift', 'S']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--begin-recording-voice-note',
|
||||
description: i18n('Keyboard--begin-recording-voice-note'),
|
||||
keys: [['commandOrCtrl', 'shift', 'V']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--archive-conversation',
|
||||
description: i18n('Keyboard--archive-conversation'),
|
||||
keys: [['commandOrCtrl', 'shift', 'A']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--unarchive-conversation',
|
||||
description: i18n('Keyboard--unarchive-conversation'),
|
||||
keys: [['commandOrCtrl', 'shift', 'U']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--scroll-to-top',
|
||||
description: i18n('Keyboard--scroll-to-top'),
|
||||
keys: [['commandOrCtrl', '↑']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--scroll-to-bottom',
|
||||
description: i18n('Keyboard--scroll-to-bottom'),
|
||||
keys: [['commandOrCtrl', '↓']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--close-curent-conversation',
|
||||
description: i18n('Keyboard--close-curent-conversation'),
|
||||
keys: [['commandOrCtrl', 'shift', 'C']],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
const MESSAGE_SHORTCUTS: Array<ShortcutType> = [
|
||||
{
|
||||
description: 'Keyboard--default-message-action',
|
||||
keys: [['enter']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--view-details-for-selected-message',
|
||||
keys: [['commandOrCtrl', 'D']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--toggle-reply',
|
||||
keys: [['commandOrCtrl', 'shift', 'R']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--toggle-reaction-picker',
|
||||
keys: [['commandOrCtrl', 'shift', 'E']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--save-attachment',
|
||||
keys: [['commandOrCtrl', 'S']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--delete-messages',
|
||||
keys: [['commandOrCtrl', 'shift', 'D']],
|
||||
},
|
||||
];
|
||||
function getMessageShortcuts(i18n: LocalizerType): Array<ShortcutType> {
|
||||
return [
|
||||
{
|
||||
id: 'Keyboard--default-message-action',
|
||||
description: i18n('Keyboard--default-message-action'),
|
||||
keys: [['enter']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--view-details-for-selected-message',
|
||||
description: i18n('Keyboard--view-details-for-selected-message'),
|
||||
keys: [['commandOrCtrl', 'D']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--toggle-reply',
|
||||
description: i18n('Keyboard--toggle-reply'),
|
||||
keys: [['commandOrCtrl', 'shift', 'R']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--toggle-reaction-picker',
|
||||
description: i18n('Keyboard--toggle-reaction-picker'),
|
||||
keys: [['commandOrCtrl', 'shift', 'E']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--save-attachment',
|
||||
description: i18n('Keyboard--save-attachment'),
|
||||
keys: [['commandOrCtrl', 'S']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--delete-message',
|
||||
description: i18n('Keyboard--delete-message'),
|
||||
keys: [['commandOrCtrl', 'shift', 'D']],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
const COMPOSER_SHORTCUTS: Array<ShortcutType> = [
|
||||
{
|
||||
description: 'Keyboard--add-newline',
|
||||
keys: [['shift', 'enter']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--expand-composer',
|
||||
keys: [['commandOrCtrl', 'shift', 'X']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--send-in-expanded-composer',
|
||||
keys: [['commandOrCtrl', 'enter']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--attach-file',
|
||||
keys: [['commandOrCtrl', 'U']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--remove-draft-link-preview',
|
||||
keys: [['commandOrCtrl', 'P']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--remove-draft-attachments',
|
||||
keys: [['commandOrCtrl', 'shift', 'P']],
|
||||
},
|
||||
];
|
||||
function getComposerShortcuts(i18n: LocalizerType): Array<ShortcutType> {
|
||||
return [
|
||||
{
|
||||
id: 'Keyboard--add-newline',
|
||||
description: i18n('Keyboard--add-newline'),
|
||||
keys: [['shift', 'enter']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--expand-composer',
|
||||
description: i18n('Keyboard--expand-composer'),
|
||||
keys: [['commandOrCtrl', 'shift', 'X']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--send-in-expanded-composer',
|
||||
description: i18n('Keyboard--send-in-expanded-composer'),
|
||||
keys: [['commandOrCtrl', 'enter']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--attach-file',
|
||||
description: i18n('Keyboard--attach-file'),
|
||||
keys: [['commandOrCtrl', 'U']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--remove-draft-link-preview',
|
||||
description: i18n('Keyboard--remove-draft-link-preview'),
|
||||
keys: [['commandOrCtrl', 'P']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--remove-draft-attachments',
|
||||
description: i18n('Keyboard--remove-draft-attachments'),
|
||||
keys: [['commandOrCtrl', 'shift', 'P']],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
const CALLING_SHORTCUTS: Array<ShortcutType> = [
|
||||
{
|
||||
description: 'Keyboard--toggle-audio',
|
||||
keys: [['shift', 'M']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--toggle-video',
|
||||
keys: [['shift', 'V']],
|
||||
},
|
||||
{
|
||||
description: 'icu:Keyboard--accept-video-call',
|
||||
keys: [['ctrlOrAlt', 'shift', 'V']],
|
||||
},
|
||||
{
|
||||
description: 'icu:Keyboard--accept-call-without-video',
|
||||
keys: [['ctrlOrAlt', 'shift', 'A']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--decline-call',
|
||||
keys: [['ctrlOrAlt', 'shift', 'D']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--start-audio-call',
|
||||
keys: [['ctrlOrAlt', 'shift', 'C']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--start-video-call',
|
||||
keys: [['ctrlOrAlt', 'shift', 'Y']],
|
||||
},
|
||||
{
|
||||
description: 'Keyboard--hang-up',
|
||||
keys: [['ctrlOrAlt', 'shift', 'E']],
|
||||
},
|
||||
];
|
||||
function getCallingShortcuts(i18n: LocalizerType): Array<ShortcutType> {
|
||||
return [
|
||||
{
|
||||
id: 'Keyboard--toggle-audio',
|
||||
description: i18n('Keyboard--toggle-audio'),
|
||||
keys: [['shift', 'M']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--toggle-video',
|
||||
description: i18n('Keyboard--toggle-video'),
|
||||
keys: [['shift', 'V']],
|
||||
},
|
||||
{
|
||||
id: 'icu:Keyboard--accept-video-call',
|
||||
description: i18n('icu:Keyboard--accept-video-call'),
|
||||
keys: [['ctrlOrAlt', 'shift', 'V']],
|
||||
},
|
||||
{
|
||||
id: 'icu:Keyboard--accept-call-without-video',
|
||||
description: i18n('icu:Keyboard--accept-call-without-video'),
|
||||
keys: [['ctrlOrAlt', 'shift', 'A']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--decline-call',
|
||||
description: i18n('Keyboard--decline-call'),
|
||||
keys: [['ctrlOrAlt', 'shift', 'D']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--start-audio-call',
|
||||
description: i18n('Keyboard--start-audio-call'),
|
||||
keys: [['ctrlOrAlt', 'shift', 'C']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--start-video-call',
|
||||
description: i18n('Keyboard--start-video-call'),
|
||||
keys: [['ctrlOrAlt', 'shift', 'Y']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--hang-up',
|
||||
description: i18n('Keyboard--hang-up'),
|
||||
keys: [['ctrlOrAlt', 'shift', 'E']],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function ShortcutGuide(props: Props): JSX.Element {
|
||||
const { i18n, close, hasInstalledStickers, platform } = props;
|
||||
|
@ -262,7 +312,7 @@ export function ShortcutGuide(props: Props): JSX.Element {
|
|||
{i18n('Keyboard--navigation-header')}
|
||||
</div>
|
||||
<div className="module-shortcut-guide__section-list">
|
||||
{NAVIGATION_SHORTCUTS.map((shortcut, index) => {
|
||||
{getNavigationShortcuts(i18n).map((shortcut, index) => {
|
||||
if (
|
||||
!hasInstalledStickers &&
|
||||
shortcut.description === 'Keyboard--open-sticker-chooser'
|
||||
|
@ -279,7 +329,7 @@ export function ShortcutGuide(props: Props): JSX.Element {
|
|||
{i18n('Keyboard--messages-header')}
|
||||
</div>
|
||||
<div className="module-shortcut-guide__section-list">
|
||||
{MESSAGE_SHORTCUTS.map((shortcut, index) =>
|
||||
{getMessageShortcuts(i18n).map((shortcut, index) =>
|
||||
renderShortcut(shortcut, index, isMacOS, i18n)
|
||||
)}
|
||||
</div>
|
||||
|
@ -289,7 +339,7 @@ export function ShortcutGuide(props: Props): JSX.Element {
|
|||
{i18n('Keyboard--composer-header')}
|
||||
</div>
|
||||
<div className="module-shortcut-guide__section-list">
|
||||
{COMPOSER_SHORTCUTS.map((shortcut, index) =>
|
||||
{getComposerShortcuts(i18n).map((shortcut, index) =>
|
||||
renderShortcut(shortcut, index, isMacOS, i18n)
|
||||
)}
|
||||
</div>
|
||||
|
@ -299,7 +349,7 @@ export function ShortcutGuide(props: Props): JSX.Element {
|
|||
{i18n('Keyboard--calling-header')}
|
||||
</div>
|
||||
<div className="module-shortcut-guide__section-list">
|
||||
{CALLING_SHORTCUTS.map((shortcut, index) =>
|
||||
{getCallingShortcuts(i18n).map((shortcut, index) =>
|
||||
renderShortcut(shortcut, index, isMacOS, i18n)
|
||||
)}
|
||||
</div>
|
||||
|
@ -319,8 +369,7 @@ function renderShortcut(
|
|||
return (
|
||||
<div key={index} className="module-shortcut-guide__shortcut">
|
||||
<div className="module-shortcut-guide__shortcut__description">
|
||||
{/* eslint-disable-next-line local-rules/valid-i18n-keys */}
|
||||
{i18n(shortcut.description)}
|
||||
{shortcut.description}
|
||||
</div>
|
||||
<div className="module-shortcut-guide__shortcut__key-container">
|
||||
{shortcut.keys.map(keys => (
|
||||
|
|
|
@ -37,32 +37,35 @@ export type PropsType = {
|
|||
|
||||
const contactSortCollator = new window.Intl.Collator();
|
||||
|
||||
function getI18nKey(sendStatus: SendStatus | undefined): string {
|
||||
function getSendStatusLabel(
|
||||
sendStatus: SendStatus | undefined,
|
||||
i18n: LocalizerType
|
||||
): string {
|
||||
if (sendStatus === SendStatus.Failed) {
|
||||
return 'MessageDetailsHeader--Failed';
|
||||
return i18n('MessageDetailsHeader--Failed');
|
||||
}
|
||||
|
||||
if (sendStatus === SendStatus.Viewed) {
|
||||
return 'MessageDetailsHeader--Viewed';
|
||||
return i18n('MessageDetailsHeader--Viewed');
|
||||
}
|
||||
|
||||
if (sendStatus === SendStatus.Read) {
|
||||
return 'MessageDetailsHeader--Read';
|
||||
return i18n('MessageDetailsHeader--Read');
|
||||
}
|
||||
|
||||
if (sendStatus === SendStatus.Delivered) {
|
||||
return 'MessageDetailsHeader--Delivered';
|
||||
return i18n('MessageDetailsHeader--Delivered');
|
||||
}
|
||||
|
||||
if (sendStatus === SendStatus.Sent) {
|
||||
return 'MessageDetailsHeader--Sent';
|
||||
return i18n('MessageDetailsHeader--Sent');
|
||||
}
|
||||
|
||||
if (sendStatus === SendStatus.Pending) {
|
||||
return 'MessageDetailsHeader--Pending';
|
||||
return i18n('MessageDetailsHeader--Pending');
|
||||
}
|
||||
|
||||
return 'from';
|
||||
return i18n('from');
|
||||
}
|
||||
|
||||
export function StoryDetailsModal({
|
||||
|
@ -105,17 +108,19 @@ export function StoryDetailsModal({
|
|||
return null;
|
||||
}
|
||||
|
||||
const i18nKey = getI18nKey(sendStatus);
|
||||
const sendStatusLabel = getSendStatusLabel(sendStatus, i18n);
|
||||
|
||||
const sortedContacts = [...contacts].sort((a, b) =>
|
||||
contactSortCollator.compare(a.recipient.title, b.recipient.title)
|
||||
);
|
||||
|
||||
return (
|
||||
<div key={i18nKey} className="StoryDetailsModal__contact-group">
|
||||
<div
|
||||
key={sendStatusLabel}
|
||||
className="StoryDetailsModal__contact-group"
|
||||
>
|
||||
<div className="StoryDetailsModal__contact-group__header">
|
||||
{/* eslint-disable-next-line local-rules/valid-i18n-keys */}
|
||||
{i18n(i18nKey)}
|
||||
{sendStatusLabel}
|
||||
</div>
|
||||
{sortedContacts.map(status => {
|
||||
const contact = status.recipient;
|
||||
|
|
|
@ -23,13 +23,15 @@ export function UsernameOnboardingModalBody({
|
|||
<div className={CLASS}>
|
||||
<div className={`${CLASS}__large-at`} />
|
||||
|
||||
<div className={`${CLASS}__title`}>{i18n(`icu:${CLASS}__title`)}</div>
|
||||
<div className={`${CLASS}__title`}>
|
||||
{i18n('icu:UsernameOnboardingModalBody__title')}
|
||||
</div>
|
||||
|
||||
<div className={`${CLASS}__row`}>
|
||||
<div className={`${CLASS}__row__icon ${CLASS}__row__icon--number`} />
|
||||
|
||||
<div className={`${CLASS}__row__body`}>
|
||||
{i18n(`icu:${CLASS}__row__number`)}
|
||||
{i18n('icu:UsernameOnboardingModalBody__row__number')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -37,7 +39,7 @@ export function UsernameOnboardingModalBody({
|
|||
<div className={`${CLASS}__row__icon ${CLASS}__row__icon--link`} />
|
||||
|
||||
<div className={`${CLASS}__row__body`}>
|
||||
{i18n(`icu:${CLASS}__row__link`)}
|
||||
{i18n('icu:UsernameOnboardingModalBody__row__link')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -45,7 +47,7 @@ export function UsernameOnboardingModalBody({
|
|||
<div className={`${CLASS}__row__icon ${CLASS}__row__icon--lock`} />
|
||||
|
||||
<div className={`${CLASS}__row__body`}>
|
||||
{i18n(`icu:${CLASS}__row__lock`)}
|
||||
{i18n('icu:UsernameOnboardingModalBody__row__lock')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -56,12 +58,12 @@ export function UsernameOnboardingModalBody({
|
|||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
{i18n(`icu:${CLASS}__learn-more`)}
|
||||
{i18n('icu:UsernameOnboardingModalBody__learn-more')}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<Button className={`${CLASS}__submit`} onClick={onNext}>
|
||||
{i18n(`icu:${CLASS}__continue`)}
|
||||
{i18n('icu:UsernameOnboardingModalBody__continue')}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -571,7 +571,10 @@ export class Message extends React.PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
if (giftBadge) {
|
||||
const description = i18n(`icu:message--donation--unopened--${direction}`);
|
||||
const description =
|
||||
direction === 'incoming'
|
||||
? i18n('icu:message--donation--unopened--incoming')
|
||||
: i18n('icu:message--donation--unopened--outgoing');
|
||||
const isDescriptionRTL = getDirection(description) === 'rtl';
|
||||
|
||||
if (giftBadge.state === GiftBadgeStates.Unopened && !isDescriptionRTL) {
|
||||
|
|
|
@ -49,13 +49,23 @@ export function MessageRequestActionsConfirmation({
|
|||
onChangeState(MessageRequestState.default);
|
||||
}}
|
||||
title={
|
||||
<Intl
|
||||
i18n={i18n}
|
||||
id={`MessageRequests--block-${conversationType}-confirm-title`}
|
||||
components={{
|
||||
title: <ContactName key="name" title={title} />,
|
||||
}}
|
||||
/>
|
||||
conversationType === 'direct' ? (
|
||||
<Intl
|
||||
i18n={i18n}
|
||||
id="MessageRequests--block-direct-confirm-title"
|
||||
components={{
|
||||
title: <ContactName key="name" title={title} />,
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<Intl
|
||||
i18n={i18n}
|
||||
id="MessageRequests--block-group-confirm-title"
|
||||
components={{
|
||||
title: <ContactName key="name" title={title} />,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
actions={[
|
||||
...(conversationType === 'direct'
|
||||
|
@ -74,7 +84,9 @@ export function MessageRequestActionsConfirmation({
|
|||
},
|
||||
]}
|
||||
>
|
||||
{i18n(`MessageRequests--block-${conversationType}-confirm-body`)}
|
||||
{conversationType === 'direct'
|
||||
? i18n('MessageRequests--block-direct-confirm-body')
|
||||
: i18n('MessageRequests--block-group-confirm-body')}
|
||||
</ConfirmationDialog>
|
||||
);
|
||||
}
|
||||
|
@ -104,7 +116,9 @@ export function MessageRequestActionsConfirmation({
|
|||
},
|
||||
]}
|
||||
>
|
||||
{i18n(`MessageRequests--unblock-${conversationType}-confirm-body`)}
|
||||
{conversationType === 'direct'
|
||||
? i18n('MessageRequests--unblock-direct-confirm-body')
|
||||
: i18n('MessageRequests--unblock-group-confirm-body')}
|
||||
</ConfirmationDialog>
|
||||
);
|
||||
}
|
||||
|
@ -128,13 +142,18 @@ export function MessageRequestActionsConfirmation({
|
|||
}
|
||||
actions={[
|
||||
{
|
||||
text: i18n(`MessageRequests--delete-${conversationType}`),
|
||||
text:
|
||||
conversationType === 'direct'
|
||||
? i18n('MessageRequests--delete-direct')
|
||||
: i18n('MessageRequests--delete-group'),
|
||||
action: () => deleteConversation(conversationId),
|
||||
style: 'negative',
|
||||
},
|
||||
]}
|
||||
>
|
||||
{i18n(`MessageRequests--delete-${conversationType}-confirm-body`)}
|
||||
{conversationType === 'direct'
|
||||
? i18n('MessageRequests--delete-direct-confirm-body')
|
||||
: i18n('MessageRequests--delete-group-confirm-body')}
|
||||
</ConfirmationDialog>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -285,12 +285,13 @@ function getConfirmationMessage({
|
|||
|
||||
// Requesting a membership since they weren't added by anyone
|
||||
if (membershipType === StageType.DENY_REQUEST) {
|
||||
const params = {
|
||||
name: firstMembership.member.title,
|
||||
};
|
||||
return isAccessControlEnabled(conversation.accessControlAddFromInviteLink)
|
||||
? i18n('PendingRequests--deny-for--with-link', params)
|
||||
: i18n('PendingRequests--deny-for', params);
|
||||
? i18n('PendingRequests--deny-for--with-link', {
|
||||
name: firstMembership.member.title,
|
||||
})
|
||||
: i18n('PendingRequests--deny-for', {
|
||||
name: firstMembership.member.title,
|
||||
});
|
||||
}
|
||||
|
||||
if (membershipType === StageType.APPROVE_REQUEST) {
|
||||
|
|
|
@ -30,7 +30,7 @@ async function clearResetsTracking(idForTracking: string | undefined) {
|
|||
|
||||
const sessionResets = window.storage.get(
|
||||
'sessionResets',
|
||||
<SessionResetsType>{}
|
||||
{} as SessionResetsType
|
||||
);
|
||||
delete sessionResets[idForTracking];
|
||||
await window.storage.put('sessionResets', sessionResets);
|
||||
|
|
|
@ -765,7 +765,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
|
|||
fromContact?.getTitle() ?? window.i18n('unknownContact');
|
||||
return {
|
||||
emoji,
|
||||
text: window.i18n('icu:message--giftBadge--preview--sent', {
|
||||
text: window.i18n('icu:message--donation--preview--sent', {
|
||||
recipient,
|
||||
}),
|
||||
};
|
||||
|
@ -776,10 +776,10 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
|
|||
emoji,
|
||||
text:
|
||||
giftBadge.state === GiftBadgeStates.Unopened
|
||||
? window.i18n('icu:message--giftBadge--preview--unopened', {
|
||||
? window.i18n('icu:message--donation--preview--unopened', {
|
||||
sender,
|
||||
})
|
||||
: window.i18n('icu:message--giftBadge--preview--redeemed'),
|
||||
: window.i18n('icu:message--donation--preview--redeemed'),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -83,9 +83,9 @@ async function notifyForCall(
|
|||
icon: isVideoCall
|
||||
? 'images/icons/v2/video-solid-24.svg'
|
||||
: 'images/icons/v2/phone-right-solid-24.svg',
|
||||
message: window.i18n(
|
||||
isVideoCall ? 'incomingVideoCall' : 'incomingAudioCall'
|
||||
),
|
||||
message: isVideoCall
|
||||
? window.i18n('incomingVideoCall')
|
||||
: window.i18n('incomingAudioCall'),
|
||||
onNotificationClick: () => {
|
||||
window.IPC.showWindow();
|
||||
},
|
||||
|
|
|
@ -100,10 +100,11 @@ describe('both/state/ducks/audioPlayer', () => {
|
|||
it('active is not changed when changing the conversation', () => {
|
||||
const state = getInitializedState();
|
||||
|
||||
const updated = rootReducer(state, <TargetedConversationChangedActionType>{
|
||||
const action: TargetedConversationChangedActionType = {
|
||||
type: TARGETED_CONVERSATION_CHANGED,
|
||||
payload: { id: 'any' },
|
||||
});
|
||||
payload: { conversationId: 'any' },
|
||||
};
|
||||
const updated = rootReducer(state, action);
|
||||
|
||||
const content = updated.audioPlayer.active?.content;
|
||||
assert.isTrue(content && AudioPlayerContent.isVoiceNote(content));
|
||||
|
|
|
@ -60,9 +60,10 @@ describe('NativeThemeListener', () => {
|
|||
|
||||
const listener = createNativeThemeListener(ipc, holder);
|
||||
|
||||
ipc.emit('native-theme:changed', null, <NativeThemeState>{
|
||||
const state: NativeThemeState = {
|
||||
shouldUseDarkColors: false,
|
||||
});
|
||||
};
|
||||
ipc.emit('native-theme:changed', null, state);
|
||||
|
||||
assert.strictEqual(holder.systemTheme, 'light');
|
||||
assert.strictEqual(listener.getSystemTheme(), 'light');
|
||||
|
@ -80,8 +81,9 @@ describe('NativeThemeListener', () => {
|
|||
done();
|
||||
});
|
||||
|
||||
ipc.emit('native-theme:changed', null, <NativeThemeState>{
|
||||
const state: NativeThemeState = {
|
||||
shouldUseDarkColors: false,
|
||||
});
|
||||
};
|
||||
ipc.emit('native-theme:changed', null, state);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue