mirror of
https://github.com/docmost/docmost.git
synced 2025-11-16 19:01:11 +10:00
feat: complete page translation
This commit is contained in:
26
apps/client/public/locales/en/page.json
Normal file
26
apps/client/public/locales/en/page.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"Copy link": "Copy link",
|
||||||
|
"Delete": "Delete",
|
||||||
|
"Link copied": "Link copied",
|
||||||
|
"Are you sure you want to delete this page?": "Are you sure you want to delete this page?",
|
||||||
|
"Cancel": "Cancel",
|
||||||
|
"deletePageModalContent": "Are you sure you want to delete this page? This will delete its children and page history. This action is irreversible.",
|
||||||
|
"Page deleted successfully": "Page deleted successfully",
|
||||||
|
"Failed to delete page": "Failed to delete page",
|
||||||
|
"Failed to create page": "Failed to create page",
|
||||||
|
"Import pages": "Import pages",
|
||||||
|
"Importing pages": "Importing pages",
|
||||||
|
"Page import is in progress. Please do not close this tab.": "Page import is in progress. Please do not close this tab.",
|
||||||
|
"Successfully imported": "Successfully imported",
|
||||||
|
"Your import is complete.": "Your import is complete.",
|
||||||
|
"Failed to import pages": "Failed to import pages",
|
||||||
|
"Unable to import pages. Please try again.": "Unable to import pages. Please try again.",
|
||||||
|
"page": "page",
|
||||||
|
"pages": "pages",
|
||||||
|
"Error fetching page data.": "Error fetching page data.",
|
||||||
|
"untitled": "untitled",
|
||||||
|
"Full width": "Full width",
|
||||||
|
"Page history": "Page history",
|
||||||
|
"Export": "Export",
|
||||||
|
"Print PDF": "Print PDF"
|
||||||
|
}
|
||||||
@ -40,17 +40,7 @@
|
|||||||
"Recently updated": "Recently updated"
|
"Recently updated": "Recently updated"
|
||||||
},
|
},
|
||||||
"space": {},
|
"space": {},
|
||||||
"page": {
|
"page": {},
|
||||||
"Error fetching page data.": "Error fetching page data.",
|
|
||||||
"untitled": "untitled",
|
|
||||||
"Link copied": "Link copied",
|
|
||||||
"Copy link": "Copy link",
|
|
||||||
"Full width": "Full width",
|
|
||||||
"Page history": "Page history",
|
|
||||||
"Export": "Export",
|
|
||||||
"Print PDF": "Print PDF",
|
|
||||||
"Delete": "Delete"
|
|
||||||
},
|
|
||||||
"page-history": {
|
"page-history": {
|
||||||
"Page history": "Page history",
|
"Page history": "Page history",
|
||||||
"Error loading page history.": "Error loading page history.",
|
"Error loading page history.": "Error loading page history.",
|
||||||
|
|||||||
26
apps/client/public/locales/zh/page.json
Normal file
26
apps/client/public/locales/zh/page.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"Copy link": "复制链接",
|
||||||
|
"Delete": "删除",
|
||||||
|
"Link copied": "链接已复制",
|
||||||
|
"Are you sure you want to delete this page?": "您确定要删除这个页面吗?",
|
||||||
|
"Cancel": "取消",
|
||||||
|
"deletePageModalContent": "您确定要删除这个页面吗?这将删除其子页面和页面历史记录。此操作不可逆。",
|
||||||
|
"Page deleted successfully": "页面已成功删除",
|
||||||
|
"Failed to delete page": "删除页面失败",
|
||||||
|
"Failed to create page": "创建页面失败",
|
||||||
|
"Import pages": "导入页面",
|
||||||
|
"Importing pages": "正在导入页面",
|
||||||
|
"Page import is in progress. Please do not close this tab.": "页面导入正在进行中。请不要关闭此标签页。",
|
||||||
|
"Successfully imported": "成功导入",
|
||||||
|
"Your import is complete.": "导入已完成。",
|
||||||
|
"Failed to import pages": "导入页面失败",
|
||||||
|
"Unable to import pages. Please try again.": "无法导入页面。请重试。",
|
||||||
|
"page": "个页面",
|
||||||
|
"pages": "个页面",
|
||||||
|
"Error fetching page data.": "获取页面数据时出错。",
|
||||||
|
"untitled": "无标题",
|
||||||
|
"Full width": "全宽",
|
||||||
|
"Page history": "页面历史",
|
||||||
|
"Export": "导出",
|
||||||
|
"Print PDF": "打印 PDF"
|
||||||
|
}
|
||||||
@ -40,17 +40,7 @@
|
|||||||
"Recently updated": "最近更新"
|
"Recently updated": "最近更新"
|
||||||
},
|
},
|
||||||
"space": {},
|
"space": {},
|
||||||
"page": {
|
"page": {},
|
||||||
"Error fetching page data.": "获取页面数据时出错。",
|
|
||||||
"untitled": "无标题",
|
|
||||||
"Link copied": "链接已复制",
|
|
||||||
"Copy link": "复制链接",
|
|
||||||
"Full width": "全宽",
|
|
||||||
"Page history": "页面历史",
|
|
||||||
"Export": "导出",
|
|
||||||
"Print PDF": "打印 PDF",
|
|
||||||
"Delete": "删除"
|
|
||||||
},
|
|
||||||
"page-history": {
|
"page-history": {
|
||||||
"Page history": "页面历史",
|
"Page history": "页面历史",
|
||||||
"Error loading page history.": "加载页面历史时出错。",
|
"Error loading page history.": "加载页面历史时出错。",
|
||||||
|
|||||||
@ -53,8 +53,7 @@ interface PageActionMenuProps {
|
|||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
}
|
}
|
||||||
function PageActionMenu({ readOnly }: PageActionMenuProps) {
|
function PageActionMenu({ readOnly }: PageActionMenuProps) {
|
||||||
const { t } = useTranslation("translation", { keyPrefix: "page" });
|
const { t } = useTranslation("page");
|
||||||
|
|
||||||
const [, setHistoryModalOpen] = useAtom(historyAtoms);
|
const [, setHistoryModalOpen] = useAtom(historyAtoms);
|
||||||
const clipboard = useClipboard({ timeout: 500 });
|
const clipboard = useClipboard({ timeout: 500 });
|
||||||
const { pageSlug, spaceSlug } = useParams();
|
const { pageSlug, spaceSlug } = useParams();
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import { useAtom } from "jotai";
|
|||||||
import { buildTree } from "@/features/page/tree/utils";
|
import { buildTree } from "@/features/page/tree/utils";
|
||||||
import { IPage } from "@/features/page/types/page.types.ts";
|
import { IPage } from "@/features/page/types/page.types.ts";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
interface PageImportModalProps {
|
interface PageImportModalProps {
|
||||||
spaceId: string;
|
spaceId: string;
|
||||||
@ -24,6 +25,7 @@ export default function PageImportModal({
|
|||||||
open,
|
open,
|
||||||
onClose,
|
onClose,
|
||||||
}: PageImportModalProps) {
|
}: PageImportModalProps) {
|
||||||
|
const { t } = useTranslation("page");
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Modal.Root
|
<Modal.Root
|
||||||
@ -38,7 +40,7 @@ export default function PageImportModal({
|
|||||||
<Modal.Overlay />
|
<Modal.Overlay />
|
||||||
<Modal.Content style={{ overflow: "hidden" }}>
|
<Modal.Content style={{ overflow: "hidden" }}>
|
||||||
<Modal.Header py={0}>
|
<Modal.Header py={0}>
|
||||||
<Modal.Title fw={500}>Import pages</Modal.Title>
|
<Modal.Title fw={500}>{t("Import pages")}</Modal.Title>
|
||||||
<Modal.CloseButton />
|
<Modal.CloseButton />
|
||||||
</Modal.Header>
|
</Modal.Header>
|
||||||
<Modal.Body>
|
<Modal.Body>
|
||||||
@ -55,6 +57,7 @@ interface ImportFormatSelection {
|
|||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}
|
}
|
||||||
function ImportFormatSelection({ spaceId, onClose }: ImportFormatSelection) {
|
function ImportFormatSelection({ spaceId, onClose }: ImportFormatSelection) {
|
||||||
|
const { t } = useTranslation("page");
|
||||||
const [treeData, setTreeData] = useAtom(treeDataAtom);
|
const [treeData, setTreeData] = useAtom(treeDataAtom);
|
||||||
|
|
||||||
const handleFileUpload = async (selectedFiles: File[]) => {
|
const handleFileUpload = async (selectedFiles: File[]) => {
|
||||||
@ -65,8 +68,8 @@ function ImportFormatSelection({ spaceId, onClose }: ImportFormatSelection) {
|
|||||||
onClose();
|
onClose();
|
||||||
|
|
||||||
const alert = notifications.show({
|
const alert = notifications.show({
|
||||||
title: "Importing pages",
|
title: t("Importing pages"),
|
||||||
message: "Page import is in progress. Please do not close this tab.",
|
message: t("Page import is in progress. Please do not close this tab."),
|
||||||
loading: true,
|
loading: true,
|
||||||
autoClose: false,
|
autoClose: false,
|
||||||
});
|
});
|
||||||
@ -92,13 +95,14 @@ function ImportFormatSelection({ spaceId, onClose }: ImportFormatSelection) {
|
|||||||
setTreeData(fullTree);
|
setTreeData(fullTree);
|
||||||
}
|
}
|
||||||
|
|
||||||
const pageCountText = pageCount === 1 ? "1 page" : `${pageCount} pages`;
|
const pageCountText =
|
||||||
|
pageCount === 1 ? `1 ${t("page")}` : `${pageCount} ${t("pages")}`;
|
||||||
|
|
||||||
notifications.update({
|
notifications.update({
|
||||||
id: alert,
|
id: alert,
|
||||||
color: "teal",
|
color: "teal",
|
||||||
title: `Successfully imported ${pageCountText}`,
|
title: `${t("Successfully imported")} ${pageCountText}`,
|
||||||
message: "Your import is complete.",
|
message: t("Your import is complete."),
|
||||||
icon: <IconCheck size={18} />,
|
icon: <IconCheck size={18} />,
|
||||||
loading: false,
|
loading: false,
|
||||||
autoClose: 5000,
|
autoClose: 5000,
|
||||||
@ -107,8 +111,8 @@ function ImportFormatSelection({ spaceId, onClose }: ImportFormatSelection) {
|
|||||||
notifications.update({
|
notifications.update({
|
||||||
id: alert,
|
id: alert,
|
||||||
color: "red",
|
color: "red",
|
||||||
title: `Failed to import pages`,
|
title: t("Failed to import pages"),
|
||||||
message: "Unable to import pages. Please try again.",
|
message: t("Unable to import pages. Please try again."),
|
||||||
icon: <IconX size={18} />,
|
icon: <IconX size={18} />,
|
||||||
loading: false,
|
loading: false,
|
||||||
autoClose: 5000,
|
autoClose: 5000,
|
||||||
|
|||||||
@ -1,22 +1,19 @@
|
|||||||
import { modals } from "@mantine/modals";
|
import { modals } from "@mantine/modals";
|
||||||
import { Text } from "@mantine/core";
|
import { Text } from "@mantine/core";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
type UseDeleteModalProps = {
|
type UseDeleteModalProps = {
|
||||||
onConfirm: () => void;
|
onConfirm: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function useDeletePageModal() {
|
export function useDeletePageModal() {
|
||||||
|
const { t } = useTranslation("page");
|
||||||
const openDeleteModal = ({ onConfirm }: UseDeleteModalProps) => {
|
const openDeleteModal = ({ onConfirm }: UseDeleteModalProps) => {
|
||||||
modals.openConfirmModal({
|
modals.openConfirmModal({
|
||||||
title: "Are you sure you want to delete this page?",
|
title: t("Are you sure you want to delete this page?"),
|
||||||
children: (
|
children: <Text size="sm">{t("deletePageModalContent")}</Text>,
|
||||||
<Text size="sm">
|
|
||||||
Are you sure you want to delete this page? This will delete its
|
|
||||||
children and page history. This action is irreversible.
|
|
||||||
</Text>
|
|
||||||
),
|
|
||||||
centered: true,
|
centered: true,
|
||||||
labels: { confirm: "Delete", cancel: "Cancel" },
|
labels: { confirm: t("Delete"), cancel: t("Cancel") },
|
||||||
confirmProps: { color: "red" },
|
confirmProps: { color: "red" },
|
||||||
onConfirm,
|
onConfirm,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -25,6 +25,7 @@ import { notifications } from "@mantine/notifications";
|
|||||||
import { IPagination } from "@/lib/types.ts";
|
import { IPagination } from "@/lib/types.ts";
|
||||||
import { queryClient } from "@/main.tsx";
|
import { queryClient } from "@/main.tsx";
|
||||||
import { buildTree } from "@/features/page/tree/utils";
|
import { buildTree } from "@/features/page/tree/utils";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
export function usePageQuery(
|
export function usePageQuery(
|
||||||
pageInput: Partial<IPageInput>,
|
pageInput: Partial<IPageInput>,
|
||||||
@ -38,11 +39,12 @@ export function usePageQuery(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function useCreatePageMutation() {
|
export function useCreatePageMutation() {
|
||||||
|
const { t } = useTranslation('page');
|
||||||
return useMutation<IPage, Error, Partial<IPageInput>>({
|
return useMutation<IPage, Error, Partial<IPageInput>>({
|
||||||
mutationFn: (data) => createPage(data),
|
mutationFn: (data) => createPage(data),
|
||||||
onSuccess: (data) => {},
|
onSuccess: (data) => { },
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
notifications.show({ message: "Failed to create page", color: "red" });
|
notifications.show({ message: t("Failed to create page"), color: "red" });
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -74,13 +76,14 @@ export function useUpdatePageMutation() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function useDeletePageMutation() {
|
export function useDeletePageMutation() {
|
||||||
|
const { t } = useTranslation('page');
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: (pageId: string) => deletePage(pageId),
|
mutationFn: (pageId: string) => deletePage(pageId),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
notifications.show({ message: "Page deleted successfully" });
|
notifications.show({ message: t("Page deleted successfully") });
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
notifications.show({ message: "Failed to delete page", color: "red" });
|
notifications.show({ message: t("Failed to delete page"), color: "red" });
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,6 +47,7 @@ import { notifications } from "@mantine/notifications";
|
|||||||
import { getAppUrl } from "@/lib/config.ts";
|
import { getAppUrl } from "@/lib/config.ts";
|
||||||
import { extractPageSlugId } from "@/lib";
|
import { extractPageSlugId } from "@/lib";
|
||||||
import { useDeletePageModal } from "@/features/page/hooks/use-delete-page-modal.tsx";
|
import { useDeletePageModal } from "@/features/page/hooks/use-delete-page-modal.tsx";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
interface SpaceTreeProps {
|
interface SpaceTreeProps {
|
||||||
spaceId: string;
|
spaceId: string;
|
||||||
@ -397,6 +398,7 @@ interface NodeMenuProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function NodeMenu({ node, treeApi }: NodeMenuProps) {
|
function NodeMenu({ node, treeApi }: NodeMenuProps) {
|
||||||
|
const { t } = useTranslation("page");
|
||||||
const clipboard = useClipboard({ timeout: 500 });
|
const clipboard = useClipboard({ timeout: 500 });
|
||||||
const { spaceSlug } = useParams();
|
const { spaceSlug } = useParams();
|
||||||
const { openDeleteModal } = useDeletePageModal();
|
const { openDeleteModal } = useDeletePageModal();
|
||||||
@ -405,7 +407,7 @@ function NodeMenu({ node, treeApi }: NodeMenuProps) {
|
|||||||
const pageUrl =
|
const pageUrl =
|
||||||
getAppUrl() + buildPageUrl(spaceSlug, node.data.slugId, node.data.name);
|
getAppUrl() + buildPageUrl(spaceSlug, node.data.slugId, node.data.name);
|
||||||
clipboard.copy(pageUrl);
|
clipboard.copy(pageUrl);
|
||||||
notifications.show({ message: "Link copied" });
|
notifications.show({ message: t("Link copied") });
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -435,7 +437,7 @@ function NodeMenu({ node, treeApi }: NodeMenuProps) {
|
|||||||
handleCopyLink();
|
handleCopyLink();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Copy link
|
{t("Copy link")}
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
|
||||||
{!(treeApi.props.disableEdit as boolean) && (
|
{!(treeApi.props.disableEdit as boolean) && (
|
||||||
@ -453,7 +455,7 @@ function NodeMenu({ node, treeApi }: NodeMenuProps) {
|
|||||||
openDeleteModal({ onConfirm: () => treeApi?.delete(node) });
|
openDeleteModal({ onConfirm: () => treeApi?.delete(node) });
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Delete
|
{t("Delete")}
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user