use Trans as much as possible to ease lingui upgrade to 4.0

This commit is contained in:
Athou
2023-05-08 12:36:58 +02:00
parent 3d1a1cd033
commit 8b5735f521
27 changed files with 159 additions and 122 deletions

View File

@@ -6,7 +6,7 @@ import { forwardRef, MouseEventHandler, ReactNode } from "react"
interface ActionButtonProps {
className?: string
icon?: ReactNode
label?: string
label?: ReactNode
onClick?: MouseEventHandler
variant?: ActionIconVariant & ButtonVariant
showLabelOnMobile?: boolean

View File

@@ -1,5 +1,5 @@
import { t } from "@lingui/macro"
import { Alert as MantineAlert, Box } from "@mantine/core"
import { Trans } from "@lingui/macro"
import { Box, Alert as MantineAlert } from "@mantine/core"
import { Fragment } from "react"
import { TbAlertCircle, TbAlertTriangle, TbCircleCheck } from "react-icons/tb"
@@ -10,24 +10,24 @@ export interface ErrorsAlertProps {
}
export function Alert(props: ErrorsAlertProps) {
let title: string
let title: React.ReactNode
let color: string
let icon: React.ReactNode
const level = props.level ?? "error"
switch (level) {
case "error":
title = t`Error`
title = <Trans>Error</Trans>
color = "red"
icon = <TbAlertCircle />
break
case "warning":
title = t`Warning`
title = <Trans>Warning</Trans>
color = "orange"
icon = <TbAlertTriangle />
break
case "success":
title = t`Success`
title = <Trans>Success</Trans>
color = "green"
icon = <TbCircleCheck />
break

View File

@@ -1,4 +1,4 @@
import { t, Trans } from "@lingui/macro"
import { Trans } from "@lingui/macro"
import { Box, Button, Checkbox, Group, PasswordInput, Stack, TextInput } from "@mantine/core"
import { useForm } from "@mantine/form"
import { client, errorToStrings } from "app/client"
@@ -29,11 +29,11 @@ export function UserEdit(props: UserEditProps) {
<form onSubmit={form.onSubmit(saveUser.execute)}>
<Stack>
<TextInput label={t`Name`} {...form.getInputProps("name")} required />
<PasswordInput label={t`Password`} {...form.getInputProps("password")} required={!props.user} />
<TextInput type="email" label={t`E-mail`} {...form.getInputProps("email")} />
<Checkbox label={t`Admin`} {...form.getInputProps("admin", { type: "checkbox" })} />
<Checkbox label={t`Enabled`} {...form.getInputProps("enabled", { type: "checkbox" })} />
<TextInput label={<Trans>Name</Trans>} {...form.getInputProps("name")} required />
<PasswordInput label={<Trans>Password</Trans>} {...form.getInputProps("password")} required={!props.user} />
<TextInput type="email" label={<Trans>E-mail</Trans>} {...form.getInputProps("email")} />
<Checkbox label={<Trans>Admin</Trans>} {...form.getInputProps("admin", { type: "checkbox" })} />
<Checkbox label={<Trans>Enabled</Trans>} {...form.getInputProps("enabled", { type: "checkbox" })} />
<Group>
<Button variant="default" onClick={props.onCancel}>

View File

@@ -1,4 +1,4 @@
import { t } from "@lingui/macro"
import { Trans } from "@lingui/macro"
import { openModal } from "@mantine/modals"
import { Constants } from "app/constants"
import {
@@ -234,7 +234,13 @@ export function FeedEntries() {
)
})
useMousetrap("g a", () => dispatch(redirectToRootCategory()))
useMousetrap("?", () => openModal({ title: t`Keyboard shortcuts`, size: "xl", children: <KeyboardShortcutsHelp /> }))
useMousetrap("?", () =>
openModal({
title: <Trans>Keyboard shortcuts</Trans>,
size: "xl",
children: <KeyboardShortcutsHelp />,
})
)
if (!entries) return <Loader />
return (

View File

@@ -1,4 +1,4 @@
import { t, Trans } from "@lingui/macro"
import { Trans } from "@lingui/macro"
import { createStyles, Group } from "@mantine/core"
import { Constants } from "app/constants"
import { markEntriesUpToEntry, markEntry, starEntry } from "app/slices/entries"
@@ -29,6 +29,7 @@ const useStyles = createStyles(theme => ({
}))
const menuId = (entry: Entry) => entry.id
export function FeedEntryContextMenu(props: FeedEntryContextMenuProps) {
const { classes, theme } = useStyles()
const sourceType = useAppSelector(state => state.entries.source.type)
@@ -64,13 +65,13 @@ export function FeedEntryContextMenu(props: FeedEntryContextMenuProps) {
<Item onClick={() => dispatch(starEntry({ entry: props.entry, starred: !props.entry.starred }))}>
<Group>
{props.entry.starred ? <TbStarOff size={iconSize} /> : <TbStar size={iconSize} />}
{props.entry.starred ? t`Unstar` : t`Star`}
{props.entry.starred ? <Trans>Unstar</Trans> : <Trans>Star</Trans>}
</Group>
</Item>
<Item onClick={() => dispatch(markEntry({ entry: props.entry, read: !props.entry.read }))}>
<Group>
{props.entry.read ? <TbEyeOff size={iconSize} /> : <TbEyeCheck size={iconSize} />}
{props.entry.read ? t`Keep unread` : t`Mark as read`}
{props.entry.read ? <Trans>Keep unread</Trans> : <Trans>Mark as read</Trans>}
</Group>
</Item>
<Item onClick={() => dispatch(markEntriesUpToEntry(props.entry))}>

View File

@@ -1,4 +1,4 @@
import { t } from "@lingui/macro"
import { t, Trans } from "@lingui/macro"
import { Group, Indicator, MultiSelect, Popover } from "@mantine/core"
import { useMediaQuery } from "@mantine/hooks"
import { Constants } from "app/constants"
@@ -50,20 +50,20 @@ export function FeedEntryFooter(props: FeedEntryFooterProps) {
{props.entry.markable && (
<ActionButton
icon={props.entry.read ? <TbEyeOff size={18} /> : <TbEyeCheck size={18} />}
label={props.entry.read ? t`Keep unread` : t`Mark as read`}
label={props.entry.read ? <Trans>Keep unread</Trans> : <Trans>Mark as read</Trans>}
onClick={readStatusButtonClicked}
/>
)}
<ActionButton
icon={props.entry.starred ? <TbStarOff size={18} /> : <TbStar size={18} />}
label={props.entry.starred ? t`Unstar` : t`Star`}
label={props.entry.starred ? <Trans>Unstar</Trans> : <Trans>Star</Trans>}
onClick={() => dispatch(starEntry({ entry: props.entry, starred: !props.entry.starred }))}
/>
{showSharingButtons && (
<Popover withArrow withinPortal shadow="md" positionDependencies={[scrollPosition]} closeOnClickOutside={!mobile}>
<Popover.Target>
<ActionButton icon={<TbShare size={18} />} label={t`Share`} />
<ActionButton icon={<TbShare size={18} />} label={<Trans>Share</Trans>} />
</Popover.Target>
<Popover.Dropdown>
<ShareButtons url={props.entry.url} description={props.entry.title} />
@@ -75,7 +75,7 @@ export function FeedEntryFooter(props: FeedEntryFooterProps) {
<Popover withArrow withinPortal shadow="md" positionDependencies={[scrollPosition]} closeOnClickOutside={!mobile}>
<Popover.Target>
<Indicator label={props.entry.tags.length} showZero={false} dot={false} inline size={16}>
<ActionButton icon={<TbTag size={18} />} label={t`Tags`} />
<ActionButton icon={<TbTag size={18} />} label={<Trans>Tags</Trans>} />
</Indicator>
</Popover.Target>
<Popover.Dropdown>
@@ -94,13 +94,13 @@ export function FeedEntryFooter(props: FeedEntryFooterProps) {
)}
<a href={props.entry.url} target="_blank" rel="noreferrer">
<ActionButton icon={<TbExternalLink size={18} />} label={t`Open link`} />
<ActionButton icon={<TbExternalLink size={18} />} label={<Trans>Open link</Trans>} />
</a>
</ButtonToolbar>
<ActionButton
icon={<TbArrowBarToDown size={18} />}
label={t`Mark as read up to here`}
label={<Trans>Mark as read up to here</Trans>}
onClick={() => dispatch(markEntriesUpToEntry(props.entry))}
/>
</Group>

View File

@@ -33,8 +33,8 @@ export function AddCategory() {
<form onSubmit={form.onSubmit(addCategory.execute)}>
<Stack>
<TextInput label={t`Category`} placeholder={t`Category`} {...form.getInputProps("name")} required />
<CategorySelect label={t`Parent`} {...form.getInputProps("parentId")} clearable />
<TextInput label={<Trans>Category</Trans>} placeholder={t`Category`} {...form.getInputProps("name")} required />
<CategorySelect label={<Trans>Parent</Trans>} {...form.getInputProps("parentId")} clearable />
<Group position="center">
<Button variant="default" onClick={() => dispatch(redirectToSelectedSource())}>
<Trans>Cancel</Trans>

View File

@@ -36,9 +36,14 @@ export function ImportOpml() {
<form onSubmit={form.onSubmit(v => importOpml.execute(v.file))}>
<Stack>
<FileInput
label={t`OPML file`}
label={<Trans>OPML file</Trans>}
placeholder={t`OPML file`}
description={t`An opml file is an XML file containing feed URLs and categories. You can get an OPML file by exporting your data from other feed reading services.`}
description={
<Trans>
An opml file is an XML file containing feed URLs and categories. You can get an OPML file by exporting your
data from other feed reading services.
</Trans>
}
{...form.getInputProps("file")}
required
accept="application/xml"

View File

@@ -1,4 +1,4 @@
import { t, Trans } from "@lingui/macro"
import { Trans } from "@lingui/macro"
import { Box, Button, Group, Stack, Stepper, TextInput } from "@mantine/core"
import { useForm } from "@mantine/form"
import { client, errorToStrings } from "app/client"
@@ -74,24 +74,33 @@ export function Subscribe() {
<form onSubmit={nextStep}>
<Stepper active={activeStep} onStepClick={setActiveStep}>
<Stepper.Step
label={t`Analyze feed`}
description={t`Check that the feed is working`}
label={<Trans>Analyze feed</Trans>}
description={<Trans>Check that the feed is working</Trans>}
allowStepSelect={activeStep === 1}
>
<TextInput
label={t`Feed URL`}
label={<Trans>Feed URL</Trans>}
placeholder="http://www.mysite.com/rss"
description={t`The URL for the feed you want to subscribe to. You can also use the website's url directly and CommaFeed will try to find the feed in the page.`}
description={
<Trans>
The URL for the feed you want to subscribe to. You can also use the website's url directly and CommaFeed
will try to find the feed in the page.
</Trans>
}
required
autoFocus
{...step0Form.getInputProps("url")}
/>
</Stepper.Step>
<Stepper.Step label={t`Subscribe`} description={t`Subscribe to the feed`} allowStepSelect={false}>
<Stepper.Step
label={<Trans>Subscribe</Trans>}
description={<Trans>Subscribe to the feed</Trans>}
allowStepSelect={false}
>
<Stack>
<TextInput label={t`Feed URL`} {...step1Form.getInputProps("url")} disabled />
<TextInput label={t`Feed name`} {...step1Form.getInputProps("title")} required autoFocus />
<CategorySelect label={t`Category`} {...step1Form.getInputProps("categoryId")} clearable />
<TextInput label={<Trans>Feed URL</Trans>} {...step1Form.getInputProps("url")} disabled />
<TextInput label={<Trans>Feed name</Trans>} {...step1Form.getInputProps("title")} required autoFocus />
<CategorySelect label={<Trans>Category</Trans>} {...step1Form.getInputProps("categoryId")} clearable />
</Stack>
</Stepper.Step>
</Stepper>

View File

@@ -1,4 +1,4 @@
import { t } from "@lingui/macro"
import { t, Trans } from "@lingui/macro"
import { ActionIcon, Center, Divider, Indicator, Popover, TextInput } from "@mantine/core"
import { useForm } from "@mantine/form"
import { reloadEntries, search } from "app/slices/entries"
@@ -17,6 +17,7 @@ function HeaderDivider() {
}
const iconSize = 18
export function Header() {
const settings = useAppSelector(state => state.user.settings)
const profile = useAppSelector(state => state.user.profile)
@@ -40,26 +41,30 @@ export function Header() {
return (
<Center>
<ButtonToolbar>
<ActionButton icon={<TbRefresh size={iconSize} />} label={t`Refresh`} onClick={() => dispatch(reloadEntries())} />
<ActionButton
icon={<TbRefresh size={iconSize} />}
label={<Trans>Refresh</Trans>}
onClick={() => dispatch(reloadEntries())}
/>
<MarkAllAsReadButton iconSize={iconSize} />
<HeaderDivider />
<ActionButton
icon={settings.readingMode === "all" ? <TbEye size={iconSize} /> : <TbEyeOff size={iconSize} />}
label={settings.readingMode === "all" ? t`All` : t`Unread`}
label={settings.readingMode === "all" ? <Trans>All</Trans> : <Trans>Unread</Trans>}
onClick={() => dispatch(changeReadingMode(settings.readingMode === "all" ? "unread" : "all"))}
/>
<ActionButton
icon={settings.readingOrder === "asc" ? <TbArrowUp size={iconSize} /> : <TbArrowDown size={iconSize} />}
label={settings.readingOrder === "asc" ? t`Asc` : t`Desc`}
label={settings.readingOrder === "asc" ? <Trans>Asc</Trans> : <Trans>Desc</Trans>}
onClick={() => dispatch(changeReadingOrder(settings.readingOrder === "asc" ? "desc" : "asc"))}
/>
<Popover>
<Popover.Target>
<Indicator disabled={!searchFromStore}>
<ActionButton icon={<TbSearch size={iconSize} />} label={t`Search`} />
<ActionButton icon={<TbSearch size={iconSize} />} label={<Trans>Search</Trans>} />
</Indicator>
</Popover.Target>
<Popover.Dropdown>

View File

@@ -1,4 +1,4 @@
import { t, Trans } from "@lingui/macro"
import { Trans } from "@lingui/macro"
import { Button, Code, Group, Modal, Slider, Stack, Text } from "@mantine/core"
import { markAllEntries } from "app/slices/entries"
@@ -17,7 +17,7 @@ export function MarkAllAsReadButton(props: { iconSize: number }) {
return (
<>
<Modal opened={opened} onClose={() => setOpened(false)} title={t`Mark all entries as read`}>
<Modal opened={opened} onClose={() => setOpened(false)} title={<Trans>Mark all entries as read</Trans>}>
<Stack>
<Text size="sm">
{threshold === 0 && (
@@ -72,7 +72,7 @@ export function MarkAllAsReadButton(props: { iconSize: number }) {
</Modal>
<ActionButton
icon={<TbChecks size={props.iconSize} />}
label={t`Mark all as read`}
label={<Trans>Mark all as read</Trans>}
onClick={() => {
setThreshold(0)
setOpened(true)

View File

@@ -1,4 +1,4 @@
import { t, Trans } from "@lingui/macro"
import { Trans } from "@lingui/macro"
import { Box, Divider, Group, Menu, SegmentedControl, SegmentedControlItem, useMantineColorScheme } from "@mantine/core"
import { showNotification } from "@mantine/notifications"
import { client } from "app/client"
@@ -111,7 +111,7 @@ export function ProfileMenu(props: ProfileMenuProps) {
onClick={() =>
client.feed.refreshAll().then(() => {
showNotification({
message: t`Your feeds have been queued for refresh.`,
message: <Trans>Your feeds have been queued for refresh.</Trans>,
color: "green",
autoClose: 1000,
})

View File

@@ -1,4 +1,4 @@
import { t } from "@lingui/macro"
import { Trans } from "@lingui/macro"
import { Divider, Select, SimpleGrid, Stack, Switch } from "@mantine/core"
import { Constants } from "app/constants"
import { changeLanguage, changeScrollMarks, changeScrollSpeed, changeSharingSetting, changeShowRead } from "app/slices/user"
@@ -17,7 +17,7 @@ export function DisplaySettings() {
return (
<Stack>
<Select
description={t`Language`}
description={<Trans>Language</Trans>}
value={language}
data={locales.map(l => ({
value: l.key,
@@ -27,24 +27,24 @@ export function DisplaySettings() {
/>
<Switch
label={t`Scroll smoothly when navigating between entries`}
label={<Trans>Scroll smoothly when navigating between entries</Trans>}
checked={scrollSpeed ? scrollSpeed > 0 : false}
onChange={e => dispatch(changeScrollSpeed(e.currentTarget.checked))}
/>
<Switch
label={t`Show feeds and categories with no unread entries`}
label={<Trans>Show feeds and categories with no unread entries</Trans>}
checked={showRead}
onChange={e => dispatch(changeShowRead(e.currentTarget.checked))}
/>
<Switch
label={t`In expanded view, scrolling through entries mark them as read`}
label={<Trans>In expanded view, scrolling through entries mark them as read</Trans>}
checked={scrollMarks}
onChange={e => dispatch(changeScrollMarks(e.currentTarget.checked))}
/>
<Divider label={t`Sharing sites`} labelPosition="center" />
<Divider label={<Trans>Sharing sites</Trans>} labelPosition="center" />
<SimpleGrid cols={2}>
{(Object.keys(Constants.sharing) as Array<keyof SharingSettings>).map(site => (

View File

@@ -41,13 +41,13 @@ export function ProfileSettings() {
const openDeleteProfileModal = () =>
openConfirmModal({
title: t`Delete account`,
title: <Trans>Delete account</Trans>,
children: (
<Text size="sm">
<Trans>Are you sure you want to delete your account? There's no turning back!</Trans>
</Text>
),
labels: { confirm: t`Confirm`, cancel: t`Cancel` },
labels: { confirm: <Trans>Confirm</Trans>, cancel: <Trans>Cancel</Trans> },
confirmProps: { color: "red" },
onConfirm: () => deleteProfile.execute(),
})
@@ -77,12 +77,16 @@ export function ProfileSettings() {
<form onSubmit={form.onSubmit(saveProfile.execute)}>
<Stack>
<Input.Wrapper label={t`User name`}>
<Input.Wrapper label={<Trans>User name</Trans>}>
<Box>{profile?.name}</Box>
</Input.Wrapper>
<Input.Wrapper
label={t`OPML export`}
description={t`Export your subscriptions and categories as an OPML file that can be imported in other feed reading services`}
label={<Trans>OPML export</Trans>}
description={
<Trans>
Export your subscriptions and categories as an OPML file that can be imported in other feed reading services
</Trans>
}
>
<Box>
<Anchor href="rest/feed/export" download="commafeed_opml.xml">
@@ -91,20 +95,20 @@ export function ProfileSettings() {
</Box>
</Input.Wrapper>
<PasswordInput
label={t`Current password`}
description={t`Enter your current password to change profile settings`}
label={<Trans>Current password</Trans>}
description={<Trans>Enter your current password to change profile settings</Trans>}
required
{...form.getInputProps("currentPassword")}
/>
<TextInput type="email" label={t`E-mail`} {...form.getInputProps("email")} required />
<TextInput type="email" label={<Trans>E-mail</Trans>} {...form.getInputProps("email")} required />
<PasswordInput
label={t`New password`}
description={t`Changing password will generate a new API key`}
label={<Trans>New password</Trans>}
description={<Trans>Changing password will generate a new API key</Trans>}
{...form.getInputProps("newPassword")}
/>
<PasswordInput label={t`Confirm password`} {...form.getInputProps("newPasswordConfirmation")} />
<TextInput label={t`API key`} readOnly value={profile?.apiKey} />
<Checkbox label={t`Generate new API key`} {...form.getInputProps("newApiKey", { type: "checkbox" })} />
<PasswordInput label={<Trans>Confirm password</Trans>} {...form.getInputProps("newPasswordConfirmation")} />
<TextInput label={<Trans>API key</Trans>} readOnly value={profile?.apiKey} />
<Checkbox label={<Trans>Generate new API key</Trans>} {...form.getInputProps("newApiKey", { type: "checkbox" })} />
<Group>
<Button variant="default" onClick={() => dispatch(redirectToSelectedSource())}>

View File

@@ -1,4 +1,4 @@
import { t } from "@lingui/macro"
import { Trans } from "@lingui/macro"
import { Box, Stack } from "@mantine/core"
import { Constants } from "app/constants"
import {
@@ -27,6 +27,7 @@ const expandedIcon = <TbChevronDown size={16} />
const collapsedIcon = <TbChevronRight size={16} />
const errorThreshold = 9
export function Tree() {
const root = useAppSelector(state => state.tree.rootCategory)
const source = useAppSelector(state => state.entries.source)
@@ -63,7 +64,7 @@ export function Tree() {
const allCategoryNode = () => (
<TreeNode
id={Constants.categories.all.id}
name={t`All`}
name={<Trans>All</Trans>}
icon={allIcon}
unread={categoryUnreadCount(root)}
selected={source.type === "category" && source.id === Constants.categories.all.id}
@@ -76,7 +77,7 @@ export function Tree() {
const starredCategoryNode = () => (
<TreeNode
id={Constants.categories.starred.id}
name={t`Starred`}
name={<Trans>Starred</Trans>}
icon={starredIcon}
unread={0}
selected={source.type === "category" && source.id === Constants.categories.starred.id}

View File

@@ -5,8 +5,8 @@ import { UnreadCount } from "./UnreadCount"
interface TreeNodeProps {
id: string
name: string
icon: ReactNode | string
name: ReactNode
icon: ReactNode
unread: number
selected: boolean
expanded?: boolean

View File

@@ -1,4 +1,4 @@
import { t } from "@lingui/macro"
import { t, Trans } from "@lingui/macro"
import { Box, Center, Kbd, TextInput } from "@mantine/core"
import { openSpotlight, SpotlightAction, SpotlightProvider } from "@mantine/spotlight"
import { redirectToFeed } from "app/slices/redirect"
@@ -11,6 +11,7 @@ import { TbSearch } from "react-icons/tb"
export interface TreeSearchProps {
feeds: Subscription[]
}
export function TreeSearch(props: TreeSearchProps) {
const dispatch = useAppDispatch()
@@ -40,7 +41,7 @@ export function TreeSearch(props: TreeSearchProps) {
searchIcon={searchIcon}
searchPlaceholder={t`Search`}
shortcut="ctrl+k"
nothingFoundMessage={t`Nothing found`}
nothingFoundMessage={<Trans>Nothing found</Trans>}
>
<TextInput
placeholder={t`Search`}