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 { interface ActionButtonProps {
className?: string className?: string
icon?: ReactNode icon?: ReactNode
label?: string label?: ReactNode
onClick?: MouseEventHandler onClick?: MouseEventHandler
variant?: ActionIconVariant & ButtonVariant variant?: ActionIconVariant & ButtonVariant
showLabelOnMobile?: boolean showLabelOnMobile?: boolean

View File

@@ -1,5 +1,5 @@
import { t } from "@lingui/macro" import { Trans } from "@lingui/macro"
import { Alert as MantineAlert, Box } from "@mantine/core" import { Box, Alert as MantineAlert } from "@mantine/core"
import { Fragment } from "react" import { Fragment } from "react"
import { TbAlertCircle, TbAlertTriangle, TbCircleCheck } from "react-icons/tb" import { TbAlertCircle, TbAlertTriangle, TbCircleCheck } from "react-icons/tb"
@@ -10,24 +10,24 @@ export interface ErrorsAlertProps {
} }
export function Alert(props: ErrorsAlertProps) { export function Alert(props: ErrorsAlertProps) {
let title: string let title: React.ReactNode
let color: string let color: string
let icon: React.ReactNode let icon: React.ReactNode
const level = props.level ?? "error" const level = props.level ?? "error"
switch (level) { switch (level) {
case "error": case "error":
title = t`Error` title = <Trans>Error</Trans>
color = "red" color = "red"
icon = <TbAlertCircle /> icon = <TbAlertCircle />
break break
case "warning": case "warning":
title = t`Warning` title = <Trans>Warning</Trans>
color = "orange" color = "orange"
icon = <TbAlertTriangle /> icon = <TbAlertTriangle />
break break
case "success": case "success":
title = t`Success` title = <Trans>Success</Trans>
color = "green" color = "green"
icon = <TbCircleCheck /> icon = <TbCircleCheck />
break 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 { Box, Button, Checkbox, Group, PasswordInput, Stack, TextInput } from "@mantine/core"
import { useForm } from "@mantine/form" import { useForm } from "@mantine/form"
import { client, errorToStrings } from "app/client" import { client, errorToStrings } from "app/client"
@@ -29,11 +29,11 @@ export function UserEdit(props: UserEditProps) {
<form onSubmit={form.onSubmit(saveUser.execute)}> <form onSubmit={form.onSubmit(saveUser.execute)}>
<Stack> <Stack>
<TextInput label={t`Name`} {...form.getInputProps("name")} required /> <TextInput label={<Trans>Name</Trans>} {...form.getInputProps("name")} required />
<PasswordInput label={t`Password`} {...form.getInputProps("password")} required={!props.user} /> <PasswordInput label={<Trans>Password</Trans>} {...form.getInputProps("password")} required={!props.user} />
<TextInput type="email" label={t`E-mail`} {...form.getInputProps("email")} /> <TextInput type="email" label={<Trans>E-mail</Trans>} {...form.getInputProps("email")} />
<Checkbox label={t`Admin`} {...form.getInputProps("admin", { type: "checkbox" })} /> <Checkbox label={<Trans>Admin</Trans>} {...form.getInputProps("admin", { type: "checkbox" })} />
<Checkbox label={t`Enabled`} {...form.getInputProps("enabled", { type: "checkbox" })} /> <Checkbox label={<Trans>Enabled</Trans>} {...form.getInputProps("enabled", { type: "checkbox" })} />
<Group> <Group>
<Button variant="default" onClick={props.onCancel}> <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 { openModal } from "@mantine/modals"
import { Constants } from "app/constants" import { Constants } from "app/constants"
import { import {
@@ -234,7 +234,13 @@ export function FeedEntries() {
) )
}) })
useMousetrap("g a", () => dispatch(redirectToRootCategory())) 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 /> if (!entries) return <Loader />
return ( 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 { createStyles, Group } from "@mantine/core"
import { Constants } from "app/constants" import { Constants } from "app/constants"
import { markEntriesUpToEntry, markEntry, starEntry } from "app/slices/entries" import { markEntriesUpToEntry, markEntry, starEntry } from "app/slices/entries"
@@ -29,6 +29,7 @@ const useStyles = createStyles(theme => ({
})) }))
const menuId = (entry: Entry) => entry.id const menuId = (entry: Entry) => entry.id
export function FeedEntryContextMenu(props: FeedEntryContextMenuProps) { export function FeedEntryContextMenu(props: FeedEntryContextMenuProps) {
const { classes, theme } = useStyles() const { classes, theme } = useStyles()
const sourceType = useAppSelector(state => state.entries.source.type) 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 }))}> <Item onClick={() => dispatch(starEntry({ entry: props.entry, starred: !props.entry.starred }))}>
<Group> <Group>
{props.entry.starred ? <TbStarOff size={iconSize} /> : <TbStar size={iconSize} />} {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> </Group>
</Item> </Item>
<Item onClick={() => dispatch(markEntry({ entry: props.entry, read: !props.entry.read }))}> <Item onClick={() => dispatch(markEntry({ entry: props.entry, read: !props.entry.read }))}>
<Group> <Group>
{props.entry.read ? <TbEyeOff size={iconSize} /> : <TbEyeCheck size={iconSize} />} {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> </Group>
</Item> </Item>
<Item onClick={() => dispatch(markEntriesUpToEntry(props.entry))}> <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 { Group, Indicator, MultiSelect, Popover } from "@mantine/core"
import { useMediaQuery } from "@mantine/hooks" import { useMediaQuery } from "@mantine/hooks"
import { Constants } from "app/constants" import { Constants } from "app/constants"
@@ -50,20 +50,20 @@ export function FeedEntryFooter(props: FeedEntryFooterProps) {
{props.entry.markable && ( {props.entry.markable && (
<ActionButton <ActionButton
icon={props.entry.read ? <TbEyeOff size={18} /> : <TbEyeCheck size={18} />} 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} onClick={readStatusButtonClicked}
/> />
)} )}
<ActionButton <ActionButton
icon={props.entry.starred ? <TbStarOff size={18} /> : <TbStar size={18} />} 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 }))} onClick={() => dispatch(starEntry({ entry: props.entry, starred: !props.entry.starred }))}
/> />
{showSharingButtons && ( {showSharingButtons && (
<Popover withArrow withinPortal shadow="md" positionDependencies={[scrollPosition]} closeOnClickOutside={!mobile}> <Popover withArrow withinPortal shadow="md" positionDependencies={[scrollPosition]} closeOnClickOutside={!mobile}>
<Popover.Target> <Popover.Target>
<ActionButton icon={<TbShare size={18} />} label={t`Share`} /> <ActionButton icon={<TbShare size={18} />} label={<Trans>Share</Trans>} />
</Popover.Target> </Popover.Target>
<Popover.Dropdown> <Popover.Dropdown>
<ShareButtons url={props.entry.url} description={props.entry.title} /> <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 withArrow withinPortal shadow="md" positionDependencies={[scrollPosition]} closeOnClickOutside={!mobile}>
<Popover.Target> <Popover.Target>
<Indicator label={props.entry.tags.length} showZero={false} dot={false} inline size={16}> <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> </Indicator>
</Popover.Target> </Popover.Target>
<Popover.Dropdown> <Popover.Dropdown>
@@ -94,13 +94,13 @@ export function FeedEntryFooter(props: FeedEntryFooterProps) {
)} )}
<a href={props.entry.url} target="_blank" rel="noreferrer"> <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> </a>
</ButtonToolbar> </ButtonToolbar>
<ActionButton <ActionButton
icon={<TbArrowBarToDown size={18} />} 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))} onClick={() => dispatch(markEntriesUpToEntry(props.entry))}
/> />
</Group> </Group>

View File

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

View File

@@ -36,9 +36,14 @@ export function ImportOpml() {
<form onSubmit={form.onSubmit(v => importOpml.execute(v.file))}> <form onSubmit={form.onSubmit(v => importOpml.execute(v.file))}>
<Stack> <Stack>
<FileInput <FileInput
label={t`OPML file`} label={<Trans>OPML file</Trans>}
placeholder={t`OPML file`} 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")} {...form.getInputProps("file")}
required required
accept="application/xml" 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 { Box, Button, Group, Stack, Stepper, TextInput } from "@mantine/core"
import { useForm } from "@mantine/form" import { useForm } from "@mantine/form"
import { client, errorToStrings } from "app/client" import { client, errorToStrings } from "app/client"
@@ -74,24 +74,33 @@ export function Subscribe() {
<form onSubmit={nextStep}> <form onSubmit={nextStep}>
<Stepper active={activeStep} onStepClick={setActiveStep}> <Stepper active={activeStep} onStepClick={setActiveStep}>
<Stepper.Step <Stepper.Step
label={t`Analyze feed`} label={<Trans>Analyze feed</Trans>}
description={t`Check that the feed is working`} description={<Trans>Check that the feed is working</Trans>}
allowStepSelect={activeStep === 1} allowStepSelect={activeStep === 1}
> >
<TextInput <TextInput
label={t`Feed URL`} label={<Trans>Feed URL</Trans>}
placeholder="http://www.mysite.com/rss" 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 required
autoFocus autoFocus
{...step0Form.getInputProps("url")} {...step0Form.getInputProps("url")}
/> />
</Stepper.Step> </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> <Stack>
<TextInput label={t`Feed URL`} {...step1Form.getInputProps("url")} disabled /> <TextInput label={<Trans>Feed URL</Trans>} {...step1Form.getInputProps("url")} disabled />
<TextInput label={t`Feed name`} {...step1Form.getInputProps("title")} required autoFocus /> <TextInput label={<Trans>Feed name</Trans>} {...step1Form.getInputProps("title")} required autoFocus />
<CategorySelect label={t`Category`} {...step1Form.getInputProps("categoryId")} clearable /> <CategorySelect label={<Trans>Category</Trans>} {...step1Form.getInputProps("categoryId")} clearable />
</Stack> </Stack>
</Stepper.Step> </Stepper.Step>
</Stepper> </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 { ActionIcon, Center, Divider, Indicator, Popover, TextInput } from "@mantine/core"
import { useForm } from "@mantine/form" import { useForm } from "@mantine/form"
import { reloadEntries, search } from "app/slices/entries" import { reloadEntries, search } from "app/slices/entries"
@@ -17,6 +17,7 @@ function HeaderDivider() {
} }
const iconSize = 18 const iconSize = 18
export function Header() { export function Header() {
const settings = useAppSelector(state => state.user.settings) const settings = useAppSelector(state => state.user.settings)
const profile = useAppSelector(state => state.user.profile) const profile = useAppSelector(state => state.user.profile)
@@ -40,26 +41,30 @@ export function Header() {
return ( return (
<Center> <Center>
<ButtonToolbar> <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} /> <MarkAllAsReadButton iconSize={iconSize} />
<HeaderDivider /> <HeaderDivider />
<ActionButton <ActionButton
icon={settings.readingMode === "all" ? <TbEye size={iconSize} /> : <TbEyeOff size={iconSize} />} 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"))} onClick={() => dispatch(changeReadingMode(settings.readingMode === "all" ? "unread" : "all"))}
/> />
<ActionButton <ActionButton
icon={settings.readingOrder === "asc" ? <TbArrowUp size={iconSize} /> : <TbArrowDown size={iconSize} />} 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"))} onClick={() => dispatch(changeReadingOrder(settings.readingOrder === "asc" ? "desc" : "asc"))}
/> />
<Popover> <Popover>
<Popover.Target> <Popover.Target>
<Indicator disabled={!searchFromStore}> <Indicator disabled={!searchFromStore}>
<ActionButton icon={<TbSearch size={iconSize} />} label={t`Search`} /> <ActionButton icon={<TbSearch size={iconSize} />} label={<Trans>Search</Trans>} />
</Indicator> </Indicator>
</Popover.Target> </Popover.Target>
<Popover.Dropdown> <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 { Button, Code, Group, Modal, Slider, Stack, Text } from "@mantine/core"
import { markAllEntries } from "app/slices/entries" import { markAllEntries } from "app/slices/entries"
@@ -17,7 +17,7 @@ export function MarkAllAsReadButton(props: { iconSize: number }) {
return ( 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> <Stack>
<Text size="sm"> <Text size="sm">
{threshold === 0 && ( {threshold === 0 && (
@@ -72,7 +72,7 @@ export function MarkAllAsReadButton(props: { iconSize: number }) {
</Modal> </Modal>
<ActionButton <ActionButton
icon={<TbChecks size={props.iconSize} />} icon={<TbChecks size={props.iconSize} />}
label={t`Mark all as read`} label={<Trans>Mark all as read</Trans>}
onClick={() => { onClick={() => {
setThreshold(0) setThreshold(0)
setOpened(true) 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 { Box, Divider, Group, Menu, SegmentedControl, SegmentedControlItem, useMantineColorScheme } from "@mantine/core"
import { showNotification } from "@mantine/notifications" import { showNotification } from "@mantine/notifications"
import { client } from "app/client" import { client } from "app/client"
@@ -111,7 +111,7 @@ export function ProfileMenu(props: ProfileMenuProps) {
onClick={() => onClick={() =>
client.feed.refreshAll().then(() => { client.feed.refreshAll().then(() => {
showNotification({ showNotification({
message: t`Your feeds have been queued for refresh.`, message: <Trans>Your feeds have been queued for refresh.</Trans>,
color: "green", color: "green",
autoClose: 1000, 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 { Divider, Select, SimpleGrid, Stack, Switch } from "@mantine/core"
import { Constants } from "app/constants" import { Constants } from "app/constants"
import { changeLanguage, changeScrollMarks, changeScrollSpeed, changeSharingSetting, changeShowRead } from "app/slices/user" import { changeLanguage, changeScrollMarks, changeScrollSpeed, changeSharingSetting, changeShowRead } from "app/slices/user"
@@ -17,7 +17,7 @@ export function DisplaySettings() {
return ( return (
<Stack> <Stack>
<Select <Select
description={t`Language`} description={<Trans>Language</Trans>}
value={language} value={language}
data={locales.map(l => ({ data={locales.map(l => ({
value: l.key, value: l.key,
@@ -27,24 +27,24 @@ export function DisplaySettings() {
/> />
<Switch <Switch
label={t`Scroll smoothly when navigating between entries`} label={<Trans>Scroll smoothly when navigating between entries</Trans>}
checked={scrollSpeed ? scrollSpeed > 0 : false} checked={scrollSpeed ? scrollSpeed > 0 : false}
onChange={e => dispatch(changeScrollSpeed(e.currentTarget.checked))} onChange={e => dispatch(changeScrollSpeed(e.currentTarget.checked))}
/> />
<Switch <Switch
label={t`Show feeds and categories with no unread entries`} label={<Trans>Show feeds and categories with no unread entries</Trans>}
checked={showRead} checked={showRead}
onChange={e => dispatch(changeShowRead(e.currentTarget.checked))} onChange={e => dispatch(changeShowRead(e.currentTarget.checked))}
/> />
<Switch <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} checked={scrollMarks}
onChange={e => dispatch(changeScrollMarks(e.currentTarget.checked))} 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}> <SimpleGrid cols={2}>
{(Object.keys(Constants.sharing) as Array<keyof SharingSettings>).map(site => ( {(Object.keys(Constants.sharing) as Array<keyof SharingSettings>).map(site => (

View File

@@ -41,13 +41,13 @@ export function ProfileSettings() {
const openDeleteProfileModal = () => const openDeleteProfileModal = () =>
openConfirmModal({ openConfirmModal({
title: t`Delete account`, title: <Trans>Delete account</Trans>,
children: ( children: (
<Text size="sm"> <Text size="sm">
<Trans>Are you sure you want to delete your account? There's no turning back!</Trans> <Trans>Are you sure you want to delete your account? There's no turning back!</Trans>
</Text> </Text>
), ),
labels: { confirm: t`Confirm`, cancel: t`Cancel` }, labels: { confirm: <Trans>Confirm</Trans>, cancel: <Trans>Cancel</Trans> },
confirmProps: { color: "red" }, confirmProps: { color: "red" },
onConfirm: () => deleteProfile.execute(), onConfirm: () => deleteProfile.execute(),
}) })
@@ -77,12 +77,16 @@ export function ProfileSettings() {
<form onSubmit={form.onSubmit(saveProfile.execute)}> <form onSubmit={form.onSubmit(saveProfile.execute)}>
<Stack> <Stack>
<Input.Wrapper label={t`User name`}> <Input.Wrapper label={<Trans>User name</Trans>}>
<Box>{profile?.name}</Box> <Box>{profile?.name}</Box>
</Input.Wrapper> </Input.Wrapper>
<Input.Wrapper <Input.Wrapper
label={t`OPML export`} label={<Trans>OPML export</Trans>}
description={t`Export your subscriptions and categories as an OPML file that can be imported in other feed reading services`} description={
<Trans>
Export your subscriptions and categories as an OPML file that can be imported in other feed reading services
</Trans>
}
> >
<Box> <Box>
<Anchor href="rest/feed/export" download="commafeed_opml.xml"> <Anchor href="rest/feed/export" download="commafeed_opml.xml">
@@ -91,20 +95,20 @@ export function ProfileSettings() {
</Box> </Box>
</Input.Wrapper> </Input.Wrapper>
<PasswordInput <PasswordInput
label={t`Current password`} label={<Trans>Current password</Trans>}
description={t`Enter your current password to change profile settings`} description={<Trans>Enter your current password to change profile settings</Trans>}
required required
{...form.getInputProps("currentPassword")} {...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 <PasswordInput
label={t`New password`} label={<Trans>New password</Trans>}
description={t`Changing password will generate a new API key`} description={<Trans>Changing password will generate a new API key</Trans>}
{...form.getInputProps("newPassword")} {...form.getInputProps("newPassword")}
/> />
<PasswordInput label={t`Confirm password`} {...form.getInputProps("newPasswordConfirmation")} /> <PasswordInput label={<Trans>Confirm password</Trans>} {...form.getInputProps("newPasswordConfirmation")} />
<TextInput label={t`API key`} readOnly value={profile?.apiKey} /> <TextInput label={<Trans>API key</Trans>} readOnly value={profile?.apiKey} />
<Checkbox label={t`Generate new API key`} {...form.getInputProps("newApiKey", { type: "checkbox" })} /> <Checkbox label={<Trans>Generate new API key</Trans>} {...form.getInputProps("newApiKey", { type: "checkbox" })} />
<Group> <Group>
<Button variant="default" onClick={() => dispatch(redirectToSelectedSource())}> <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 { Box, Stack } from "@mantine/core"
import { Constants } from "app/constants" import { Constants } from "app/constants"
import { import {
@@ -27,6 +27,7 @@ const expandedIcon = <TbChevronDown size={16} />
const collapsedIcon = <TbChevronRight size={16} /> const collapsedIcon = <TbChevronRight size={16} />
const errorThreshold = 9 const errorThreshold = 9
export function Tree() { export function Tree() {
const root = useAppSelector(state => state.tree.rootCategory) const root = useAppSelector(state => state.tree.rootCategory)
const source = useAppSelector(state => state.entries.source) const source = useAppSelector(state => state.entries.source)
@@ -63,7 +64,7 @@ export function Tree() {
const allCategoryNode = () => ( const allCategoryNode = () => (
<TreeNode <TreeNode
id={Constants.categories.all.id} id={Constants.categories.all.id}
name={t`All`} name={<Trans>All</Trans>}
icon={allIcon} icon={allIcon}
unread={categoryUnreadCount(root)} unread={categoryUnreadCount(root)}
selected={source.type === "category" && source.id === Constants.categories.all.id} selected={source.type === "category" && source.id === Constants.categories.all.id}
@@ -76,7 +77,7 @@ export function Tree() {
const starredCategoryNode = () => ( const starredCategoryNode = () => (
<TreeNode <TreeNode
id={Constants.categories.starred.id} id={Constants.categories.starred.id}
name={t`Starred`} name={<Trans>Starred</Trans>}
icon={starredIcon} icon={starredIcon}
unread={0} unread={0}
selected={source.type === "category" && source.id === Constants.categories.starred.id} selected={source.type === "category" && source.id === Constants.categories.starred.id}

View File

@@ -5,8 +5,8 @@ import { UnreadCount } from "./UnreadCount"
interface TreeNodeProps { interface TreeNodeProps {
id: string id: string
name: string name: ReactNode
icon: ReactNode | string icon: ReactNode
unread: number unread: number
selected: boolean selected: boolean
expanded?: 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 { Box, Center, Kbd, TextInput } from "@mantine/core"
import { openSpotlight, SpotlightAction, SpotlightProvider } from "@mantine/spotlight" import { openSpotlight, SpotlightAction, SpotlightProvider } from "@mantine/spotlight"
import { redirectToFeed } from "app/slices/redirect" import { redirectToFeed } from "app/slices/redirect"
@@ -11,6 +11,7 @@ import { TbSearch } from "react-icons/tb"
export interface TreeSearchProps { export interface TreeSearchProps {
feeds: Subscription[] feeds: Subscription[]
} }
export function TreeSearch(props: TreeSearchProps) { export function TreeSearch(props: TreeSearchProps) {
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
@@ -40,7 +41,7 @@ export function TreeSearch(props: TreeSearchProps) {
searchIcon={searchIcon} searchIcon={searchIcon}
searchPlaceholder={t`Search`} searchPlaceholder={t`Search`}
shortcut="ctrl+k" shortcut="ctrl+k"
nothingFoundMessage={t`Nothing found`} nothingFoundMessage={<Trans>Nothing found</Trans>}
> >
<TextInput <TextInput
placeholder={t`Search`} placeholder={t`Search`}

View File

@@ -1,4 +1,4 @@
import { t } from "@lingui/macro" import { Trans } from "@lingui/macro"
import { Anchor, Box, Center, Container, Divider, Group, Image, Title, useMantineColorScheme } from "@mantine/core" import { Anchor, Box, Center, Container, Divider, Group, Image, Title, useMantineColorScheme } from "@mantine/core"
import { useMediaQuery } from "@mantine/hooks" import { useMediaQuery } from "@mantine/hooks"
import { client } from "app/client" import { client } from "app/client"
@@ -76,7 +76,7 @@ function Buttons() {
<ButtonToolbar> <ButtonToolbar>
{serverInfos?.demoAccountEnabled && ( {serverInfos?.demoAccountEnabled && (
<ActionButton <ActionButton
label={t`Try the demo!`} label={<Trans>Try the demo!</Trans>}
icon={<TbClock size={iconSize} />} icon={<TbClock size={iconSize} />}
variant="outline" variant="outline"
onClick={() => login.execute({ name: "demo", password: "demo" })} onClick={() => login.execute({ name: "demo", password: "demo" })}
@@ -84,7 +84,7 @@ function Buttons() {
/> />
)} )}
<ActionButton <ActionButton
label={t`Log in`} label={<Trans>Log in</Trans>}
icon={<TbKey size={iconSize} />} icon={<TbKey size={iconSize} />}
variant="outline" variant="outline"
onClick={() => dispatch(redirectToLogin())} onClick={() => dispatch(redirectToLogin())}
@@ -92,7 +92,7 @@ function Buttons() {
/> />
{serverInfos?.allowRegistrations && ( {serverInfos?.allowRegistrations && (
<ActionButton <ActionButton
label={t`Sign up`} label={<Trans>Sign up</Trans>}
icon={<TbUserPlus size={iconSize} />} icon={<TbUserPlus size={iconSize} />}
variant="filled" variant="filled"
onClick={() => dispatch(redirectToRegistration())} onClick={() => dispatch(redirectToRegistration())}

View File

@@ -1,4 +1,4 @@
import { t, Trans } from "@lingui/macro" import { Trans } from "@lingui/macro"
import { ActionIcon, Box, Code, Container, Group, Table, Text, Title, useMantineTheme } from "@mantine/core" import { ActionIcon, Box, Code, Container, Group, Table, Text, Title, useMantineTheme } from "@mantine/core"
import { closeAllModals, openConfirmModal, openModal } from "@mantine/modals" import { closeAllModals, openConfirmModal, openModal } from "@mantine/modals"
import { client, errorToStrings } from "app/client" import { client, errorToStrings } from "app/client"
@@ -7,6 +7,7 @@ import { UserEdit } from "components/admin/UserEdit"
import { Alert } from "components/Alert" import { Alert } from "components/Alert"
import { Loader } from "components/Loader" import { Loader } from "components/Loader"
import { RelativeDate } from "components/RelativeDate" import { RelativeDate } from "components/RelativeDate"
import { ReactNode } from "react"
import { useAsync, useAsyncCallback } from "react-async-hook" import { useAsync, useAsyncCallback } from "react-async-hook"
import { TbCheck, TbPencil, TbPlus, TbTrash, TbX } from "react-icons/tb" import { TbCheck, TbPencil, TbPlus, TbTrash, TbX } from "react-icons/tb"
@@ -26,7 +27,7 @@ export function AdminUsersPage() {
}, },
}) })
const openUserEditModal = (title: string, user?: UserModel) => { const openUserEditModal = (title: ReactNode, user?: UserModel) => {
openModal({ openModal({
title, title,
children: ( children: (
@@ -45,7 +46,7 @@ export function AdminUsersPage() {
const openUserDeleteModal = (user: UserModel) => { const openUserDeleteModal = (user: UserModel) => {
const userName = user.name const userName = user.name
openConfirmModal({ openConfirmModal({
title: t`Delete user`, title: <Trans>Delete user</Trans>,
children: ( children: (
<Text size="sm"> <Text size="sm">
<Trans> <Trans>
@@ -53,7 +54,7 @@ export function AdminUsersPage() {
</Trans> </Trans>
</Text> </Text>
), ),
labels: { confirm: t`Confirm`, cancel: t`Cancel` }, labels: { confirm: <Trans>Confirm</Trans>, cancel: <Trans>Cancel</Trans> },
confirmProps: { color: "red" }, confirmProps: { color: "red" },
onConfirm: () => deleteUser.execute({ id: user.id }), onConfirm: () => deleteUser.execute({ id: user.id }),
}) })
@@ -65,7 +66,7 @@ export function AdminUsersPage() {
<Title order={3} mb="md"> <Title order={3} mb="md">
<Group> <Group>
<Trans>Manage users</Trans> <Trans>Manage users</Trans>
<ActionIcon color={theme.primaryColor} onClick={() => openUserEditModal(t`Add user`)}> <ActionIcon color={theme.primaryColor} onClick={() => openUserEditModal(<Trans>Add user</Trans>)}>
<TbPlus size={20} /> <TbPlus size={20} />
</ActionIcon> </ActionIcon>
</Group> </Group>
@@ -126,7 +127,7 @@ export function AdminUsersPage() {
</td> </td>
<td> <td>
<Group> <Group>
<ActionIcon color={theme.primaryColor} onClick={() => openUserEditModal(t`Edit user`, u)}> <ActionIcon color={theme.primaryColor} onClick={() => openUserEditModal(<Trans>Edit user</Trans>, u)}>
<TbPencil size={18} /> <TbPencil size={18} />
</ActionIcon> </ActionIcon>
<ActionIcon <ActionIcon

View File

@@ -15,7 +15,7 @@ const useStyles = createStyles(() => ({
}, },
})) }))
function Section(props: { title: string; icon: React.ReactNode; children: React.ReactNode }) { function Section(props: { title: React.ReactNode; icon: React.ReactNode; children: React.ReactNode }) {
const { classes } = useStyles() const { classes } = useStyles()
return ( return (
<Box my="xl"> <Box my="xl">
@@ -38,7 +38,7 @@ function NextUnreadBookmarklet() {
return ( return (
<Box> <Box>
<CategorySelect value={categoryId} onChange={c => c && setCategoryId(c)} withAll description={t`Category`} /> <CategorySelect value={categoryId} onChange={c => c && setCategoryId(c)} withAll description={<Trans>Category</Trans>} />
<NativeSelect <NativeSelect
data={[ data={[
{ value: "desc", label: t`Newest first` }, { value: "desc", label: t`Newest first` },
@@ -46,7 +46,7 @@ function NextUnreadBookmarklet() {
]} ]}
value={order} value={order}
onChange={e => setOrder(e.target.value)} onChange={e => setOrder(e.target.value)}
description={t`Order`} description={<Trans>Order</Trans>}
/> />
<Trans>Drag link to bookmark bar</Trans> <Trans>Drag link to bookmark bar</Trans>
<span> </span> <span> </span>
@@ -58,6 +58,7 @@ function NextUnreadBookmarklet() {
} }
const bitcoinAddress = <Code>{Constants.bitcoinWalletAddress}</Code> const bitcoinAddress = <Code>{Constants.bitcoinWalletAddress}</Code>
export function AboutPage() { export function AboutPage() {
const version = useAppSelector(state => state.server.serverInfos?.version) const version = useAppSelector(state => state.server.serverInfos?.version)
const revision = useAppSelector(state => state.server.serverInfos?.gitCommit) const revision = useAppSelector(state => state.server.serverInfos?.gitCommit)
@@ -65,7 +66,7 @@ export function AboutPage() {
return ( return (
<Container size="xl"> <Container size="xl">
<SimpleGrid cols={2} breakpoints={[{ maxWidth: Constants.layout.mobileBreakpoint, cols: 1 }]}> <SimpleGrid cols={2} breakpoints={[{ maxWidth: Constants.layout.mobileBreakpoint, cols: 1 }]}>
<Section title={t`About`} icon={<TbHelp size={24} />}> <Section title={<Trans>About</Trans>} icon={<TbHelp size={24} />}>
<Box> <Box>
<Trans> <Trans>
CommaFeed version {version} ({revision}) CommaFeed version {version} ({revision})
@@ -119,7 +120,7 @@ export function AboutPage() {
<Trans>For those of you who prefer bitcoin, here is the address: {bitcoinAddress}</Trans> <Trans>For those of you who prefer bitcoin, here is the address: {bitcoinAddress}</Trans>
</Box> </Box>
</Section> </Section>
<Section title={t`Goodies`} icon={<TbPuzzle size={24} />}> <Section title={<Trans>Goodies</Trans>} icon={<TbPuzzle size={24} />}>
<List> <List>
<List.Item> <List.Item>
<Trans>Browser extentions</Trans> <Trans>Browser extentions</Trans>
@@ -161,10 +162,10 @@ export function AboutPage() {
</List.Item> </List.Item>
</List> </List>
</Section> </Section>
<Section title={t`Keyboard shortcuts`} icon={<TbKeyboard size={24} />}> <Section title={<Trans>Keyboard shortcuts</Trans>} icon={<TbKeyboard size={24} />}>
<KeyboardShortcutsHelp /> <KeyboardShortcutsHelp />
</Section> </Section>
<Section title={t`REST API`} icon={<TbRocket size={24} />}> <Section title={<Trans>REST API</Trans>} icon={<TbRocket size={24} />}>
<Anchor onClick={() => dispatch(redirectToApiDocumentation())}> <Anchor onClick={() => dispatch(redirectToApiDocumentation())}>
<Trans>Go to the API documentation.</Trans> <Trans>Go to the API documentation.</Trans>
</Anchor> </Anchor>

View File

@@ -1,4 +1,4 @@
import { t, Trans } from "@lingui/macro" import { Trans } from "@lingui/macro"
import { Anchor, Box, Button, Code, Container, Divider, Group, Input, NumberInput, Stack, Text, TextInput, Title } from "@mantine/core" import { Anchor, Box, Button, Code, Container, Divider, Group, Input, NumberInput, Stack, Text, TextInput, Title } from "@mantine/core"
import { useForm } from "@mantine/form" import { useForm } from "@mantine/form"
import { openConfirmModal } from "@mantine/modals" import { openConfirmModal } from "@mantine/modals"
@@ -48,7 +48,7 @@ export function CategoryDetailsPage() {
const openDeleteCategoryModal = () => { const openDeleteCategoryModal = () => {
const categoryName = category?.name const categoryName = category?.name
return openConfirmModal({ return openConfirmModal({
title: t`Delete Category`, title: <Trans>Delete Category</Trans>,
children: ( children: (
<Text size="sm"> <Text size="sm">
<Trans> <Trans>
@@ -56,7 +56,7 @@ export function CategoryDetailsPage() {
</Trans> </Trans>
</Text> </Text>
), ),
labels: { confirm: t`Confirm`, cancel: t`Cancel` }, labels: { confirm: <Trans>Confirm</Trans>, cancel: <Trans>Cancel</Trans> },
confirmProps: { color: "red" }, confirmProps: { color: "red" },
onConfirm: () => deleteCategory.execute({ id: +id }), onConfirm: () => deleteCategory.execute({ id: +id }),
}) })
@@ -91,7 +91,7 @@ export function CategoryDetailsPage() {
<form onSubmit={form.onSubmit(modifyCategory.execute)}> <form onSubmit={form.onSubmit(modifyCategory.execute)}>
<Stack> <Stack>
<Title order={3}>{category.name}</Title> <Title order={3}>{category.name}</Title>
<Input.Wrapper label={t`Generated feed url`}> <Input.Wrapper label={<Trans>Generated feed url</Trans>}>
<Box> <Box>
{apiKey && ( {apiKey && (
<Anchor <Anchor
@@ -108,14 +108,14 @@ export function CategoryDetailsPage() {
{editable && ( {editable && (
<> <>
<TextInput label={t`Name`} {...form.getInputProps("name")} required /> <TextInput label={<Trans>Name</Trans>} {...form.getInputProps("name")} required />
<CategorySelect <CategorySelect
label={t`Parent Category`} label={<Trans>Parent Category</Trans>}
{...form.getInputProps("parentId")} {...form.getInputProps("parentId")}
clearable clearable
withoutCategoryIds={[id]} withoutCategoryIds={[id]}
/> />
<NumberInput label={t`Position`} {...form.getInputProps("position")} required min={0} /> <NumberInput label={<Trans>Position</Trans>} {...form.getInputProps("position")} required min={0} />
</> </>
)} )}

View File

@@ -1,4 +1,4 @@
import { t, Trans } from "@lingui/macro" import { Trans } from "@lingui/macro"
import { Anchor, Box, Button, Code, Container, Divider, Group, Input, NumberInput, Stack, Text, TextInput, Title } from "@mantine/core" import { Anchor, Box, Button, Code, Container, Divider, Group, Input, NumberInput, Stack, Text, TextInput, Title } from "@mantine/core"
import { useForm } from "@mantine/form" import { useForm } from "@mantine/form"
import { openConfirmModal } from "@mantine/modals" import { openConfirmModal } from "@mantine/modals"
@@ -47,6 +47,7 @@ function FilteringExpressionDescription() {
</div> </div>
) )
} }
export function FeedDetailsPage() { export function FeedDetailsPage() {
const { id } = useParams() const { id } = useParams()
if (!id) throw Error("id required") if (!id) throw Error("id required")
@@ -75,7 +76,7 @@ export function FeedDetailsPage() {
const openUnsubscribeModal = () => { const openUnsubscribeModal = () => {
const feedName = feed?.name const feedName = feed?.name
return openConfirmModal({ return openConfirmModal({
title: t`Unsubscribe`, title: <Trans>Unsubscribe</Trans>,
children: ( children: (
<Text size="sm"> <Text size="sm">
<Trans> <Trans>
@@ -83,7 +84,7 @@ export function FeedDetailsPage() {
</Trans> </Trans>
</Text> </Text>
), ),
labels: { confirm: t`Confirm`, cancel: t`Cancel` }, labels: { confirm: <Trans>Confirm</Trans>, cancel: <Trans>Cancel</Trans> },
confirmProps: { color: "red" }, confirmProps: { color: "red" },
onConfirm: () => unsubscribe.execute({ id: +id }), onConfirm: () => unsubscribe.execute({ id: +id }),
}) })
@@ -112,34 +113,34 @@ export function FeedDetailsPage() {
<form onSubmit={form.onSubmit(modifyFeed.execute)}> <form onSubmit={form.onSubmit(modifyFeed.execute)}>
<Stack> <Stack>
<Title order={3}>{feed.name}</Title> <Title order={3}>{feed.name}</Title>
<Input.Wrapper label={t`Feed URL`}> <Input.Wrapper label={<Trans>Feed URL</Trans>}>
<Box> <Box>
<Anchor href={feed.feedUrl} target="_blank" rel="noreferrer"> <Anchor href={feed.feedUrl} target="_blank" rel="noreferrer">
{feed.feedUrl} {feed.feedUrl}
</Anchor> </Anchor>
</Box> </Box>
</Input.Wrapper> </Input.Wrapper>
<Input.Wrapper label={t`Website`}> <Input.Wrapper label={<Trans>Website</Trans>}>
<Box> <Box>
<Anchor href={feed.feedLink} target="_blank" rel="noreferrer"> <Anchor href={feed.feedLink} target="_blank" rel="noreferrer">
{feed.feedLink} {feed.feedLink}
</Anchor> </Anchor>
</Box> </Box>
</Input.Wrapper> </Input.Wrapper>
<Input.Wrapper label={t`Last refresh`}> <Input.Wrapper label={<Trans>Last refresh</Trans>}>
<Box> <Box>
<RelativeDate date={feed.lastRefresh} /> <RelativeDate date={feed.lastRefresh} />
</Box> </Box>
</Input.Wrapper> </Input.Wrapper>
<Input.Wrapper label={t`Last refresh message`}> <Input.Wrapper label={<Trans>Last refresh message</Trans>}>
<Box>{feed.message ?? t`N/A`}</Box> <Box>{feed.message ?? <Trans>N/A</Trans>}</Box>
</Input.Wrapper> </Input.Wrapper>
<Input.Wrapper label={t`Next refresh`}> <Input.Wrapper label={<Trans>Next refresh</Trans>}>
<Box> <Box>
<RelativeDate date={feed.nextRefresh} /> <RelativeDate date={feed.nextRefresh} />
</Box> </Box>
</Input.Wrapper> </Input.Wrapper>
<Input.Wrapper label={t`Generated feed url`}> <Input.Wrapper label={<Trans>Generated feed url</Trans>}>
<Box> <Box>
{apiKey && ( {apiKey && (
<Anchor href={`rest/feed/entriesAsFeed?id=${feed.id}&apiKey=${apiKey}`} target="_blank" rel="noreferrer"> <Anchor href={`rest/feed/entriesAsFeed?id=${feed.id}&apiKey=${apiKey}`} target="_blank" rel="noreferrer">
@@ -150,11 +151,11 @@ export function FeedDetailsPage() {
</Box> </Box>
</Input.Wrapper> </Input.Wrapper>
<TextInput label={t`Name`} {...form.getInputProps("name")} required /> <TextInput label={<Trans>Name</Trans>} {...form.getInputProps("name")} required />
<CategorySelect label={t`Category`} {...form.getInputProps("categoryId")} clearable /> <CategorySelect label={<Trans>Category</Trans>} {...form.getInputProps("categoryId")} clearable />
<NumberInput label={t`Position`} {...form.getInputProps("position")} required min={0} /> <NumberInput label={<Trans>Position</Trans>} {...form.getInputProps("position")} required min={0} />
<TextInput <TextInput
label={t`Filtering expression`} label={<Trans>Filtering expression</Trans>}
description={<FilteringExpressionDescription />} description={<FilteringExpressionDescription />}
{...form.getInputProps("filter")} {...form.getInputProps("filter")}
/> />

View File

@@ -1,4 +1,4 @@
import { t, Trans } from "@lingui/macro" import { Trans } from "@lingui/macro"
import { ActionIcon, Anchor, Box, Center, Divider, Group, Title, useMantineTheme } from "@mantine/core" import { ActionIcon, Anchor, Box, Center, Divider, Group, Title, useMantineTheme } from "@mantine/core"
import { useViewportSize } from "@mantine/hooks" import { useViewportSize } from "@mantine/hooks"
import { Constants } from "app/constants" import { Constants } from "app/constants"
@@ -77,7 +77,7 @@ export function FeedEntriesPage(props: FeedEntriesPageProps) {
<FeedEntries /> <FeedEntries />
{!hasMore && <Divider my="xl" label={t`No more entries`} labelPosition="center" />} {!hasMore && <Divider my="xl" label={<Trans>No more entries</Trans>} labelPosition="center" />}
</Box> </Box>
) )
} }

View File

@@ -1,4 +1,4 @@
import { t, Trans } from "@lingui/macro" import { Trans } from "@lingui/macro"
import { Anchor, Box, Button, Container, Group, Input, Stack, Title } from "@mantine/core" import { Anchor, Box, Button, Container, Group, Input, Stack, Title } from "@mantine/core"
import { Constants } from "app/constants" import { Constants } from "app/constants"
@@ -16,7 +16,7 @@ export function TagDetailsPage() {
<Container> <Container>
<Stack> <Stack>
<Title order={3}>{id}</Title> <Title order={3}>{id}</Title>
<Input.Wrapper label={t`Generated feed url`}> <Input.Wrapper label={<Trans>Generated feed url</Trans>}>
<Box> <Box>
{apiKey && ( {apiKey && (
<Anchor <Anchor

View File

@@ -42,15 +42,17 @@ export function LoginPage() {
<form onSubmit={form.onSubmit(login.execute)}> <form onSubmit={form.onSubmit(login.execute)}>
<Stack> <Stack>
<TextInput <TextInput
label={t`User Name or E-mail`} label={<Trans>User Name or E-mail</Trans>}
placeholder={t`User Name or E-mail`} placeholder={t`User Name or E-mail`}
{...form.getInputProps("name")} {...form.getInputProps("name")}
description={serverInfos?.demoAccountEnabled ? t`Try out CommaFeed with the demo account: demo/demo` : ""} description={
serverInfos?.demoAccountEnabled ? <Trans>Try out CommaFeed with the demo account: demo/demo</Trans> : ""
}
size="md" size="md"
required required
/> />
<PasswordInput <PasswordInput
label={t`Password`} label={<Trans>Password</Trans>}
placeholder={t`Password`} placeholder={t`Password`}
{...form.getInputProps("password")} {...form.getInputProps("password")}
size="md" size="md"

View File

@@ -53,7 +53,7 @@ export function PasswordRecoveryPage() {
<Stack> <Stack>
<TextInput <TextInput
type="email" type="email"
label={t`E-mail`} label={<Trans>E-mail</Trans>}
placeholder={t`E-mail`} placeholder={t`E-mail`}
{...form.getInputProps("email")} {...form.getInputProps("email")}
size="md" size="md"

View File

@@ -53,14 +53,14 @@ export function RegistrationPage() {
<TextInput label="User Name" placeholder="User Name" {...form.getInputProps("name")} size="md" required /> <TextInput label="User Name" placeholder="User Name" {...form.getInputProps("name")} size="md" required />
<TextInput <TextInput
type="email" type="email"
label={t`E-mail address`} label={<Trans>E-mail address</Trans>}
placeholder={t`E-mail address`} placeholder={t`E-mail address`}
{...form.getInputProps("email")} {...form.getInputProps("email")}
size="md" size="md"
required required
/> />
<PasswordInput <PasswordInput
label={t`Password`} label={<Trans>Password</Trans>}
placeholder={t`Password`} placeholder={t`Password`}
{...form.getInputProps("password")} {...form.getInputProps("password")}
size="md" size="md"