mirror of
https://github.com/usememos/memos.git
synced 2025-06-05 22:09:59 +02:00
chore: adding missing translations (#4273)
* Added missing translations strings (filters, about page, ...) * Forgot one translation string. * Fixed PR issues and added Access Token related missing translation strings. * Fixed eslint issues. * Fixed eslint issues #2. * Fixed access token dialog translations, added missing webhook dialog translations.
This commit is contained in:
@@ -74,7 +74,14 @@ const ActivityCalendar = (props: Props) => {
|
|||||||
const date = dayjs(`${year}-${month + 1}-${item.day}`).format("YYYY-MM-DD");
|
const date = dayjs(`${year}-${month + 1}-${item.day}`).format("YYYY-MM-DD");
|
||||||
const count = item.isCurrentMonth ? data[date] || 0 : 0;
|
const count = item.isCurrentMonth ? data[date] || 0 : 0;
|
||||||
const isToday = dayjs().format("YYYY-MM-DD") === date;
|
const isToday = dayjs().format("YYYY-MM-DD") === date;
|
||||||
const tooltipText = count ? t("memo.count-memos-in-date", { count: count, date: date }) : date;
|
const tooltipText =
|
||||||
|
count === 0
|
||||||
|
? t("memo.no-memos")
|
||||||
|
: t("memo.count-memos-in-date", {
|
||||||
|
count: count,
|
||||||
|
memos: count === 1 ? t("common.memo") : t("common.memos"),
|
||||||
|
date: date,
|
||||||
|
}).toLowerCase();
|
||||||
const isSelected = dayjs(props.selectedDate).format("YYYY-MM-DD") === date;
|
const isSelected = dayjs(props.selectedDate).format("YYYY-MM-DD") === date;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@@ -13,21 +13,6 @@ interface Props extends DialogProps {
|
|||||||
onConfirm: () => void;
|
onConfirm: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const expirationOptions = [
|
|
||||||
{
|
|
||||||
label: "8 hours",
|
|
||||||
value: 3600 * 8,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "1 month",
|
|
||||||
value: 3600 * 24 * 30,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Never",
|
|
||||||
value: 0,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
description: string;
|
description: string;
|
||||||
expiration: number;
|
expiration: number;
|
||||||
@@ -43,6 +28,21 @@ const CreateAccessTokenDialog: React.FC<Props> = (props: Props) => {
|
|||||||
});
|
});
|
||||||
const requestState = useLoading(false);
|
const requestState = useLoading(false);
|
||||||
|
|
||||||
|
const expirationOptions = [
|
||||||
|
{
|
||||||
|
label: t("setting.access-token-section.create-dialog.duration-8h"),
|
||||||
|
value: 3600 * 8,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t("setting.access-token-section.create-dialog.duration-1m"),
|
||||||
|
value: 3600 * 24 * 30,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t("setting.access-token-section.create-dialog.duration-never"),
|
||||||
|
value: 0,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const setPartialState = (partialState: Partial<State>) => {
|
const setPartialState = (partialState: Partial<State>) => {
|
||||||
setState({
|
setState({
|
||||||
...state,
|
...state,
|
||||||
@@ -64,7 +64,7 @@ const CreateAccessTokenDialog: React.FC<Props> = (props: Props) => {
|
|||||||
|
|
||||||
const handleSaveBtnClick = async () => {
|
const handleSaveBtnClick = async () => {
|
||||||
if (!state.description) {
|
if (!state.description) {
|
||||||
toast.error("Description is required");
|
toast.error(t("message.description-is-required"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ const CreateAccessTokenDialog: React.FC<Props> = (props: Props) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="dialog-header-container">
|
<div className="dialog-header-container">
|
||||||
<p className="title-text">Create access token</p>
|
<p className="title-text">{t("setting.access-token-section.create-dialog.create-access-token")}</p>
|
||||||
<Button size="sm" variant="plain" onClick={() => destroy()}>
|
<Button size="sm" variant="plain" onClick={() => destroy()}>
|
||||||
<XIcon className="w-5 h-auto" />
|
<XIcon className="w-5 h-auto" />
|
||||||
</Button>
|
</Button>
|
||||||
@@ -94,13 +94,13 @@ const CreateAccessTokenDialog: React.FC<Props> = (props: Props) => {
|
|||||||
<div className="dialog-content-container !w-80">
|
<div className="dialog-content-container !w-80">
|
||||||
<div className="w-full flex flex-col justify-start items-start mb-3">
|
<div className="w-full flex flex-col justify-start items-start mb-3">
|
||||||
<span className="mb-2">
|
<span className="mb-2">
|
||||||
Description <span className="text-red-600">*</span>
|
{t("setting.access-token-section.create-dialog.description")} <span className="text-red-600">*</span>
|
||||||
</span>
|
</span>
|
||||||
<div className="relative w-full">
|
<div className="relative w-full">
|
||||||
<Input
|
<Input
|
||||||
className="w-full"
|
className="w-full"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Some description"
|
placeholder={t("setting.access-token-section.create-dialog.some-description")}
|
||||||
value={state.description}
|
value={state.description}
|
||||||
onChange={handleDescriptionInputChange}
|
onChange={handleDescriptionInputChange}
|
||||||
/>
|
/>
|
||||||
@@ -108,7 +108,7 @@ const CreateAccessTokenDialog: React.FC<Props> = (props: Props) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="w-full flex flex-col justify-start items-start mb-3">
|
<div className="w-full flex flex-col justify-start items-start mb-3">
|
||||||
<span className="mb-2">
|
<span className="mb-2">
|
||||||
Expiration <span className="text-red-600">*</span>
|
{t("setting.access-token-section.create-dialog.expiration")} <span className="text-red-600">*</span>
|
||||||
</span>
|
</span>
|
||||||
<div className="w-full flex flex-row justify-start items-center text-base">
|
<div className="w-full flex flex-row justify-start items-center text-base">
|
||||||
<RadioGroup orientation="horizontal" value={state.expiration} onChange={handleRoleInputChange}>
|
<RadioGroup orientation="horizontal" value={state.expiration} onChange={handleRoleInputChange}>
|
||||||
|
@@ -63,7 +63,7 @@ const CreateWebhookDialog: React.FC<Props> = (props: Props) => {
|
|||||||
|
|
||||||
const handleSaveBtnClick = async () => {
|
const handleSaveBtnClick = async () => {
|
||||||
if (!state.name || !state.url) {
|
if (!state.name || !state.url) {
|
||||||
toast.error("Please fill all required fields");
|
toast.error(t("message.fill-all-required-fields"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +95,9 @@ const CreateWebhookDialog: React.FC<Props> = (props: Props) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="dialog-header-container">
|
<div className="dialog-header-container">
|
||||||
<p className="title-text">{isCreating ? "Create webhook" : "Edit webhook"}</p>
|
<p className="title-text">
|
||||||
|
{isCreating ? t("setting.webhook-section.create-dialog.create-webhook") : t("setting.webhook-section.create-dialog.edit-webhook")}
|
||||||
|
</p>
|
||||||
<Button size="sm" variant="plain" onClick={() => destroy()}>
|
<Button size="sm" variant="plain" onClick={() => destroy()}>
|
||||||
<XIcon className="w-5 h-auto" />
|
<XIcon className="w-5 h-auto" />
|
||||||
</Button>
|
</Button>
|
||||||
@@ -103,13 +105,13 @@ const CreateWebhookDialog: React.FC<Props> = (props: Props) => {
|
|||||||
<div className="dialog-content-container !w-80">
|
<div className="dialog-content-container !w-80">
|
||||||
<div className="w-full flex flex-col justify-start items-start mb-3">
|
<div className="w-full flex flex-col justify-start items-start mb-3">
|
||||||
<span className="mb-2">
|
<span className="mb-2">
|
||||||
Title <span className="text-red-600">*</span>
|
{t("setting.webhook-section.create-dialog.title")} <span className="text-red-600">*</span>
|
||||||
</span>
|
</span>
|
||||||
<div className="relative w-full">
|
<div className="relative w-full">
|
||||||
<Input
|
<Input
|
||||||
className="w-full"
|
className="w-full"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="An easy-to-remember name"
|
placeholder={t("setting.webhook-section.create-dialog.an-easy-to-remember-name")}
|
||||||
value={state.name}
|
value={state.name}
|
||||||
onChange={handleTitleInputChange}
|
onChange={handleTitleInputChange}
|
||||||
/>
|
/>
|
||||||
@@ -117,13 +119,13 @@ const CreateWebhookDialog: React.FC<Props> = (props: Props) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="w-full flex flex-col justify-start items-start mb-3">
|
<div className="w-full flex flex-col justify-start items-start mb-3">
|
||||||
<span className="mb-2">
|
<span className="mb-2">
|
||||||
Payload URL <span className="text-red-600">*</span>
|
{t("setting.webhook-section.create-dialog.payload-url")} <span className="text-red-600">*</span>
|
||||||
</span>
|
</span>
|
||||||
<div className="relative w-full">
|
<div className="relative w-full">
|
||||||
<Input
|
<Input
|
||||||
className="w-full"
|
className="w-full"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="https://example.com/postreceive"
|
placeholder={t("setting.webhook-section.create-dialog.url-example-post-receive")}
|
||||||
value={state.url}
|
value={state.url}
|
||||||
onChange={handleUrlInputChange}
|
onChange={handleUrlInputChange}
|
||||||
/>
|
/>
|
||||||
|
@@ -2,6 +2,7 @@ import { Option, Select } from "@mui/joy";
|
|||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import { Settings2Icon } from "lucide-react";
|
import { Settings2Icon } from "lucide-react";
|
||||||
import { useMemoFilterStore } from "@/store/v1";
|
import { useMemoFilterStore } from "@/store/v1";
|
||||||
|
import { useTranslate } from "@/utils/i18n";
|
||||||
import { Popover, PopoverContent, PopoverTrigger } from "./ui/Popover";
|
import { Popover, PopoverContent, PopoverTrigger } from "./ui/Popover";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -9,6 +10,7 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const MemoDisplaySettingMenu = ({ className }: Props) => {
|
const MemoDisplaySettingMenu = ({ className }: Props) => {
|
||||||
|
const t = useTranslate();
|
||||||
const memoFilterStore = useMemoFilterStore();
|
const memoFilterStore = useMemoFilterStore();
|
||||||
const isApplying = Boolean(memoFilterStore.orderByTimeAsc) !== false;
|
const isApplying = Boolean(memoFilterStore.orderByTimeAsc) !== false;
|
||||||
|
|
||||||
@@ -22,16 +24,16 @@ const MemoDisplaySettingMenu = ({ className }: Props) => {
|
|||||||
<PopoverContent align="end" alignOffset={-12} sideOffset={14}>
|
<PopoverContent align="end" alignOffset={-12} sideOffset={14}>
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
<div className="w-full flex flex-row justify-between items-center">
|
<div className="w-full flex flex-row justify-between items-center">
|
||||||
<span className="text-sm shrink-0 mr-3">Order by</span>
|
<span className="text-sm shrink-0 mr-3">{t("memo.order-by")}</span>
|
||||||
<Select value="displayTime">
|
<Select value="displayTime">
|
||||||
<Option value={"displayTime"}>Display Time</Option>
|
<Option value={"displayTime"}>{t("memo.display-time")}</Option>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full flex flex-row justify-between items-center">
|
<div className="w-full flex flex-row justify-between items-center">
|
||||||
<span className="text-sm shrink-0 mr-3">Direction</span>
|
<span className="text-sm shrink-0 mr-3">{t("memo.direction")}</span>
|
||||||
<Select value={memoFilterStore.orderByTimeAsc} onChange={(_, value) => memoFilterStore.setOrderByTimeAsc(Boolean(value))}>
|
<Select value={memoFilterStore.orderByTimeAsc} onChange={(_, value) => memoFilterStore.setOrderByTimeAsc(Boolean(value))}>
|
||||||
<Option value={false}>DESC</Option>
|
<Option value={false}>{t("memo.direction-desc")}</Option>
|
||||||
<Option value={true}>ASC</Option>
|
<Option value={true}>{t("memo.direction-asc")}</Option>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -92,7 +92,7 @@ const AddMemoRelationPopover = (props: Props) => {
|
|||||||
// If embedded mode is enabled, embed the memo instead of creating a relation.
|
// If embedded mode is enabled, embed the memo instead of creating a relation.
|
||||||
if (embedded) {
|
if (embedded) {
|
||||||
if (!editorRef.current) {
|
if (!editorRef.current) {
|
||||||
toast.error("Failed to embed memo");
|
toast.error(t("message.failed-to-embed-memo"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3,8 +3,10 @@ import { CalendarIcon, CheckCircleIcon, CodeIcon, EyeIcon, FilterIcon, LinkIcon,
|
|||||||
import { useEffect, useRef } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
import { useSearchParams } from "react-router-dom";
|
import { useSearchParams } from "react-router-dom";
|
||||||
import { FilterFactor, getMemoFilterKey, MemoFilter, parseFilterQuery, stringifyFilters, useMemoFilterStore } from "@/store/v1";
|
import { FilterFactor, getMemoFilterKey, MemoFilter, parseFilterQuery, stringifyFilters, useMemoFilterStore } from "@/store/v1";
|
||||||
|
import { useTranslate } from "@/utils/i18n";
|
||||||
|
|
||||||
const MemoFilters = () => {
|
const MemoFilters = () => {
|
||||||
|
const t = useTranslate();
|
||||||
const [searchParams, setSearchParams] = useSearchParams();
|
const [searchParams, setSearchParams] = useSearchParams();
|
||||||
const memoFilterStore = useMemoFilterStore();
|
const memoFilterStore = useMemoFilterStore();
|
||||||
const filters = memoFilterStore.filters;
|
const filters = memoFilterStore.filters;
|
||||||
@@ -75,7 +77,7 @@ const MemoFilters = () => {
|
|||||||
<div className="w-full mb-2 flex flex-row justify-start items-start gap-2">
|
<div className="w-full mb-2 flex flex-row justify-start items-start gap-2">
|
||||||
<span className="flex flex-row items-center gap-0.5 text-gray-500 text-sm leading-6 border border-transparent">
|
<span className="flex flex-row items-center gap-0.5 text-gray-500 text-sm leading-6 border border-transparent">
|
||||||
<FilterIcon className="w-4 h-auto opacity-60 inline" />
|
<FilterIcon className="w-4 h-auto opacity-60 inline" />
|
||||||
Filters
|
{t("memo.filters")}
|
||||||
</span>
|
</span>
|
||||||
<div className="flex flex-row justify-start items-center flex-wrap gap-2 leading-6 h-6">
|
<div className="flex flex-row justify-start items-center flex-wrap gap-2 leading-6 h-6">
|
||||||
{filters.map((filter) => (
|
{filters.map((filter) => (
|
||||||
|
@@ -33,13 +33,12 @@ const AccessTokenSection = () => {
|
|||||||
|
|
||||||
const copyAccessToken = (accessToken: string) => {
|
const copyAccessToken = (accessToken: string) => {
|
||||||
copy(accessToken);
|
copy(accessToken);
|
||||||
toast.success("Access token copied to clipboard");
|
toast.success(t("setting.access-token-section.access-token-copied-to-clipboard"));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteAccessToken = async (accessToken: string) => {
|
const handleDeleteAccessToken = async (accessToken: string) => {
|
||||||
const confirmed = window.confirm(
|
const formatedAccessToken = getFormatedAccessToken(accessToken);
|
||||||
`Are you sure to delete access token \`${getFormatedAccessToken(accessToken)}\`? You cannot undo this action.`,
|
const confirmed = window.confirm(t("setting.access-token-section.access-token-deletion", { accessToken: formatedAccessToken }));
|
||||||
);
|
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
await userServiceClient.deleteUserAccessToken({ name: currentUser.name, accessToken: accessToken });
|
await userServiceClient.deleteUserAccessToken({ name: currentUser.name, accessToken: accessToken });
|
||||||
setUserAccessTokens(userAccessTokens.filter((token) => token.accessToken !== accessToken));
|
setUserAccessTokens(userAccessTokens.filter((token) => token.accessToken !== accessToken));
|
||||||
@@ -85,10 +84,10 @@ const AccessTokenSection = () => {
|
|||||||
{t("common.description")}
|
{t("common.description")}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col" className="px-3 py-2 text-left text-sm font-semibold text-gray-900 dark:text-gray-400">
|
<th scope="col" className="px-3 py-2 text-left text-sm font-semibold text-gray-900 dark:text-gray-400">
|
||||||
{t("setting.access-token-section.created-at")}
|
{t("setting.access-token-section.create-dialog.created-at")}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col" className="px-3 py-2 text-left text-sm font-semibold text-gray-900 dark:text-gray-400">
|
<th scope="col" className="px-3 py-2 text-left text-sm font-semibold text-gray-900 dark:text-gray-400">
|
||||||
{t("setting.access-token-section.expires-at")}
|
{t("setting.access-token-section.create-dialog.expires-at")}
|
||||||
</th>
|
</th>
|
||||||
<th scope="col" className="relative py-3.5 pl-3 pr-4">
|
<th scope="col" className="relative py-3.5 pl-3 pr-4">
|
||||||
<span className="sr-only">{t("common.delete")}</span>
|
<span className="sr-only">{t("common.delete")}</span>
|
||||||
@@ -111,7 +110,7 @@ const AccessTokenSection = () => {
|
|||||||
{userAccessToken.issuedAt?.toLocaleString()}
|
{userAccessToken.issuedAt?.toLocaleString()}
|
||||||
</td>
|
</td>
|
||||||
<td className="whitespace-nowrap px-3 py-2 text-sm text-gray-500 dark:text-gray-400">
|
<td className="whitespace-nowrap px-3 py-2 text-sm text-gray-500 dark:text-gray-400">
|
||||||
{userAccessToken.expiresAt?.toLocaleString() ?? "Never"}
|
{userAccessToken.expiresAt?.toLocaleString() ?? t("setting.access-token-section.create-dialog.duration-never")}
|
||||||
</td>
|
</td>
|
||||||
<td className="relative whitespace-nowrap py-2 pl-3 pr-4 text-right text-sm">
|
<td className="relative whitespace-nowrap py-2 pl-3 pr-4 text-right text-sm">
|
||||||
<Button
|
<Button
|
||||||
|
@@ -31,6 +31,9 @@ const UserStatisticsView = () => {
|
|||||||
const [visibleMonthString, setVisibleMonthString] = useState(dayjs(selectedDate.toDateString()).format("YYYY-MM"));
|
const [visibleMonthString, setVisibleMonthString] = useState(dayjs(selectedDate.toDateString()).format("YYYY-MM"));
|
||||||
const days = Math.ceil((Date.now() - currentUser.createTime!.getTime()) / 86400000);
|
const days = Math.ceil((Date.now() - currentUser.createTime!.getTime()) / 86400000);
|
||||||
|
|
||||||
|
const singularOrPluralMemo = (memoAmount > 0 ? t("common.memos") : t("common.memo")).toLowerCase();
|
||||||
|
const singularOrPluralDay = (days > 0 ? t("common.days") : t("common.day")).toLowerCase();
|
||||||
|
|
||||||
useAsyncEffect(async () => {
|
useAsyncEffect(async () => {
|
||||||
const memoStats: UserMemoStats = { link: 0, taskList: 0, code: 0, incompleteTasks: 0 };
|
const memoStats: UserMemoStats = { link: 0, taskList: 0, code: 0, incompleteTasks: 0 };
|
||||||
metadataList.forEach((memo) => {
|
metadataList.forEach((memo) => {
|
||||||
@@ -90,14 +93,10 @@ const UserStatisticsView = () => {
|
|||||||
onClick={onCalendarClick}
|
onClick={onCalendarClick}
|
||||||
/>
|
/>
|
||||||
{memoAmount === 0 ? (
|
{memoAmount === 0 ? (
|
||||||
<p className="mt-1 w-full text-xs italic opacity-80">No memos</p>
|
<p className="mt-1 w-full text-xs italic opacity-80">{t("memo.no-memos")}</p>
|
||||||
) : memoAmount === 1 ? (
|
|
||||||
<p className="mt-1 w-full text-xs italic opacity-80">
|
|
||||||
<span>{memoAmount}</span> memo in <span>{days}</span> {days > 1 ? "days" : "day"}
|
|
||||||
</p>
|
|
||||||
) : (
|
) : (
|
||||||
<p className="mt-1 w-full text-xs italic opacity-80">
|
<p className="mt-1 w-full text-xs italic opacity-80">
|
||||||
<span>{memoAmount}</span> memos in <span>{days}</span> {days > 1 ? "days" : "day"}
|
<span>{memoAmount}</span> {singularOrPluralMemo} {t("common.in").toLowerCase()} <span>{days}</span> {singularOrPluralDay}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@@ -24,6 +24,7 @@
|
|||||||
"collapse": "Collapse",
|
"collapse": "Collapse",
|
||||||
"create": "Create",
|
"create": "Create",
|
||||||
"database": "Database",
|
"database": "Database",
|
||||||
|
"day": "Day",
|
||||||
"days": "Days",
|
"days": "Days",
|
||||||
"delete": "Delete",
|
"delete": "Delete",
|
||||||
"description": "Description",
|
"description": "Description",
|
||||||
@@ -34,12 +35,14 @@
|
|||||||
"file": "File",
|
"file": "File",
|
||||||
"filter": "Filter",
|
"filter": "Filter",
|
||||||
"home": "Home",
|
"home": "Home",
|
||||||
|
"in": "In",
|
||||||
"image": "Image",
|
"image": "Image",
|
||||||
"inbox": "Inbox",
|
"inbox": "Inbox",
|
||||||
"language": "Language",
|
"language": "Language",
|
||||||
"learn-more": "Learn more",
|
"learn-more": "Learn more",
|
||||||
"link": "Link",
|
"link": "Link",
|
||||||
"mark": "Mark",
|
"mark": "Mark",
|
||||||
|
"memo": "Memo",
|
||||||
"memos": "Memos",
|
"memos": "Memos",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"new": "New",
|
"new": "New",
|
||||||
@@ -103,7 +106,7 @@
|
|||||||
"write-a-comment": "Write a comment"
|
"write-a-comment": "Write a comment"
|
||||||
},
|
},
|
||||||
"copy-link": "Copy Link",
|
"copy-link": "Copy Link",
|
||||||
"count-memos-in-date": "{{count}} memos in {{date}}",
|
"count-memos-in-date": "{{count}} {{memos}} in {{date}}",
|
||||||
"delete-confirm": "Are you sure you want to delete this memo? THIS ACTION IS IRREVERSIBLE",
|
"delete-confirm": "Are you sure you want to delete this memo? THIS ACTION IS IRREVERSIBLE",
|
||||||
"load-more": "Load more",
|
"load-more": "Load more",
|
||||||
"no-archived-memos": "No archived memos.",
|
"no-archived-memos": "No archived memos.",
|
||||||
@@ -121,7 +124,14 @@
|
|||||||
"to-do": "To-do",
|
"to-do": "To-do",
|
||||||
"code": "Code",
|
"code": "Code",
|
||||||
"remove-completed-task-list-items": "Remove done",
|
"remove-completed-task-list-items": "Remove done",
|
||||||
"remove-completed-task-list-items-confirm": "Are you sure you want to remove all completed to-dos? THIS ACTION IS IRREVERSIBLE"
|
"remove-completed-task-list-items-confirm": "Are you sure you want to remove all completed to-dos? THIS ACTION IS IRREVERSIBLE",
|
||||||
|
"filters": "Filters",
|
||||||
|
"order-by": "Order By",
|
||||||
|
"display-time": "Display Time",
|
||||||
|
"direction": "Direction",
|
||||||
|
"direction-desc": "Descending",
|
||||||
|
"direction-asc": "Ascending",
|
||||||
|
"no-memos": "No memos."
|
||||||
},
|
},
|
||||||
"message": {
|
"message": {
|
||||||
"archived-successfully": "Archived successfully",
|
"archived-successfully": "Archived successfully",
|
||||||
@@ -139,7 +149,10 @@
|
|||||||
"succeed-copy-link": "Link copied successfully.",
|
"succeed-copy-link": "Link copied successfully.",
|
||||||
"update-succeed": "Update succeeded",
|
"update-succeed": "Update succeeded",
|
||||||
"user-not-found": "User not found",
|
"user-not-found": "User not found",
|
||||||
"remove-completed-task-list-items-successfully": "The removal was successful"
|
"remove-completed-task-list-items-successfully": "The removal was successful",
|
||||||
|
"failed-to-embed-memo": "Failed to embed memo",
|
||||||
|
"description-is-required": "Description is required",
|
||||||
|
"fill-all-required-fields": "Please fill all required fields"
|
||||||
},
|
},
|
||||||
"reference": {
|
"reference": {
|
||||||
"add-references": "Add references",
|
"add-references": "Add references",
|
||||||
@@ -310,14 +323,33 @@
|
|||||||
"access-token-section": {
|
"access-token-section": {
|
||||||
"title": "Access Tokens",
|
"title": "Access Tokens",
|
||||||
"description": "A list of all access tokens for your account.",
|
"description": "A list of all access tokens for your account.",
|
||||||
|
"token": "Token",
|
||||||
|
"access-token-deletion": "Are you sure to delete access token {{accessToken}}? THIS ACTION IS IRREVERSIBLE.",
|
||||||
|
"access-token-copied-to-clipboard": "Access token copied to clipboard",
|
||||||
|
"create-dialog": {
|
||||||
|
"create-access-token": "Create Access Token",
|
||||||
|
"description": "Description",
|
||||||
|
"some-description": "Some description...",
|
||||||
|
"expiration": "Expiration",
|
||||||
"created-at": "Created At",
|
"created-at": "Created At",
|
||||||
"expires-at": "Expires At",
|
"expires-at": "Expires At",
|
||||||
"token": "Token"
|
"duration-never": "Never",
|
||||||
|
"duration-8h": "8 Hours",
|
||||||
|
"duration-1m": "1 Month"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"webhook-section": {
|
"webhook-section": {
|
||||||
"title": "Webhooks",
|
"title": "Webhooks",
|
||||||
"url": "Url",
|
"url": "URL",
|
||||||
"no-webhooks-found": "No webhooks found."
|
"no-webhooks-found": "No webhooks found.",
|
||||||
|
"create-dialog": {
|
||||||
|
"create-webhook": "Create webhook",
|
||||||
|
"edit-webhook": "Edit webhook",
|
||||||
|
"an-easy-to-remember-name": "An easy-to-remember name",
|
||||||
|
"title": "Title",
|
||||||
|
"payload-url": "Payload URL",
|
||||||
|
"url-example-post-receive": "https://example.com/postreceive"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"workspace-section": {
|
"workspace-section": {
|
||||||
"disallow-user-registration": "Disallow user registration",
|
"disallow-user-registration": "Disallow user registration",
|
||||||
@@ -351,5 +383,12 @@
|
|||||||
"code-block": "Code block",
|
"code-block": "Code block",
|
||||||
"checkbox": "Checkbox",
|
"checkbox": "Checkbox",
|
||||||
"content-syntax": "Content syntax"
|
"content-syntax": "Content syntax"
|
||||||
|
},
|
||||||
|
"about": {
|
||||||
|
"description": "A privacy-first, lightweight note-taking service. Easily capture and share your great thoughts.",
|
||||||
|
"github-repository": "GitHub Repo",
|
||||||
|
"official-website": "Official Website",
|
||||||
|
"blogs": "Blogs",
|
||||||
|
"documents": "Documents"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -24,6 +24,7 @@
|
|||||||
"collapse": "Réduire",
|
"collapse": "Réduire",
|
||||||
"create": "Créer",
|
"create": "Créer",
|
||||||
"database": "Base de données",
|
"database": "Base de données",
|
||||||
|
"day": "Jour",
|
||||||
"days": "Jours",
|
"days": "Jours",
|
||||||
"delete": "Supprimer",
|
"delete": "Supprimer",
|
||||||
"description": "Description",
|
"description": "Description",
|
||||||
@@ -34,12 +35,14 @@
|
|||||||
"file": "Fichier",
|
"file": "Fichier",
|
||||||
"filter": "Filtre",
|
"filter": "Filtre",
|
||||||
"home": "Accueil",
|
"home": "Accueil",
|
||||||
|
"in": "En",
|
||||||
"image": "Image",
|
"image": "Image",
|
||||||
"inbox": "Notifications",
|
"inbox": "Notifications",
|
||||||
"language": "Langue",
|
"language": "Langue",
|
||||||
"learn-more": "En savoir plus",
|
"learn-more": "En savoir plus",
|
||||||
"link": "Lien",
|
"link": "Lien",
|
||||||
"mark": "Lier",
|
"mark": "Lier",
|
||||||
|
"memo": "Memo",
|
||||||
"memos": "Memos",
|
"memos": "Memos",
|
||||||
"name": "Nom",
|
"name": "Nom",
|
||||||
"new": "Nouveau",
|
"new": "Nouveau",
|
||||||
@@ -103,7 +106,7 @@
|
|||||||
"write-a-comment": "Écrire un commentaire"
|
"write-a-comment": "Écrire un commentaire"
|
||||||
},
|
},
|
||||||
"copy-link": "Copier le lien",
|
"copy-link": "Copier le lien",
|
||||||
"count-memos-in-date": "{{count}} memos le {{date}}",
|
"count-memos-in-date": "{{count}} {{memos}} le {{date}}",
|
||||||
"delete-confirm": "Êtes-vous sûr de vouloir supprimer ce memos ? CETTE ACTION EST IRRÉVERSIBLE",
|
"delete-confirm": "Êtes-vous sûr de vouloir supprimer ce memos ? CETTE ACTION EST IRRÉVERSIBLE",
|
||||||
"load-more": "Charger plus",
|
"load-more": "Charger plus",
|
||||||
"no-archived-memos": "Pas de memos archivés.",
|
"no-archived-memos": "Pas de memos archivés.",
|
||||||
@@ -121,7 +124,14 @@
|
|||||||
"to-do": "À faire",
|
"to-do": "À faire",
|
||||||
"code": "Code",
|
"code": "Code",
|
||||||
"remove-completed-task-list-items": "Supprimer terminées",
|
"remove-completed-task-list-items": "Supprimer terminées",
|
||||||
"remove-completed-task-list-items-confirm": "Êtes-vous sûr de vouloir supprimer toutes les tâches terminées ? (Cette action est irréversible)"
|
"remove-completed-task-list-items-confirm": "Êtes-vous sûr de vouloir supprimer toutes les tâches terminées ? CETTE ACTION EST IRRÉVERSIBLE",
|
||||||
|
"filters": "Filtres",
|
||||||
|
"order-by": "Ordonner par",
|
||||||
|
"display-time": "Date d'Affichage",
|
||||||
|
"direction": "Ordre",
|
||||||
|
"direction-desc": "Descendant",
|
||||||
|
"direction-asc": "Ascendant",
|
||||||
|
"no-memos": "Pas de memos."
|
||||||
},
|
},
|
||||||
"message": {
|
"message": {
|
||||||
"archived-successfully": "Archivé avec succès",
|
"archived-successfully": "Archivé avec succès",
|
||||||
@@ -139,7 +149,10 @@
|
|||||||
"succeed-copy-link": "Succeed to copy link to clipboard.",
|
"succeed-copy-link": "Succeed to copy link to clipboard.",
|
||||||
"update-succeed": "Mise à jour effectuée",
|
"update-succeed": "Mise à jour effectuée",
|
||||||
"user-not-found": "Utilisateur introuvable",
|
"user-not-found": "Utilisateur introuvable",
|
||||||
"remove-completed-task-list-items-successfully": "Supprimé avec succès !"
|
"remove-completed-task-list-items-successfully": "Supprimé avec succès !",
|
||||||
|
"failed-to-embed-memo": "Échec de l'intégration du memo.",
|
||||||
|
"message.description-is-required": "Une description est requise",
|
||||||
|
"fill-all-required-fields": "Merci de remplir tous les champs requis"
|
||||||
},
|
},
|
||||||
"reference": {
|
"reference": {
|
||||||
"add-references": "Ajouter des références",
|
"add-references": "Ajouter des références",
|
||||||
@@ -155,7 +168,7 @@
|
|||||||
"file-name": "Nom du fichier",
|
"file-name": "Nom du fichier",
|
||||||
"file-name-placeholder": "Nom du fichier",
|
"file-name-placeholder": "Nom du fichier",
|
||||||
"link": "Lien",
|
"link": "Lien",
|
||||||
"link-placeholder": "https://the.link.to/your/resource",
|
"link-placeholder": "https://le.lien.vers/votre/ressource",
|
||||||
"option": "Lien externe",
|
"option": "Lien externe",
|
||||||
"type": "Type",
|
"type": "Type",
|
||||||
"type-placeholder": "Type de fichier"
|
"type-placeholder": "Type de fichier"
|
||||||
@@ -308,16 +321,35 @@
|
|||||||
},
|
},
|
||||||
"memo-related": "Memo",
|
"memo-related": "Memo",
|
||||||
"access-token-section": {
|
"access-token-section": {
|
||||||
"title": "Jetons d'Accès",
|
"title": "Jetons d'accès",
|
||||||
"description": "Une liste de tous les jetons d'accès pour votre compte.",
|
"description": "Une liste de tous les jetons d'accès pour votre compte.",
|
||||||
|
"token": "Jeton",
|
||||||
|
"access-token-deletion": "Êtes-vous sûr de vouloir supprimer le jeton d'accès {{accessToken}}? CETTE ACTION EST IRRÉVERSIBLE.",
|
||||||
|
"access-token-copied-to-clipboard": "Jeton d'accès copié dans le presse-papier",
|
||||||
|
"create-dialog": {
|
||||||
|
"create-access-token": "Créer un jeton d'accès",
|
||||||
|
"description-label": "Description",
|
||||||
|
"some-description": "Une description…",
|
||||||
|
"expiration-label": "Expiration",
|
||||||
"created-at": "Créé le",
|
"created-at": "Créé le",
|
||||||
"expires-at": "Expire le",
|
"expires-at": "Expire le",
|
||||||
"token": "Jeton"
|
"duration-never": "Jamais",
|
||||||
|
"duration-8h": "8 Heures",
|
||||||
|
"duration-1m": "1 Mois"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"webhook-section": {
|
"webhook-section": {
|
||||||
"title": "Webhooks",
|
"title": "Webhooks",
|
||||||
"url": "Url",
|
"url": "URL",
|
||||||
"no-webhooks-found": "Aucun webhook trouvé."
|
"no-webhooks-found": "Aucun webhook trouvé.",
|
||||||
|
"create-dialog": {
|
||||||
|
"create-webhook": "Créer un webhook",
|
||||||
|
"edit-webhook": "Éditer le webhook",
|
||||||
|
"an-easy-to-remember-name": "Un nom facile à retenir",
|
||||||
|
"title": "Titre",
|
||||||
|
"payload-url": "URL de payload",
|
||||||
|
"url-example-post-receive": "https://exemple.com/postreceive"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"workspace-section": {
|
"workspace-section": {
|
||||||
"disallow-user-registration": "Interdire l'inscription de nouveaux utilisateurs",
|
"disallow-user-registration": "Interdire l'inscription de nouveaux utilisateurs",
|
||||||
@@ -351,5 +383,12 @@
|
|||||||
"code-block": "Bloc de code",
|
"code-block": "Bloc de code",
|
||||||
"checkbox": "Case à cocher",
|
"checkbox": "Case à cocher",
|
||||||
"content-syntax": "Syntaxe du contenu"
|
"content-syntax": "Syntaxe du contenu"
|
||||||
|
},
|
||||||
|
"about": {
|
||||||
|
"description": "Un service de prise de notes léger et respectueux de la vie privée. Capturez et partagez facilement vos meilleures idées.",
|
||||||
|
"github-repository": "Dépôt GitHub",
|
||||||
|
"official-website": "Site web officiel",
|
||||||
|
"blogs": "Blogs",
|
||||||
|
"documents": "Documents"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,8 +1,11 @@
|
|||||||
import { Link } from "@mui/joy";
|
import { Link } from "@mui/joy";
|
||||||
import { DotIcon } from "lucide-react";
|
import { DotIcon } from "lucide-react";
|
||||||
import MobileHeader from "@/components/MobileHeader";
|
import MobileHeader from "@/components/MobileHeader";
|
||||||
|
import { useTranslate } from "@/utils/i18n";
|
||||||
|
|
||||||
const About = () => {
|
const About = () => {
|
||||||
|
const t = useTranslate();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="@container w-full max-w-5xl min-h-full flex flex-col justify-start items-center sm:pt-3 md:pt-6 pb-8">
|
<section className="@container w-full max-w-5xl min-h-full flex flex-col justify-start items-center sm:pt-3 md:pt-6 pb-8">
|
||||||
<MobileHeader />
|
<MobileHeader />
|
||||||
@@ -11,22 +14,22 @@ const About = () => {
|
|||||||
<a href="https://www.usememos.com" target="_blank">
|
<a href="https://www.usememos.com" target="_blank">
|
||||||
<img className="w-auto h-12" src="https://www.usememos.com/full-logo-landscape.png" alt="memos" />
|
<img className="w-auto h-12" src="https://www.usememos.com/full-logo-landscape.png" alt="memos" />
|
||||||
</a>
|
</a>
|
||||||
<p className="text-base">A privacy-first, lightweight note-taking service. Easily capture and share your great thoughts.</p>
|
<p className="text-base">{t("about.description")}</p>
|
||||||
<div className="mt-1 flex flex-row items-center flex-wrap">
|
<div className="mt-1 flex flex-row items-center flex-wrap">
|
||||||
<Link underline="always" href="https://www.github.com/usememos/memos" target="_blank">
|
<Link underline="always" href="https://www.github.com/usememos/memos" target="_blank">
|
||||||
GitHub Repo
|
{t("about.github-repository")}
|
||||||
</Link>
|
</Link>
|
||||||
<DotIcon className="w-4 h-auto opacity-60" />
|
<DotIcon className="w-4 h-auto opacity-60" />
|
||||||
<Link underline="always" href="https://www.usememos.com/" target="_blank">
|
<Link underline="always" href="https://www.usememos.com/" target="_blank">
|
||||||
Official Website
|
{t("about.official-website")}
|
||||||
</Link>
|
</Link>
|
||||||
<DotIcon className="w-4 h-auto opacity-60" />
|
<DotIcon className="w-4 h-auto opacity-60" />
|
||||||
<Link underline="always" href="https://www.usememos.com/blog" target="_blank">
|
<Link underline="always" href="https://www.usememos.com/blog" target="_blank">
|
||||||
Blogs
|
{t("about.blogs")}
|
||||||
</Link>
|
</Link>
|
||||||
<DotIcon className="w-4 h-auto opacity-60" />
|
<DotIcon className="w-4 h-auto opacity-60" />
|
||||||
<Link underline="always" href="https://www.usememos.com/docs" target="_blank">
|
<Link underline="always" href="https://www.usememos.com/docs" target="_blank">
|
||||||
Documents
|
{t("about.documents")}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user