Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding missing translations #4273

Merged
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion web/src/components/ActivityCalendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,14 @@ const ActivityCalendar = (props: Props) => {
const date = dayjs(`${year}-${month + 1}-${item.day}`).format("YYYY-MM-DD");
const count = item.isCurrentMonth ? data[date] || 0 : 0;
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;

return (
Expand Down
40 changes: 20 additions & 20 deletions web/src/components/CreateAccessTokenDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,6 @@ interface Props extends DialogProps {
onConfirm: () => void;
}

const expirationOptions = [
{
label: "8 hours",
value: 3600 * 8,
},
{
label: "1 month",
value: 3600 * 24 * 30,
},
{
label: "Never",
value: 0,
},
];

interface State {
description: string;
expiration: number;
Expand All @@ -43,6 +28,21 @@ const CreateAccessTokenDialog: React.FC<Props> = (props: Props) => {
});
const requestState = useLoading(false);

const expirationOptions = [
{
label: t("setting.access-token-section.duration-8h"),
value: 3600 * 8,
},
{
label: t("setting.access-token-section.duration-1m"),
value: 3600 * 24 * 30,
},
{
label: t("setting.access-token-section.duration-never"),
value: 0,
},
];

const setPartialState = (partialState: Partial<State>) => {
setState({
...state,
Expand All @@ -64,7 +64,7 @@ const CreateAccessTokenDialog: React.FC<Props> = (props: Props) => {

const handleSaveBtnClick = async () => {
if (!state.description) {
toast.error("Description is required");
toast.error(t("message.description-is-required"));
dandelionmood marked this conversation as resolved.
Show resolved Hide resolved
return;
}

Expand All @@ -86,29 +86,29 @@ const CreateAccessTokenDialog: React.FC<Props> = (props: Props) => {
return (
<>
<div className="dialog-header-container">
<p className="title-text">Create access token</p>
<p className="title-text">{t("setting.access-token-section.create-access-token")}</p>
<Button size="sm" variant="plain" onClick={() => destroy()}>
<XIcon className="w-5 h-auto" />
</Button>
</div>
<div className="dialog-content-container !w-80">
<div className="w-full flex flex-col justify-start items-start mb-3">
<span className="mb-2">
Description <span className="text-red-600">*</span>
{t("setting.access-token-section.description-label")} <span className="text-red-600">*</span>
</span>
<div className="relative w-full">
<Input
className="w-full"
type="text"
placeholder="Some description"
placeholder={t("setting.access-token-section.some-description")}
value={state.description}
onChange={handleDescriptionInputChange}
/>
</div>
</div>
<div className="w-full flex flex-col justify-start items-start mb-3">
<span className="mb-2">
Expiration <span className="text-red-600">*</span>
{t("setting.access-token-section.expiration-label")} <span className="text-red-600">*</span>
</span>
<div className="w-full flex flex-row justify-start items-center text-base">
<RadioGroup orientation="horizontal" value={state.expiration} onChange={handleRoleInputChange}>
Expand Down
12 changes: 7 additions & 5 deletions web/src/components/MemoDisplaySettingMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ import { Option, Select } from "@mui/joy";
import clsx from "clsx";
import { Settings2Icon } from "lucide-react";
import { useMemoFilterStore } from "@/store/v1";
import { useTranslate } from "@/utils/i18n";
import { Popover, PopoverContent, PopoverTrigger } from "./ui/Popover";

interface Props {
className?: string;
}

const MemoDisplaySettingMenu = ({ className }: Props) => {
const t = useTranslate();
const memoFilterStore = useMemoFilterStore();
const isApplying = Boolean(memoFilterStore.orderByTimeAsc) !== false;

Expand All @@ -22,16 +24,16 @@ const MemoDisplaySettingMenu = ({ className }: Props) => {
<PopoverContent align="end" alignOffset={-12} sideOffset={14}>
<div className="flex flex-col gap-2">
<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">
<Option value={"displayTime"}>Display Time</Option>
<Option value={"displayTime"}>{t("memo.display-time")}</Option>
</Select>
</div>
<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))}>
<Option value={false}>DESC</Option>
<Option value={true}>ASC</Option>
<Option value={false}>{t("memo.direction-desc")}</Option>
<Option value={true}>{t("memo.direction-asc")}</Option>
</Select>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ const AddMemoRelationPopover = (props: Props) => {
// If embedded mode is enabled, embed the memo instead of creating a relation.
if (embedded) {
if (!editorRef.current) {
toast.error("Failed to embed memo");
toast.error(t("message.failed-to-embed-memo"));
return;
}

Expand Down
4 changes: 3 additions & 1 deletion web/src/components/MemoFilters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import { CalendarIcon, CheckCircleIcon, CodeIcon, EyeIcon, FilterIcon, LinkIcon,
import { useEffect, useRef } from "react";
import { useSearchParams } from "react-router-dom";
import { FilterFactor, getMemoFilterKey, MemoFilter, parseFilterQuery, stringifyFilters, useMemoFilterStore } from "@/store/v1";
import { useTranslate } from "@/utils/i18n";

const MemoFilters = () => {
const t = useTranslate();
const [searchParams, setSearchParams] = useSearchParams();
const memoFilterStore = useMemoFilterStore();
const filters = memoFilterStore.filters;
Expand Down Expand Up @@ -75,7 +77,7 @@ const MemoFilters = () => {
<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">
<FilterIcon className="w-4 h-auto opacity-60 inline" />
Filters
{t("memo.filters")}
</span>
<div className="flex flex-row justify-start items-center flex-wrap gap-2 leading-6 h-6">
{filters.map((filter) => (
Expand Down
9 changes: 4 additions & 5 deletions web/src/components/Settings/AccessTokenSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,12 @@ const AccessTokenSection = () => {

const copyAccessToken = (accessToken: string) => {
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 confirmed = window.confirm(
`Are you sure to delete access token \`${getFormatedAccessToken(accessToken)}\`? You cannot undo this action.`,
);
const formatedAccessToken = getFormatedAccessToken(accessToken);
const confirmed = window.confirm(t("setting.access-token-section.access-token-deletion", { accessToken: formatedAccessToken }));
if (confirmed) {
await userServiceClient.deleteUserAccessToken({ name: currentUser.name, accessToken: accessToken });
setUserAccessTokens(userAccessTokens.filter((token) => token.accessToken !== accessToken));
Expand Down Expand Up @@ -111,7 +110,7 @@ const AccessTokenSection = () => {
{userAccessToken.issuedAt?.toLocaleString()}
</td>
<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.duration-never")}
</td>
<td className="relative whitespace-nowrap py-2 pl-3 pr-4 text-right text-sm">
<Button
Expand Down
11 changes: 5 additions & 6 deletions web/src/components/UserStatisticsView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ const UserStatisticsView = () => {
const [visibleMonthString, setVisibleMonthString] = useState(dayjs(selectedDate.toDateString()).format("YYYY-MM"));
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 () => {
const memoStats: UserMemoStats = { link: 0, taskList: 0, code: 0, incompleteTasks: 0 };
metadataList.forEach((memo) => {
Expand Down Expand Up @@ -90,14 +93,10 @@ const UserStatisticsView = () => {
onClick={onCalendarClick}
/>
{memoAmount === 0 ? (
<p className="mt-1 w-full text-xs italic opacity-80">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">{t("memo.no-memos")}</p>
) : (
<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>
)}
</div>
Expand Down
36 changes: 32 additions & 4 deletions web/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"collapse": "Collapse",
"create": "Create",
"database": "Database",
"day": "Day",
"days": "Days",
"delete": "Delete",
"description": "Description",
Expand All @@ -34,12 +35,14 @@
"file": "File",
"filter": "Filter",
"home": "Home",
"in": "In",
"image": "Image",
"inbox": "Inbox",
"language": "Language",
"learn-more": "Learn more",
"link": "Link",
"mark": "Mark",
"memo": "Memo",
"memos": "Memos",
"name": "Name",
"new": "New",
Expand Down Expand Up @@ -103,7 +106,7 @@
"write-a-comment": "Write a comment"
},
"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",
"load-more": "Load more",
"no-archived-memos": "No archived memos.",
Expand All @@ -121,7 +124,14 @@
"to-do": "To-do",
"code": "Code",
"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": {
"archived-successfully": "Archived successfully",
Expand All @@ -139,7 +149,9 @@
"succeed-copy-link": "Link copied successfully.",
"update-succeed": "Update succeeded",
"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"
},
"reference": {
"add-references": "Add references",
Expand Down Expand Up @@ -308,11 +320,20 @@
},
"memo-related": "Memo",
"access-token-section":{
"create-access-token": "Create Access Token",
"title": "Access Tokens",
"description-label": "Description",
"some-description": "Some description...",
"description": "A list of all access tokens for your account.",
"expiration-label": "Expiration",
"created-at": "Created At",
"expires-at": "Expires At",
"token": "Token"
"token": "Token",
"duration-never": "Never",
"duration-8h": "8 Hours",
"duration-1m": "1 Month",
"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"
dandelionmood marked this conversation as resolved.
Show resolved Hide resolved
},
"webhook-section": {
"title": "Webhooks",
Expand Down Expand Up @@ -351,5 +372,12 @@
"code-block": "Code block",
"checkbox": "Checkbox",
"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"
}
}
Loading
Loading