Add new eslint plugin to check for valid i18n keys
This commit is contained in:
parent
465b4cb0fb
commit
569b6e14a6
39 changed files with 447 additions and 78 deletions
|
@ -91,19 +91,19 @@ export function CallingHeader({
|
|||
{isGroupCall && participantCount > 2 && toggleSpeakerView && (
|
||||
<div className="module-calling-tools__button">
|
||||
<Tooltip
|
||||
content={i18n(
|
||||
content={
|
||||
isInSpeakerView
|
||||
? 'calling__switch-view--to-grid'
|
||||
: 'calling__switch-view--to-speaker'
|
||||
)}
|
||||
? i18n('calling__switch-view--to-grid')
|
||||
: i18n('calling__switch-view--to-speaker')
|
||||
}
|
||||
theme={Theme.Dark}
|
||||
>
|
||||
<button
|
||||
aria-label={i18n(
|
||||
aria-label={
|
||||
isInSpeakerView
|
||||
? 'calling__switch-view--to-grid'
|
||||
: 'calling__switch-view--to-speaker'
|
||||
)}
|
||||
? i18n('calling__switch-view--to-grid')
|
||||
: i18n('calling__switch-view--to-speaker')
|
||||
}
|
||||
className={
|
||||
isInSpeakerView
|
||||
? 'CallingButton__grid-view'
|
||||
|
|
|
@ -374,8 +374,10 @@ export function ConversationList({
|
|||
result = (
|
||||
<div
|
||||
className="module-conversation-list__item--header"
|
||||
// eslint-disable-next-line local-rules/valid-i18n-keys
|
||||
aria-label={i18n(row.i18nKey)}
|
||||
>
|
||||
{/* eslint-disable-next-line local-rules/valid-i18n-keys */}
|
||||
{i18n(row.i18nKey)}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -65,11 +65,9 @@ export function DisappearingTimerSelect(props: Props): JSX.Element {
|
|||
...expirationTimerOptions,
|
||||
{
|
||||
value: DurationInSeconds.fromSeconds(-1),
|
||||
text: i18n(
|
||||
isCustomTimeSelected
|
||||
? 'selectedCustomDisappearingTimeOption'
|
||||
: 'customDisappearingTimeOption'
|
||||
),
|
||||
text: isCustomTimeSelected
|
||||
? i18n('selectedCustomDisappearingTimeOption')
|
||||
: i18n('customDisappearingTimeOption'),
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -154,6 +154,7 @@ function renderMembers({
|
|||
|
||||
return (
|
||||
<>
|
||||
{/* eslint-disable-next-line local-rules/valid-i18n-keys */}
|
||||
<GroupDialog.Paragraph>{i18n(key)}</GroupDialog.Paragraph>
|
||||
<GroupDialog.Contacts
|
||||
contacts={sortByTitle(members)}
|
||||
|
|
|
@ -188,9 +188,9 @@ export function IncomingCallBar(props: PropsType): JSX.Element | null {
|
|||
case CallMode.Direct:
|
||||
({ isVideoCall } = props);
|
||||
headerNode = <ContactName title={title} />;
|
||||
messageNode = i18n(
|
||||
isVideoCall ? 'incomingVideoCall' : 'incomingAudioCall'
|
||||
);
|
||||
messageNode = isVideoCall
|
||||
? i18n('incomingVideoCall')
|
||||
: i18n('incomingAudioCall');
|
||||
break;
|
||||
case CallMode.Group: {
|
||||
const { otherMembersRung, ringer } = props;
|
||||
|
|
|
@ -23,7 +23,8 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
|||
renderText: overrideProps.renderText,
|
||||
});
|
||||
|
||||
// eslint-disable-next-line react/function-component-definition
|
||||
// eslint-disable-next-line max-len
|
||||
// eslint-disable-next-line react/function-component-definition, local-rules/valid-i18n-keys
|
||||
const Template: Story<Props> = args => <Intl {...args} />;
|
||||
|
||||
export const NoReplacements = Template.bind({});
|
||||
|
|
|
@ -88,6 +88,7 @@ export class Intl extends React.Component<Props> {
|
|||
return intl.formatMessage({ id }, components);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line local-rules/valid-i18n-keys
|
||||
const text = i18n(id);
|
||||
const results: Array<
|
||||
string | JSX.Element | Array<string | JSX.Element> | null
|
||||
|
|
|
@ -87,7 +87,7 @@ export function LeftPaneSearchInput({
|
|||
inputRef.current?.focus();
|
||||
};
|
||||
|
||||
const label = i18n(searchConversation ? 'searchIn' : 'search');
|
||||
const label = searchConversation ? i18n('searchIn') : i18n('search');
|
||||
|
||||
return (
|
||||
<SearchInput
|
||||
|
|
|
@ -418,6 +418,7 @@ export function ProfileEditor({
|
|||
<Emoji shortName={defaultBio.shortName} size={24} />
|
||||
</div>
|
||||
}
|
||||
// eslint-disable-next-line local-rules/valid-i18n-keys
|
||||
label={i18n(defaultBio.i18nLabel)}
|
||||
onClick={() => {
|
||||
const emojiData = getEmojiData(defaultBio.shortName, skinTone);
|
||||
|
@ -425,6 +426,7 @@ export function ProfileEditor({
|
|||
setStagedProfile(profileData => ({
|
||||
...profileData,
|
||||
aboutEmoji: unifiedToEmoji(emojiData.unified),
|
||||
// eslint-disable-next-line local-rules/valid-i18n-keys
|
||||
aboutText: i18n(defaultBio.i18nLabel),
|
||||
}));
|
||||
}}
|
||||
|
|
|
@ -64,7 +64,6 @@ export function SafetyNumberViewer({
|
|||
);
|
||||
|
||||
const { isVerified } = contact;
|
||||
const verifiedStatusKey = isVerified ? 'isVerified' : 'isNotVerified';
|
||||
const verifyButtonText = isVerified ? i18n('unverify') : i18n('verify');
|
||||
|
||||
return (
|
||||
|
@ -79,7 +78,12 @@ export function SafetyNumberViewer({
|
|||
) : (
|
||||
<span className="module-SafetyNumberViewer__icon--shield" />
|
||||
)}
|
||||
<Intl i18n={i18n} id={verifiedStatusKey} components={[boldName]} />
|
||||
{}
|
||||
{isVerified ? (
|
||||
<Intl i18n={i18n} id="isVerified" components={[boldName]} />
|
||||
) : (
|
||||
<Intl i18n={i18n} id="isNotVerified" components={[boldName]} />
|
||||
)}
|
||||
</div>
|
||||
<div className="module-SafetyNumberViewer__button">
|
||||
<Button
|
||||
|
|
|
@ -319,6 +319,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)}
|
||||
</div>
|
||||
<div className="module-shortcut-guide__shortcut__key-container">
|
||||
|
|
|
@ -815,6 +815,7 @@ export function EditMyStoryPrivacy({
|
|||
}: EditMyStoryPrivacyPropsType): JSX.Element {
|
||||
const disclaimerElement = (
|
||||
<div className="StoriesSettingsModal__disclaimer">
|
||||
{/* eslint-disable-next-line local-rules/valid-i18n-keys */}
|
||||
<Intl
|
||||
components={{
|
||||
learnMore: (
|
||||
|
|
|
@ -114,6 +114,7 @@ export function StoryDetailsModal({
|
|||
return (
|
||||
<div key={i18nKey} className="StoryDetailsModal__contact-group">
|
||||
<div className="StoryDetailsModal__contact-group__header">
|
||||
{/* eslint-disable-next-line local-rules/valid-i18n-keys */}
|
||||
{i18n(i18nKey)}
|
||||
</div>
|
||||
{sortedContacts.map(status => {
|
||||
|
|
|
@ -47,6 +47,7 @@ export function WhatsNewModal({
|
|||
const { key, components } = releaseNotes.features[0];
|
||||
contentNode = (
|
||||
<p>
|
||||
{/* eslint-disable-next-line local-rules/valid-i18n-keys */}
|
||||
<Intl
|
||||
i18n={i18n}
|
||||
id={key}
|
||||
|
@ -60,6 +61,7 @@ export function WhatsNewModal({
|
|||
<ul>
|
||||
{releaseNotes.features.map(({ key, components }) => (
|
||||
<li key={key}>
|
||||
{/* eslint-disable-next-line local-rules/valid-i18n-keys */}
|
||||
<Intl
|
||||
i18n={i18n}
|
||||
id={key}
|
||||
|
|
|
@ -24,10 +24,6 @@ export type PropsType = {
|
|||
export function DeliveryIssueDialog(props: PropsType): React.ReactElement {
|
||||
const { i18n, inGroup, sender, onClose } = props;
|
||||
|
||||
const key = inGroup
|
||||
? 'DeliveryIssue--summary--group'
|
||||
: 'DeliveryIssue--summary';
|
||||
|
||||
// Focus first button after initial render, restore focus on teardown
|
||||
const [focusRef] = useRestoreFocus();
|
||||
|
||||
|
@ -56,6 +52,10 @@ export function DeliveryIssueDialog(props: PropsType): React.ReactElement {
|
|||
</>
|
||||
);
|
||||
|
||||
const intlComponents = {
|
||||
sender: <Emojify text={sender.title} />,
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
modalName="DeliveryIssueDialog"
|
||||
|
@ -77,13 +77,19 @@ export function DeliveryIssueDialog(props: PropsType): React.ReactElement {
|
|||
{i18n('DeliveryIssue--title')}
|
||||
</div>
|
||||
<div className="module-delivery-issue-dialog__description">
|
||||
<Intl
|
||||
id={key}
|
||||
components={{
|
||||
sender: <Emojify text={sender.title} />,
|
||||
}}
|
||||
i18n={i18n}
|
||||
/>
|
||||
{inGroup ? (
|
||||
<Intl
|
||||
id="DeliveryIssue--summary--group"
|
||||
components={intlComponents}
|
||||
i18n={i18n}
|
||||
/>
|
||||
) : (
|
||||
<Intl
|
||||
id="DeliveryIssue--summary"
|
||||
components={intlComponents}
|
||||
i18n={i18n}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
</Modal>
|
||||
|
|
|
@ -75,20 +75,24 @@ export class GroupNotification extends React.Component<Props> {
|
|||
throw new Error('Group update is missing contacts');
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-case-declarations
|
||||
const otherPeopleNotifMsg =
|
||||
otherPeople.length === 1
|
||||
? 'joinedTheGroup'
|
||||
: 'multipleJoinedTheGroup';
|
||||
|
||||
return (
|
||||
<>
|
||||
{otherPeople.length > 0 && (
|
||||
<Intl
|
||||
i18n={i18n}
|
||||
id={otherPeopleNotifMsg}
|
||||
components={[otherPeopleWithCommas]}
|
||||
/>
|
||||
<>
|
||||
{otherPeople.length === 1 ? (
|
||||
<Intl
|
||||
i18n={i18n}
|
||||
id="joinedTheGroup"
|
||||
components={[otherPeopleWithCommas]}
|
||||
/>
|
||||
) : (
|
||||
<Intl
|
||||
i18n={i18n}
|
||||
id="multipleJoinedTheGroup"
|
||||
components={[otherPeopleWithCommas]}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{contactsIncludesMe && (
|
||||
<div className="module-group-notification__change">
|
||||
|
@ -106,12 +110,18 @@ export class GroupNotification extends React.Component<Props> {
|
|||
throw new Error('Group update is missing contacts');
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-case-declarations
|
||||
const leftKey =
|
||||
contacts.length > 1 ? 'multipleLeftTheGroup' : 'leftTheGroup';
|
||||
|
||||
return (
|
||||
<Intl i18n={i18n} id={leftKey} components={[otherPeopleWithCommas]} />
|
||||
return contacts.length > 1 ? (
|
||||
<Intl
|
||||
id="multipleLeftTheGroup"
|
||||
i18n={i18n}
|
||||
components={[otherPeopleWithCommas]}
|
||||
/>
|
||||
) : (
|
||||
<Intl
|
||||
id="leftTheGroup"
|
||||
i18n={i18n}
|
||||
components={[otherPeopleWithCommas]}
|
||||
/>
|
||||
);
|
||||
case 'general':
|
||||
return;
|
||||
|
|
|
@ -57,6 +57,7 @@ function renderStringToIntl(
|
|||
i18n: LocalizerType,
|
||||
components?: Array<FullJSXType> | ReplacementValuesType<FullJSXType>
|
||||
): FullJSXType {
|
||||
// eslint-disable-next-line local-rules/valid-i18n-keys
|
||||
return <Intl id={id} i18n={i18n} components={components} />;
|
||||
}
|
||||
|
||||
|
|
|
@ -189,6 +189,7 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|||
onMouseUp={() => setIsDown(false)}
|
||||
onMouseLeave={() => setIsDown(false)}
|
||||
tabIndex={0}
|
||||
// eslint-disable-next-line local-rules/valid-i18n-keys
|
||||
aria-label={i18n(label)}
|
||||
>
|
||||
{children}
|
||||
|
|
|
@ -225,6 +225,7 @@ export class MessageDetail extends React.Component<Props> {
|
|||
`module-message-detail__contact-group__header--${sendStatus}`
|
||||
)}
|
||||
>
|
||||
{/* eslint-disable-next-line local-rules/valid-i18n-keys */}
|
||||
{i18n(i18nKey)}
|
||||
</div>
|
||||
{sortedContacts.map(contact => this.renderContact(contact))}
|
||||
|
|
|
@ -26,11 +26,13 @@ export function RemoveGroupMemberConfirmationDialog({
|
|||
onClose,
|
||||
onRemove,
|
||||
}: PropsType): JSX.Element {
|
||||
const descriptionKey = isAccessControlEnabled(
|
||||
const accessControlEnabled = isAccessControlEnabled(
|
||||
group.accessControlAddFromInviteLink
|
||||
)
|
||||
? 'RemoveGroupMemberConfirmation__description__with-link'
|
||||
: 'RemoveGroupMemberConfirmation__description';
|
||||
);
|
||||
|
||||
const intlComponents = {
|
||||
name: <ContactName title={conversation.title} />,
|
||||
};
|
||||
|
||||
return (
|
||||
<ConfirmationDialog
|
||||
|
@ -45,13 +47,19 @@ export function RemoveGroupMemberConfirmationDialog({
|
|||
i18n={i18n}
|
||||
onClose={onClose}
|
||||
title={
|
||||
<Intl
|
||||
i18n={i18n}
|
||||
id={descriptionKey}
|
||||
components={{
|
||||
name: <ContactName title={conversation.title} />,
|
||||
}}
|
||||
/>
|
||||
accessControlEnabled ? (
|
||||
<Intl
|
||||
i18n={i18n}
|
||||
id="RemoveGroupMemberConfirmation__description__with-link"
|
||||
components={intlComponents}
|
||||
/>
|
||||
) : (
|
||||
<Intl
|
||||
i18n={i18n}
|
||||
id="RemoveGroupMemberConfirmation__description"
|
||||
components={intlComponents}
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -43,6 +43,7 @@ export function SafetyNumberNotification({
|
|||
<SystemMessage
|
||||
icon="safety-number"
|
||||
contents={
|
||||
// eslint-disable-next-line local-rules/valid-i18n-keys
|
||||
<Intl
|
||||
id={changeKey}
|
||||
components={[
|
||||
|
|
|
@ -55,6 +55,7 @@ export function TimerNotification(props: Props): JSX.Element {
|
|||
switch (type) {
|
||||
case 'fromOther':
|
||||
message = (
|
||||
// eslint-disable-next-line local-rules/valid-i18n-keys
|
||||
<Intl
|
||||
i18n={i18n}
|
||||
id={changeKey}
|
||||
|
|
|
@ -50,6 +50,7 @@ export function UnsupportedMessage({
|
|||
<SystemMessage
|
||||
icon={icon}
|
||||
contents={
|
||||
// eslint-disable-next-line local-rules/valid-i18n-keys
|
||||
<Intl
|
||||
id={stringId}
|
||||
components={[
|
||||
|
|
|
@ -47,6 +47,7 @@ export class VerificationNotification extends React.Component<Props> {
|
|||
const id = this.getStringId();
|
||||
|
||||
return (
|
||||
// eslint-disable-next-line local-rules/valid-i18n-keys
|
||||
<Intl
|
||||
id={id}
|
||||
components={[
|
||||
|
|
|
@ -415,11 +415,13 @@ export function ConversationDetails({
|
|||
icon={IconType.timer}
|
||||
/>
|
||||
}
|
||||
info={i18n(
|
||||
info={
|
||||
isGroup
|
||||
? 'ConversationDetails--disappearing-messages-info--group'
|
||||
: 'ConversationDetails--disappearing-messages-info--direct'
|
||||
)}
|
||||
? i18n('ConversationDetails--disappearing-messages-info--group')
|
||||
: i18n(
|
||||
'ConversationDetails--disappearing-messages-info--direct'
|
||||
)
|
||||
}
|
||||
label={i18n('ConversationDetails--disappearing-messages-label')}
|
||||
right={
|
||||
<DisappearingTimerSelect
|
||||
|
@ -621,6 +623,7 @@ function ConversationDetailsCallButton({
|
|||
onClick={onClick}
|
||||
variant={ButtonVariant.Details}
|
||||
>
|
||||
{/* eslint-disable-next-line local-rules/valid-i18n-keys */}
|
||||
{i18n(type)}
|
||||
</Button>
|
||||
);
|
||||
|
|
|
@ -285,14 +285,12 @@ function getConfirmationMessage({
|
|||
|
||||
// Requesting a membership since they weren't added by anyone
|
||||
if (membershipType === StageType.DENY_REQUEST) {
|
||||
const key = isAccessControlEnabled(
|
||||
conversation.accessControlAddFromInviteLink
|
||||
)
|
||||
? 'PendingRequests--deny-for--with-link'
|
||||
: 'PendingRequests--deny-for';
|
||||
return i18n(key, {
|
||||
const params = {
|
||||
name: firstMembership.member.title,
|
||||
});
|
||||
};
|
||||
return isAccessControlEnabled(conversation.accessControlAddFromInviteLink)
|
||||
? i18n('PendingRequests--deny-for--with-link', params)
|
||||
: i18n('PendingRequests--deny-for', params);
|
||||
}
|
||||
|
||||
if (membershipType === StageType.APPROVE_REQUEST) {
|
||||
|
|
|
@ -74,7 +74,8 @@ function MediaSection({
|
|||
const header =
|
||||
section.type === 'yearMonth'
|
||||
? date.format(MONTH_FORMAT)
|
||||
: i18n(section.type);
|
||||
: // eslint-disable-next-line local-rules/valid-i18n-keys
|
||||
i18n(section.type);
|
||||
|
||||
return (
|
||||
<AttachmentSection
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue