diff --git a/website/src/components/templates/BaseTemplate.tsx b/website/src/components/templates/BaseTemplate.tsx index c6f1d7f393..0ca8b22aca 100644 --- a/website/src/components/templates/BaseTemplate.tsx +++ b/website/src/components/templates/BaseTemplate.tsx @@ -1,7 +1,7 @@ import { html } from "hono/html"; import type { FC, PropsWithChildren } from "hono/jsx"; import { basePath, originUrl, typstOfficialDocsUrl } from "../../metadata"; -import { Translation, translation } from "../../translation"; +import { Translation, translation } from "../../translation/"; import type { Page } from "../../types/model"; import { joinPath, removeBasePath } from "../../utils/path"; import { getTranslationStatus } from "../../utils/translationStatus"; diff --git a/website/src/components/templates/CategoryTemplate.tsx b/website/src/components/templates/CategoryTemplate.tsx index 5eeafda15f..9d53269ae1 100644 --- a/website/src/components/templates/CategoryTemplate.tsx +++ b/website/src/components/templates/CategoryTemplate.tsx @@ -1,5 +1,5 @@ import type { FC } from "hono/jsx"; -import { Translation } from "../../translation"; +import { Translation } from "../../translation/"; import type { CategoryBody, Page } from "../../types/model"; import { HtmlContent } from "../ui/HtmlContent"; import BaseTemplate, { type BaseTemplateProps } from "./BaseTemplate"; diff --git a/website/src/components/templates/FuncTemplate.tsx b/website/src/components/templates/FuncTemplate.tsx index 807d966d23..e2aae8cb5c 100644 --- a/website/src/components/templates/FuncTemplate.tsx +++ b/website/src/components/templates/FuncTemplate.tsx @@ -1,5 +1,5 @@ import type { FC } from "hono/jsx"; -import { Translation } from "../../translation"; +import { Translation } from "../../translation/"; import type { Func, FuncBody, Page } from "../../types/model"; import { FunctionDefinition, diff --git a/website/src/components/templates/TypeTemplate.tsx b/website/src/components/templates/TypeTemplate.tsx index 50a9a11a78..60a943d2c9 100644 --- a/website/src/components/templates/TypeTemplate.tsx +++ b/website/src/components/templates/TypeTemplate.tsx @@ -1,5 +1,5 @@ import type { FC } from "hono/jsx"; -import { Translation } from "../../translation"; +import { Translation } from "../../translation/"; import type { Page, TypeBody } from "../../types/model"; import { FunctionDisplay, Tooltip } from "../ui"; import { HtmlContent } from "../ui/HtmlContent"; diff --git a/website/src/components/ui/FunctionDisplay.tsx b/website/src/components/ui/FunctionDisplay.tsx index c884644147..9ae1ae7012 100644 --- a/website/src/components/ui/FunctionDisplay.tsx +++ b/website/src/components/ui/FunctionDisplay.tsx @@ -1,5 +1,5 @@ import type { FC } from "hono/jsx"; -import { Translation } from "../../translation"; +import { Translation } from "../../translation/"; import type { Func } from "../../types/model"; import { ChevronRightIcon } from "../icons"; import { FunctionDefinition } from "./FunctionDefinition"; diff --git a/website/src/components/ui/FunctionParameters.tsx b/website/src/components/ui/FunctionParameters.tsx index fead4c3600..88e164d789 100644 --- a/website/src/components/ui/FunctionParameters.tsx +++ b/website/src/components/ui/FunctionParameters.tsx @@ -1,6 +1,6 @@ import type { FC } from "hono/jsx"; import { basePath } from "../../metadata"; -import { Translation } from "../../translation"; +import { Translation } from "../../translation/"; import type { Func } from "../../types/model"; import { joinPath } from "../../utils/path"; import { ChevronRightIcon } from "../icons"; diff --git a/website/src/components/ui/Tooltip.tsx b/website/src/components/ui/Tooltip.tsx index 37a50ac2cc..be6dc8d4e0 100644 --- a/website/src/components/ui/Tooltip.tsx +++ b/website/src/components/ui/Tooltip.tsx @@ -1,5 +1,5 @@ import type { FC } from "hono/jsx"; -import { Translation, translation } from "../../translation"; +import { Translation, translation } from "../../translation/"; import { CloseIcon, HelpCircleIcon } from "../icons"; export type TooltipProps = { diff --git a/website/src/components/ui/common/Footer.tsx b/website/src/components/ui/common/Footer.tsx index ed4a081926..c783e96dcf 100644 --- a/website/src/components/ui/common/Footer.tsx +++ b/website/src/components/ui/common/Footer.tsx @@ -3,6 +3,7 @@ import { githubOrganizationUrl, githubRepositoryUrl, } from "../../../metadata"; +import { Translation } from "../../../translation/"; import { DiscordIcon, GitHubIcon } from "../../icons"; export const Footer = () => { @@ -32,13 +33,7 @@ export const Footer = () => {
-						Translated by{" "}
-						
-							Typst Japanese Community
-						
+						
{props.name} Definition
+				>
+			);
+		case "search":
+			return <>Search>;
+		case "defaultValue":
+			return <>Default value:>;
+		case "stringValues":
+			return <>Available string values:>;
+		case "showExample":
+			return <>Show example>;
+		case "tableOfContents":
+			return <>On this page>;
+		case "nextPage":
+			return <>Next page>;
+		case "previousPage":
+			return <>Previous page>;
+		case "referenceDescription":
+			return (
+				<>
+					Detailed reference for all Typst syntax, concepts, types, and
+					functions.
+				>
+			);
+		case "tutorialDescription":
+			return <>Learn how to use Typst step by step.>;
+		case "tutorial":
+			return <>Tutorial>;
+		case "openOfficialDocs":
+			return <>Open official docs>;
+		case "reference":
+			return <>Reference>;
+		case "typstOfficialDocs":
+			return <>Typst official docs>;
+		case "typstOfficialWebsite":
+			return <>Typst official website>;
+		case "untranslated":
+			return <>Untranslated>;
+		case "untranslatedMessage":
+			return (
+				<>
+					This page has not been translated yet. The original content is shown.
+				>
+			);
+		case "communityContent":
+			return <>Community original content>;
+		case "contentAddedByCommunity":
+			return (
+				<>
+					This page contains content that is not part of the official
+					documentation, added independently by the community.
+				>
+			);
+		case "partiallyTranslated":
+			return <>Partially translated>;
+		case "partiallyTranslatedMessage":
+			return (
+				<>
+					This page is partially translated. Some original content is included.
+				>
+			);
+		case "translated":
+			return <>Translated>;
+		case "translatedMessage":
+			return <>This page has been translated into English.>;
+		case "elementFunction":
+			return <>Element>;
+		case "elementFunctionDescription":
+			return (
+				<>
+					Element functions can be customized with set and{" "}
+					show rules.
+				>
+			);
+		case "contextFunction":
+			return <>Context>;
+		case "contextFunctionDescription":
+			return <>Context functions can only be used when the context is known.>;
+		case "definitionTooltip":
+			return <>Definition>;
+		case "definitionTooltipDescription":
+			return (
+				<>
+					These functions and types can have related definitions. To access a
+					definition, specify the name of the function or type, followed by the
+					definition name separated by a period.
+				>
+			);
+		case "argument":
+			return <>Parameter>;
+		case "argumentDescription":
+			return (
+				<>
+					Parameters are input values for functions. Specify them in parentheses
+					after the function name.
+				>
+			);
+		case "variadic":
+			return <>Variadic>;
+		case "variadicDescription":
+			return <>Variadic parameters can be specified multiple times.>;
+		case "positional":
+			return <>Positional>;
+		case "positionalDescription":
+			return (
+				<>
+					Positional parameters can be set by specifying them in order, omitting
+					the parameter name.
+				>
+			);
+		case "required":
+			return <>Required>;
+		case "requiredDescription":
+			return (
+				<>Required parameters must be specified when calling the function.>
+			);
+		case "document":
+			return <>Document>;
+		case "langVersion":
+			return <>English>;
+		case "translationRate":
+			return <>Translated>;
+		case "settable":
+			return <>Settable>;
+		case "settableDescription":
+			return (
+				<>
+					Settable parameters can be set using the set rule,
+					changing the default value used thereafter.
+				>
+			);
+		case "siteNoticeBannerTitle":
+			return <>Info>;
+		case "siteNoticeBannerDescription":
+			return (
+				<>
+					This site is generated using the static site generator developed by
+					the Typst Community.
+					Please adjust the text content of this banner according to your usage
+					requirements. At Typst GmbH's request, when publishing documentation,
+					you must clearly indicate that it is non-official and display the
+					version of Typst being documented. For details, refer to{" "}
+					
+						Issue #874 on typst/typst
+					
+					.
+				>
+			);
+		case "footer":
+			return (
+				<>
+					Translated by Typst Community
+				>
+			);
+		default:
+			return null;
+	}
+};
diff --git a/website/src/translation/index.tsx b/website/src/translation/index.tsx
new file mode 100644
index 0000000000..a724f67c88
--- /dev/null
+++ b/website/src/translation/index.tsx
@@ -0,0 +1,86 @@
+import type { FC } from "hono/jsx";
+import type { TooltipProps } from "../components/ui/Tooltip";
+
+/**
+ * Translation dictionary for UI attributes and aria labels.
+ *
+ * @example
+ * translation.closeMenu()
+ * translation.showInformation({ name: "foo" })
+ */
+export type TranslationObject = {
+	htmlLang: () => string;
+	documentationTitle: () => string;
+	close: () => string;
+	closeMenu: () => string;
+	closeSearch: () => string;
+	openMenu: () => string;
+	openSearch: () => string;
+	showInformation: (props: { name: string }) => string;
+	tooltipKind: (props: { kind: TooltipProps["kind"] }) => string;
+};
+
+type TranslationComponentKey =
+	| "definition"
+	| "constructor"
+	| "tableOfContents"
+	| "untranslated"
+	| "untranslatedMessage"
+	| "document"
+	| "langVersion"
+	| "elementFunction"
+	| "elementFunctionDescription"
+	| "contextFunction"
+	| "contextFunctionDescription"
+	| "definitionTooltip"
+	| "definitionTooltipDescription"
+	| "variadic"
+	| "translationRate"
+	| "variadicDescription"
+	| "typstOfficialDocs"
+	| "typstOfficialWebsite"
+	| "communityContent"
+	| "contentAddedByCommunity"
+	| "partiallyTranslated"
+	| "partiallyTranslatedMessage"
+	| "translated"
+	| "translatedMessage"
+	| "siteNoticeBannerTitle"
+	| "siteNoticeBannerDescription"
+	| "tutorial"
+	| "tutorialDescription"
+	| "referenceDescription"
+	| "reference"
+	| "openOfficialDocs"
+	| "search"
+	| "argument"
+	| "argumentDescription"
+	| "required"
+	| "requiredDescription"
+	| "positional"
+	| "positionalDescription"
+	| "defaultValue"
+	| "stringValues"
+	| "showExample"
+	| "settable"
+	| "settableDescription"
+	| "previousPage"
+	| "nextPage"
+	| "footer";
+
+export type TranslationComponentProps =
+	| { translationKey: TranslationComponentKey }
+	| { translationKey: "definitionOf"; name: string };
+
+/**
+ * Translation component for UI text, descriptions, and other content to be embedded as JSX.
+ *
+ * @example
+ *