Enable ESLint rule that enforces t when preferable to Trans (#15253)

GitOrigin-RevId: d11b3f587b462d400a8d68128dc8be342415bf7d
This commit is contained in:
Alf Eaton 2023-10-19 09:33:26 +01:00 committed by Copybot
parent 0c81bccfca
commit 7755203ff7
29 changed files with 170 additions and 172 deletions

View file

@ -114,7 +114,7 @@
//
"files": ["**/frontend/js/**/components/**/*.{js,jsx,ts,tsx}", "**/frontend/js/**/hooks/**/*.{js,jsx,ts,tsx}"],
"rules": {
"@overleaf/no-empty-trans": "off",
"@overleaf/no-empty-trans": "error",
"@overleaf/should-unescape-trans": "error",
// https://astexplorer.net/

View file

@ -92,7 +92,7 @@
"back_to_subscription": "",
"back_to_your_projects": "",
"beta_program_already_participating": "",
"beta_program_benefits": "<0></0>",
"beta_program_benefits": "",
"beta_program_not_participating": "",
"binary_history_error": "",
"blank_project": "",
@ -288,7 +288,7 @@
"dropbox_sync_now_rate_limited": "",
"dropbox_sync_now_running": "",
"dropbox_sync_out": "",
"dropbox_sync_troubleshoot": "<0></0>",
"dropbox_sync_troubleshoot": "",
"dropbox_synced": "",
"dropbox_unlinked_premium_feature": "",
"duplicate_file": "",
@ -305,7 +305,7 @@
"edit_tag": "",
"editing": "",
"editing_captions": "",
"editor_and_pdf": "&",
"editor_and_pdf": "",
"editor_disconected_click_to_reconnect": "",
"editor_only_hide_pdf": "",
"editor_theme": "",
@ -567,7 +567,7 @@
"labels_help_you_to_easily_reference_your_figures": "",
"labels_help_you_to_reference_your_tables": "",
"labs_program_already_participating": "",
"labs_program_benefits": "<0></0>",
"labs_program_benefits": "",
"labs_program_not_participating": "",
"large_or_high-resolution_images_taking_too_long": "",
"last_active": "",
@ -1050,7 +1050,7 @@
"something_went_wrong_loading_pdf_viewer": "",
"something_went_wrong_processing_the_request": "",
"something_went_wrong_rendering_pdf": "",
"something_went_wrong_rendering_pdf_expected": "<0></0>",
"something_went_wrong_rendering_pdf_expected": "",
"something_went_wrong_server": "",
"somthing_went_wrong_compiling": "",
"sorry_your_table_cant_be_displayed_at_the_moment": "",

View file

@ -171,7 +171,7 @@ function LayoutDropdownButton() {
/>
}
icon={<IconSplit />}
text={<Trans i18nKey="editor_and_pdf">&</Trans>}
text={t('editor_and_pdf')}
/>
<LayoutMenuItem

View file

@ -2,7 +2,7 @@ import ControlLabel from 'react-bootstrap/lib/ControlLabel'
import { Alert, FormControl } from 'react-bootstrap'
import FormGroup from 'react-bootstrap/lib/FormGroup'
import { useCallback } from 'react'
import { Trans, useTranslation } from 'react-i18next'
import { useTranslation } from 'react-i18next'
import { useFileTreeCreateName } from '../../contexts/file-tree-create-name'
import PropTypes from 'prop-types'
import {
@ -57,7 +57,7 @@ export default function FileTreeCreateNameInput({
{touchedName && !validName && (
<Alert bsStyle="danger" className="row-spaced-small">
<Trans i18nKey="files_cannot_include_invalid_characters" />
{t('files_cannot_include_invalid_characters')}
</Alert>
)}
@ -77,6 +77,8 @@ FileTreeCreateNameInput.propTypes = {
}
function ErrorMessage({ error }) {
const { t } = useTranslation()
// if (typeof error === 'string') {
// return error
// }
@ -85,21 +87,21 @@ function ErrorMessage({ error }) {
case DuplicateFilenameError:
return (
<Alert bsStyle="danger" className="row-spaced-small">
<Trans i18nKey="file_already_exists" />
{t('file_already_exists')}
</Alert>
)
case InvalidFilenameError:
return (
<Alert bsStyle="danger" className="row-spaced-small">
<Trans i18nKey="files_cannot_include_invalid_characters" />
{t('files_cannot_include_invalid_characters')}
</Alert>
)
case BlockedFilenameError:
return (
<Alert bsStyle="danger" className="row-spaced-small">
<Trans i18nKey="blocked_filename" />
{t('blocked_filename')}
</Alert>
)

View file

@ -154,21 +154,15 @@ function CompileTimeoutMessages() {
content={
<div>
<div>
<span>
<Trans i18nKey="your_project_near_compile_timeout_limit" />
</span>
<span>{t('your_project_near_compile_timeout_limit')}</span>
</div>
{showNewCompileTimeoutUI === 'active' ? (
<>
<strong>
<Trans i18nKey="upgrade_for_12x_more_compile_time" />
</strong>
<strong>{t('upgrade_for_12x_more_compile_time')}</strong>
{'. '}
</>
) : (
<strong>
<Trans i18nKey="upgrade_for_plenty_more_compile_time" />
</strong>
<strong>{t('upgrade_for_plenty_more_compile_time')}</strong>
)}
</div>
}
@ -204,7 +198,7 @@ function CompileTimeoutMessages() {
shouldUnescape
tOptions={{ interpolation: { escapeValue: true } }}
/>{' '}
<Trans i18nKey="and_you_can_upgrade_for_plenty_more_compile_time" />
{t('and_you_can_upgrade_for_plenty_more_compile_time')}
</p>
</div>
}
@ -229,7 +223,9 @@ function CompileTimeoutMessages() {
/>
</p>
<p className="row-spaced">
<Trans i18nKey="tell_the_project_owner_to_upgrade_plan_for_more_compile_time" />
{t(
'tell_the_project_owner_to_upgrade_plan_for_more_compile_time'
)}
</p>
</div>
}

View file

@ -19,13 +19,17 @@ function PdfPreviewError({ error }) {
headerTitle={t('pdf_rendering_error')}
formattedContent={
<>
<Trans i18nKey="something_went_wrong_rendering_pdf_expected">
<Trans
i18nKey="something_went_wrong_rendering_pdf_expected"
components={[
// eslint-disable-next-line react/jsx-key
<Button
bsSize="xs"
bsStyle="info"
onClick={() => startCompile()}
/>,
]}
/>
</Trans>
<br />
<br />
<Trans

View file

@ -78,10 +78,10 @@ const CompileTimeout = memo(function CompileTimeout({
</>
) : (
<>
<strong>
<Trans i18nKey="upgrade_for_12x_more_compile_time" />
</strong>{' '}
<Trans i18nKey="plus_additional_collaborators_document_history_track_changes_and_more" />
<strong>{t('upgrade_for_12x_more_compile_time')}</strong>{' '}
{t(
'plus_additional_collaborators_document_history_track_changes_and_more'
)}
</>
)}
</p>

View file

@ -154,9 +154,7 @@ export default function INRBanner({ variant, splitTestName }: INRBannerProps) {
}}
/>
</p>
<p>
<Trans i18nKey="inr_discount_modal_info" />
</p>
<p>{t('inr_discount_modal_info')}</p>
</Modal.Body>
<Modal.Footer>
<Button bsStyle="default" onClick={handleMaybeLater}>

View file

@ -4,7 +4,7 @@ import * as eventTracking from '../../../../infrastructure/event-tracking'
import getMeta from '../../../../utils/meta'
import customLocalStorage from '../../../../infrastructure/local-storage'
import { useProjectListContext } from '../../context/project-list-context'
import { Trans, useTranslation } from 'react-i18next'
import { useTranslation } from 'react-i18next'
const variants = ['did-you-know', 'on-premise', 'people', 'FOMO'] as const
type GroupsAndEnterpriseBannerVariant = typeof variants[number]
@ -64,7 +64,7 @@ export default function GroupsAndEnterpriseBanner() {
return (
<Notification bsStyle="info" onDismiss={handleClose}>
<Notification.Body>
<span>{getText(groupsAndEnterpriseBannerVariant)}</span>
<BannerContent variant={groupsAndEnterpriseBannerVariant} />
</Notification.Body>
<Notification.Action>
<a
@ -85,16 +85,40 @@ function isVariantValid(variant: GroupsAndEnterpriseBannerVariant) {
return variants.includes(variant)
}
function getText(variant: GroupsAndEnterpriseBannerVariant) {
function BannerContent({
variant,
}: {
variant: GroupsAndEnterpriseBannerVariant
}) {
const { t } = useTranslation()
switch (variant) {
case 'did-you-know':
return <Trans i18nKey="did_you_know_that_overleaf_offers" />
return <span>{t('did_you_know_that_overleaf_offers')}</span>
case 'on-premise':
return 'Overleaf On-Premises: Does your company want to keep its data within its firewall? Overleaf offers Server Pro, an on-premises solution for companies. Get in touch to learn more.'
return (
<span>
Overleaf On-Premises: Does your company want to keep its data within
its firewall? Overleaf offers Server Pro, an on-premises solution for
companies. Get in touch to learn more.
</span>
)
case 'people':
return 'Other people at your company may already be using Overleaf. Save money with Overleaf group and company-wide subscriptions. Request more information.'
return (
<span>
Other people at your company may already be using Overleaf. Save money
with Overleaf group and company-wide subscriptions. Request more
information.
</span>
)
case 'FOMO':
return 'Why do Fortune 500 companies and top research institutions trust Overleaf to streamline their collaboration? Get in touch to learn more.'
return (
<span>
Why do Fortune 500 companies and top research institutions trust
Overleaf to streamline their collaboration? Get in touch to learn
more.
</span>
)
}
}

View file

@ -1,4 +1,4 @@
import { useTranslation, Trans } from 'react-i18next'
import { Trans, useTranslation } from 'react-i18next'
import { useUserContext } from '../../../shared/context/user-context'
function BetaProgramSection() {
@ -10,9 +10,8 @@ function BetaProgramSection() {
<h3>{t('sharelatex_beta_program')}</h3>
{betaProgram ? null : (
<p className="small">
<Trans i18nKey="beta_program_benefits">
<span />
</Trans>
{/* eslint-disable-next-line react/jsx-key */}
<Trans i18nKey="beta_program_benefits" components={[<span />]} />
</p>
)}
<p className="small">

View file

@ -1,4 +1,4 @@
import { useTranslation, Trans } from 'react-i18next'
import { Trans, useTranslation } from 'react-i18next'
import { useUserContext } from '../../../shared/context/user-context'
function LabsProgramSection() {
@ -10,9 +10,8 @@ function LabsProgramSection() {
<h3>{t('overleaf_labs')}</h3>
{labsProgram ? null : (
<p className="small">
<Trans i18nKey="labs_program_benefits">
<span />
</Trans>
{/* eslint-disable-next-line react/jsx-key */}
<Trans i18nKey="labs_program_benefits" components={[<span />]} />
</p>
)}
<p className="small">

View file

@ -7,13 +7,13 @@ export default function AddCollaboratorsUpgradeContentDefault() {
return (
<>
<p className="text-center">
<Trans i18nKey="need_to_upgrade_for_more_collabs" />. {t('also')}:
{t('need_to_upgrade_for_more_collabs')}. {t('also')}:
</p>
<ul className="list-unstyled">
<li>
<Icon type="check" />
&nbsp;
<Trans i18nKey="unlimited_projects" />
{t('unlimited_projects')}
</li>
<li>
<Icon type="check" />
@ -28,22 +28,22 @@ export default function AddCollaboratorsUpgradeContentDefault() {
<li>
<Icon type="check" />
&nbsp;
<Trans i18nKey="full_doc_history" />
{t('full_doc_history')}
</li>
<li>
<Icon type="check" />
&nbsp;
<Trans i18nKey="sync_to_dropbox" />
{t('sync_to_dropbox')}
</li>
<li>
<Icon type="check" />
&nbsp;
<Trans i18nKey="sync_to_github" />
{t('sync_to_github')}
</li>
<li>
<Icon type="check" />
&nbsp;
<Trans i18nKey="compile_larger_projects" />
{t('compile_larger_projects')}
</li>
</ul>
</>

View file

@ -1,13 +1,15 @@
import Icon from '../../../shared/components/icon'
import { Trans } from 'react-i18next'
import { Trans, useTranslation } from 'react-i18next'
export default function AddCollaboratorsUpgradeContentVariant() {
const { t } = useTranslation()
return (
<>
<div className="row">
<div className="col-xs-10 col-xs-offset-1">
<p className="text-center">
<Trans i18nKey="need_to_upgrade_for_more_collabs_variant" />
{t('need_to_upgrade_for_more_collabs_variant')}
</p>
</div>
</div>
@ -16,7 +18,7 @@ export default function AddCollaboratorsUpgradeContentVariant() {
<li>
<Icon type="check" />
&nbsp;
<Trans i18nKey="unlimited_projects" />
{t('unlimited_projects')}
</li>
<li>
<Icon type="check" />
@ -31,24 +33,24 @@ export default function AddCollaboratorsUpgradeContentVariant() {
<li>
<Icon type="check" />
&nbsp;
<Trans i18nKey="full_doc_history" />
{t('full_doc_history')}
</li>
</ul>
<ul className="list-unstyled col-xs-5">
<li>
<Icon type="check" />
&nbsp;
<Trans i18nKey="sync_to_dropbox" />
{t('sync_to_dropbox')}
</li>
<li>
<Icon type="check" />
&nbsp;
<Trans i18nKey="sync_to_github" />
{t('sync_to_github')}
</li>
<li>
<Icon type="check" />
&nbsp;
<Trans i18nKey="compile_larger_projects" />
{t('compile_larger_projects')}
</li>
</ul>
</div>

View file

@ -1,5 +1,5 @@
import { useState } from 'react'
import { Trans } from 'react-i18next'
import { useTranslation } from 'react-i18next'
import { Button } from 'react-bootstrap'
import PropTypes from 'prop-types'
@ -12,6 +12,7 @@ import AddCollaboratorsUpgradeContentVariant from './add-collaborators-upgrade-c
import { useSplitTestContext } from '../../../shared/context/split-test-context'
export default function AddCollaboratorsUpgrade() {
const { t } = useTranslation()
const user = useUserContext({
allowedFreeTrial: PropTypes.bool,
})
@ -45,14 +46,12 @@ export default function AddCollaboratorsUpgrade() {
setStartedFreeTrial(true)
}}
>
<Trans i18nKey="upgrade" />
{t('upgrade')}
</Button>
)}
</p>
{startedFreeTrial && (
<p className="small">
<Trans i18nKey="refresh_page_after_starting_free_trial" />
</p>
<p className="small">{t('refresh_page_after_starting_free_trial')}</p>
)}
</div>
)

View file

@ -1,5 +1,5 @@
import { useState, useMemo } from 'react'
import { useTranslation, Trans } from 'react-i18next'
import { useTranslation } from 'react-i18next'
import { Form, FormGroup, FormControl, Button } from 'react-bootstrap'
import { useMultipleSelection } from 'downshift'
import { useShareProjectContext } from './share-project-modal'
@ -152,7 +152,7 @@ export default function AddCollaborators() {
</FormControl>
<span>&nbsp;&nbsp;</span>
<Button type="submit" bsStyle="primary">
<Trans i18nKey="share" />
{t('share')}
</Button>
</div>
</FormGroup>

View file

@ -1,6 +1,6 @@
import { useState, useEffect } from 'react'
import PropTypes from 'prop-types'
import { Trans, useTranslation } from 'react-i18next'
import { useTranslation } from 'react-i18next'
import { useShareProjectContext } from './share-project-modal'
import TransferOwnershipModal from './transfer-ownership-modal'
import { removeMemberFromProject, updateMember } from '../utils/api'
@ -137,7 +137,7 @@ function RemoveMemberAction({ member }) {
<FormControl.Static className="text-center">
<Tooltip
id="remove-collaborator"
description={<Trans i18nKey="remove_collaborator" />}
description={t('remove_collaborator')}
overlayProps={{ placement: 'bottom' }}
>
<Button
@ -163,16 +163,18 @@ RemoveMemberAction.propTypes = {
}
function ChangePrivilegesActions({ handleReset }) {
const { t } = useTranslation()
return (
<div className="text-center">
<Button type="submit" bsSize="sm" bsStyle="primary">
<Trans i18nKey="change_or_cancel-change" />
{t('change_or_cancel-change')}
</Button>
<div className="text-sm">
<Trans i18nKey="change_or_cancel-or" />
{t('change_or_cancel-or')}
&nbsp;
<Button type="button" className="btn-inline-link" onClick={handleReset}>
<Trans i18nKey="change_or_cancel-cancel" />
{t('change_or_cancel-cancel')}
</Button>
</div>
</div>

View file

@ -4,20 +4,21 @@ import { useShareProjectContext } from './share-project-modal'
import Icon from '../../../shared/components/icon'
import { Button, Col, Row } from 'react-bootstrap'
import Tooltip from '../../../shared/components/tooltip'
import { Trans, useTranslation } from 'react-i18next'
import { useTranslation } from 'react-i18next'
import MemberPrivileges from './member-privileges'
import { resendInvite, revokeInvite } from '../utils/api'
import { useProjectContext } from '../../../shared/context/project-context'
import { sendMB } from '../../../infrastructure/event-tracking'
export default function Invite({ invite, isProjectOwner }) {
const { t } = useTranslation()
return (
<Row className="project-invite">
<Col xs={7}>
<div>{invite.email}</div>
<div className="small">
<Trans i18nKey="invite_not_accepted" />
{t('invite_not_accepted')}
.&nbsp;
{isProjectOwner && <ResendInvite invite={invite} />}
</div>
@ -42,6 +43,7 @@ Invite.propTypes = {
}
function ResendInvite({ invite }) {
const { t } = useTranslation()
const { monitorRequest } = useShareProjectContext()
const { _id: projectId } = useProjectContext()
@ -66,7 +68,7 @@ function ResendInvite({ invite }) {
onClick={handleClick}
// ref={buttonRef}
>
<Trans i18nKey="resend" />
{t('resend')}
</Button>
)
}
@ -99,7 +101,7 @@ function RevokeInvite({ invite }) {
return (
<Tooltip
id="revoke-invite"
description={<Trans i18nKey="revoke_invite" />}
description={t('revoke_invite')}
overlayProps={{ placement: 'bottom' }}
>
<Button

View file

@ -1,7 +1,7 @@
import { useCallback, useState, useEffect } from 'react'
import PropTypes from 'prop-types'
import { Button, Col, Row } from 'react-bootstrap'
import { Trans } from 'react-i18next'
import { useTranslation } from 'react-i18next'
import Tooltip from '../../../shared/components/tooltip'
import Icon from '../../../shared/components/icon'
import { useShareProjectContext } from './share-project-modal'
@ -86,10 +86,11 @@ LinkSharing.propTypes = {
}
function PrivateSharing({ setAccessLevel, inflight, projectId }) {
const { t } = useTranslation()
return (
<Row className="public-access-level">
<Col xs={12} className="text-center">
<Trans i18nKey="link_sharing_is_off" />
{t('link_sharing_is_off')}
<span>&nbsp;&nbsp;</span>
<Button
type="button"
@ -101,7 +102,7 @@ function PrivateSharing({ setAccessLevel, inflight, projectId }) {
}}
disabled={inflight}
>
<Trans i18nKey="turn_on_link_sharing" />
{t('turn_on_link_sharing')}
</Button>
<span>&nbsp;&nbsp;</span>
<LinkSharingInfo />
@ -117,6 +118,7 @@ PrivateSharing.propTypes = {
}
function TokenBasedSharing({ setAccessLevel, inflight, canAddCollaborators }) {
const { t } = useTranslation()
const { _id: projectId } = useProjectContext()
const [tokens, setTokens] = useState(null)
@ -132,9 +134,7 @@ function TokenBasedSharing({ setAccessLevel, inflight, canAddCollaborators }) {
return (
<Row className="public-access-level">
<Col xs={12} className="text-center">
<strong>
<Trans i18nKey="link_sharing_is_on" />
</strong>
<strong>{t('link_sharing_is_on')}</strong>
<span>&nbsp;&nbsp;</span>
<Button
bsStyle="link"
@ -142,16 +142,14 @@ function TokenBasedSharing({ setAccessLevel, inflight, canAddCollaborators }) {
onClick={() => setAccessLevel('private')}
disabled={inflight}
>
<Trans i18nKey="turn_off_link_sharing" />
{t('turn_off_link_sharing')}
</Button>
<span>&nbsp;&nbsp;</span>
<LinkSharingInfo />
</Col>
<Col xs={12} className="access-token-display-area">
<div className="access-token-wrapper">
<strong>
<Trans i18nKey="anyone_with_link_can_edit" />
</strong>
<strong>{t('anyone_with_link_can_edit')}</strong>
<AccessToken
token={tokens?.readAndWrite}
path="/"
@ -159,9 +157,7 @@ function TokenBasedSharing({ setAccessLevel, inflight, canAddCollaborators }) {
/>
</div>
<div className="access-token-wrapper">
<strong>
<Trans i18nKey="anyone_with_link_can_view" />
</strong>
<strong>{t('anyone_with_link_can_view')}</strong>
<AccessToken
token={tokens?.readOnly}
path="/read/"
@ -180,16 +176,14 @@ TokenBasedSharing.propTypes = {
}
function LegacySharing({ accessLevel, setAccessLevel, inflight }) {
const { t } = useTranslation()
return (
<Row className="public-access-level">
<Col xs={12} className="text-center">
<strong>
{accessLevel === 'readAndWrite' && (
<Trans i18nKey="this_project_is_public" />
)}
{accessLevel === 'readOnly' && (
<Trans i18nKey="this_project_is_public_read_only" />
)}
{accessLevel === 'readAndWrite' && t('this_project_is_public')}
{accessLevel === 'readOnly' && t('this_project_is_public_read_only')}
</strong>
<span>&nbsp;&nbsp;</span>
<Button
@ -199,7 +193,7 @@ function LegacySharing({ accessLevel, setAccessLevel, inflight }) {
onClick={() => setAccessLevel('private')}
disabled={inflight}
>
<Trans i18nKey="make_private" />
{t('make_private')}
</Button>
<span>&nbsp;&nbsp;</span>
<LinkSharingInfo />
@ -215,6 +209,7 @@ LegacySharing.propTypes = {
}
export function ReadOnlyTokenLink() {
const { t } = useTranslation()
const { _id: projectId } = useProjectContext()
const [tokens, setTokens] = useState(null)
@ -231,9 +226,7 @@ export function ReadOnlyTokenLink() {
<Row className="public-access-level">
<Col xs={12} className="access-token-display-area">
<div className="access-token-wrapper">
<strong>
<Trans i18nKey="anyone_with_link_can_view" />
</strong>
<strong>{t('anyone_with_link_can_view')}</strong>
<AccessToken
token={tokens?.readOnly}
path="/read/"
@ -246,14 +239,13 @@ export function ReadOnlyTokenLink() {
}
function AccessToken({ token, path, tooltipId }) {
const { t } = useTranslation()
const { isAdmin } = useUserContext()
if (!token) {
return (
<pre className="access-token">
<span>
<Trans i18nKey="loading" />
</span>
<span>{t('loading')}</span>
</pre>
)
}
@ -279,10 +271,12 @@ AccessToken.propTypes = {
}
function LinkSharingInfo() {
const { t } = useTranslation()
return (
<Tooltip
id="link-sharing-info"
description={<Trans i18nKey="learn_more_about_link_sharing" />}
description={t('learn_more_about_link_sharing')}
>
<a
href="/learn/how-to/What_is_Link_Sharing%3F"

View file

@ -1,13 +1,15 @@
import PropTypes from 'prop-types'
import { Trans } from 'react-i18next'
import { useTranslation } from 'react-i18next'
export default function MemberPrivileges({ privileges }) {
const { t } = useTranslation()
switch (privileges) {
case 'readAndWrite':
return <Trans i18nKey="can_edit" />
return t('can_edit')
case 'readOnly':
return <Trans i18nKey="read_only" />
return t('read_only')
default:
return null

View file

@ -1,15 +1,16 @@
import { useProjectContext } from '../../../shared/context/project-context'
import { Col, Row } from 'react-bootstrap'
import { Trans } from 'react-i18next'
import { useTranslation } from 'react-i18next'
export default function OwnerInfo() {
const { t } = useTranslation()
const { owner } = useProjectContext()
return (
<Row className="project-member">
<Col xs={7}>{owner?.email}</Col>
<Col xs={3} className="text-left">
<Trans i18nKey="owner" />
{t('owner')}
</Col>
</Row>
)

View file

@ -1,6 +1,6 @@
import { useEffect, useMemo, useState, useRef, useCallback } from 'react'
import PropTypes from 'prop-types'
import { Trans, useTranslation } from 'react-i18next'
import { useTranslation } from 'react-i18next'
import { matchSorter } from 'match-sorter'
import { useCombobox } from 'downshift'
import classnames from 'classnames'
@ -19,6 +19,7 @@ export default function SelectCollaborators({
placeholder,
multipleSelectionProps,
}) {
const { t } = useTranslation()
const {
getSelectedItemProps,
getDropdownProps,
@ -141,7 +142,7 @@ export default function SelectCollaborators({
<div className="tags-input">
{/* eslint-disable-next-line jsx-a11y/label-has-for */}
<label className="small" {...getLabelProps()}>
<Trans i18nKey="share_with_your_collabs" />
{t('share_with_your_collabs')}
&nbsp;
{loading && <Icon type="refresh" spin />}
</label>

View file

@ -1,6 +1,6 @@
import { Col, Row } from 'react-bootstrap'
import PropTypes from 'prop-types'
import { Trans } from 'react-i18next'
import { useTranslation } from 'react-i18next'
import { useProjectContext } from '../../../shared/context/project-context'
export default function SendInvitesNotice() {
@ -16,12 +16,13 @@ export default function SendInvitesNotice() {
}
function AccessLevel({ level }) {
const { t } = useTranslation()
switch (level) {
case 'private':
return <Trans i18nKey="to_add_more_collaborators" />
return t('to_add_more_collaborators')
case 'tokenBased':
return <Trans i18nKey="to_change_access_permissions" />
return t('to_change_access_permissions')
default:
return null

View file

@ -1,5 +1,5 @@
import { Button, Modal, Grid } from 'react-bootstrap'
import { Trans } from 'react-i18next'
import { useTranslation } from 'react-i18next'
import Icon from '../../../shared/components/icon'
import AccessibleModal from '../../../shared/components/accessible-modal'
import PropTypes from 'prop-types'
@ -23,6 +23,8 @@ export default function ShareProjectModalContent({
inFlight,
error,
}) {
const { t } = useTranslation()
const { isRestrictedTokenMember } = useEditorContext({
isRestrictedTokenMember: PropTypes.bool,
})
@ -30,9 +32,7 @@ export default function ShareProjectModalContent({
return (
<AccessibleModal show={show} onHide={cancel} animation={animation}>
<Modal.Header closeButton>
<Modal.Title>
<Trans i18nKey="share_project" />
</Modal.Title>
<Modal.Title>{t('share_project')}</Modal.Title>
</Modal.Header>
<Modal.Body className="modal-body-share">
@ -65,7 +65,7 @@ export default function ShareProjectModalContent({
className="btn-secondary"
disabled={inFlight}
>
<Trans i18nKey="close" />
{t('close')}
</Button>
</div>
</Modal.Footer>
@ -81,24 +81,26 @@ ShareProjectModalContent.propTypes = {
}
function ErrorMessage({ error }) {
const { t } = useTranslation()
switch (error) {
case 'cannot_invite_non_user':
return <Trans i18nKey="cannot_invite_non_user" />
return t('cannot_invite_non_user')
case 'cannot_verify_user_not_robot':
return <Trans i18nKey="cannot_verify_user_not_robot" />
return t('cannot_verify_user_not_robot')
case 'cannot_invite_self':
return <Trans i18nKey="cannot_invite_self" />
return t('cannot_invite_self')
case 'invalid_email':
return <Trans i18nKey="invalid_email" />
return t('invalid_email')
case 'too_many_requests':
return <Trans i18nKey="too_many_requests" />
return t('too_many_requests')
default:
return <Trans i18nKey="generic_something_went_wrong" />
return t('generic_something_went_wrong')
}
}
ErrorMessage.propTypes = {

View file

@ -1,6 +1,6 @@
import { useState } from 'react'
import { Modal, Button } from 'react-bootstrap'
import { Trans } from 'react-i18next'
import { Trans, useTranslation } from 'react-i18next'
import PropTypes from 'prop-types'
import Icon from '../../../shared/components/icon'
import { transferProjectOwnership } from '../utils/api'
@ -9,6 +9,8 @@ import { useProjectContext } from '../../../shared/context/project-context'
import { useLocation } from '../../../shared/hooks/use-location'
export default function TransferOwnershipModal({ member, cancel }) {
const { t } = useTranslation()
const [inflight, setInflight] = useState(false)
const [error, setError] = useState(false)
const location = useLocation()
@ -32,9 +34,7 @@ export default function TransferOwnershipModal({ member, cancel }) {
return (
<AccessibleModal show onHide={cancel}>
<Modal.Header closeButton>
<Modal.Title>
<Trans i18nKey="change_project_owner" />
</Modal.Title>
<Modal.Title>{t('change_project_owner')}</Modal.Title>
</Modal.Header>
<Modal.Body>
<p>
@ -47,16 +47,14 @@ export default function TransferOwnershipModal({ member, cancel }) {
tOptions={{ interpolation: { escapeValue: true } }}
/>
</p>
<p>
<Trans i18nKey="project_ownership_transfer_confirmation_2" />
</p>
<p>{t('project_ownership_transfer_confirmation_2')}</p>
</Modal.Body>
<Modal.Footer>
<div className="modal-footer-left">
{inflight && <Icon type="refresh" spin />}
{error && (
<span className="text-danger">
<Trans i18nKey="generic_something_went_wrong" />
{t('generic_something_went_wrong')}
</span>
)}
</div>
@ -68,7 +66,7 @@ export default function TransferOwnershipModal({ member, cancel }) {
onClick={cancel}
disabled={inflight}
>
<Trans i18nKey="cancel" />
{t('cancel')}
</Button>
<Button
type="button"
@ -76,7 +74,7 @@ export default function TransferOwnershipModal({ member, cancel }) {
onClick={confirm}
disabled={inflight}
>
<Trans i18nKey="change_owner" />
{t('change_owner')}
</Button>
</div>
</Modal.Footer>

View file

@ -9,13 +9,9 @@ export const FigureModalHelp = () => {
const { t } = useTranslation()
return (
<>
<p>
<Trans i18nKey="this_tool_helps_you_insert_figures" />
</p>
<p>{t('this_tool_helps_you_insert_figures')}</p>
<b>{t('editing_captions')}</b>
<p>
<Trans i18nKey="when_you_tick_the_include_caption_box" />
</p>
<p>{t('when_you_tick_the_include_caption_box')}</p>
<b>{t('understanding_labels')}</b>
<p>

View file

@ -410,7 +410,7 @@
"edit_tag": "Redigér tag",
"editing": "Redigering",
"editing_captions": "Redigering af billedtekster",
"editor_and_pdf": "Skrivevindue <0></0> PDF",
"editor_and_pdf": "Skrivevindue & PDF",
"editor_disconected_click_to_reconnect": "Skriveprogrammets forbindelse afbrudt, klik hvor som helst for at forbinde igen.",
"editor_only_hide_pdf": "Kun skrivevindue <0>(gem PDF)</0>",
"editor_resources": "Læringsmidler til skriveprogrammet",

View file

@ -412,7 +412,7 @@
"edit_tag": "Schlagwort bearbeiten",
"editing": "Bearbeitung",
"editing_captions": "Beschriftungen bearbeiten",
"editor_and_pdf": "Editor <0></0> PDF",
"editor_and_pdf": "Editor & PDF",
"editor_disconected_click_to_reconnect": "Editor wurde getrennt",
"editor_only_hide_pdf": "Nur Editor <0>(PDF ausblenden)</0>",
"editor_resources": "Editor-Literatur",

View file

@ -460,7 +460,7 @@
"edit_tag": "Edit Tag",
"editing": "Editing",
"editing_captions": "Editing captions",
"editor_and_pdf": "Editor <0></0> PDF",
"editor_and_pdf": "Editor & PDF",
"editor_disconected_click_to_reconnect": "Editor disconnected, click anywhere to reconnect.",
"editor_only_hide_pdf": "Editor only <0>(hide PDF)</0>",
"editor_resources": "Editor Resources",

View file

@ -31,30 +31,6 @@ describe('i18n', function () {
})
describe('Trans', function () {
it('translates a plain string', function () {
const Test = () => {
return (
<div>
<Trans i18nKey="accept" />
</div>
)
}
cy.mount(<Test />)
cy.findByText('Accept')
})
it('uses defaultValues', function () {
const Test = () => {
return (
<div>
<Trans i18nKey="welcome_to_sl" />
</div>
)
}
cy.mount(<Test />)
cy.findByText('Welcome to Overleaf!')
})
it('uses values', function () {
const Test = () => {
return (