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

i18n: Translate the website (excluding blogs) #358

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
2173e62
i18n: Proof of concept
danielhjacobs Nov 13, 2024
5e1a0eb
i18n: Put content of entire home page in translation files
danielhjacobs Nov 13, 2024
587e45d
Switch away from the pre-built hard to customize LanguageSwitcher
danielhjacobs Nov 14, 2024
6c20cc4
Use own logic for translation
danielhjacobs Nov 14, 2024
43d2e21
i18n: Translate logo by rewriting it to a modern functional component
danielhjacobs Nov 14, 2024
8ef7835
i18n: Switch to useTranslation so I can translate in loops
danielhjacobs Nov 15, 2024
d4b673a
Remove debug console logs
danielhjacobs Nov 15, 2024
c9eee6d
i18n: Translate installers, downloads, and 404 page
danielhjacobs Nov 15, 2024
ad8b031
i18n: Create simple component to provide translations with placeholder
danielhjacobs Nov 15, 2024
6848620
i18n: Translate compatibility page
danielhjacobs Nov 15, 2024
ddbe517
i18n: Translate avm2 page
danielhjacobs Nov 15, 2024
ad5b1f9
i18n: Add translations for contribute page and remove Spanish
danielhjacobs Nov 15, 2024
3b93eb0
i18n: Translate blog titles and read more links
danielhjacobs Nov 15, 2024
7da3111
i18n: Translate first blog post but keep RSS feed working
danielhjacobs Nov 16, 2024
8f9d5f9
Revert "i18n: Translate first blog post but keep RSS feed working"
danielhjacobs Nov 20, 2024
57ffb45
Revert "i18n: Translate blog titles and read more links"
danielhjacobs Nov 20, 2024
fb7d726
i18n: Copy language names from Crowdin
danielhjacobs Nov 21, 2024
8738b12
fix: Don't load logo player in useEffect and onReady
danielhjacobs Nov 21, 2024
4a9acd1
i18n: Stylize LanguageSelector
danielhjacobs Nov 21, 2024
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
23 changes: 16 additions & 7 deletions src/app/compatibility/avm.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"use client";

import classes from "./avm.module.css";
import {
Button,
Expand All @@ -9,6 +11,7 @@ import {
Title,
} from "@mantine/core";
import Link from "next/link";
import { useTranslation } from "@/app/translate";

interface AvmProgressProps {
done: number;
Expand All @@ -21,25 +24,26 @@ interface AvmProgressPropsFull extends AvmProgressProps {
}

function AvmProgress(props: AvmProgressPropsFull) {
const { t } = useTranslation();
return (
<Group align="center" justify="spread-between" mt={props.mt}>
<Text size="sm" className={classes.progressName}>
{props.name}: {props.done}%
{t(props.name)}: {props.done}%
</Text>
<ProgressRoot size="xl" radius={10} className={classes.progress}>
<ProgressSection
striped
value={props.done}
color="var(--mantine-color-green-9)"
title={`${props.done}% done`}
title={`${props.done}% ${t("compatibility.done")}`}
></ProgressSection>
{props.stubbed && (
<ProgressSection
striped
value={props.stubbed}
color="ruffle-orange"
className={classes.stub}
title={`${props.stubbed}% partially done`}
title={`${props.stubbed}% ${t("compatibility.partial")}`}
></ProgressSection>
)}
</ProgressRoot>
Expand All @@ -57,25 +61,30 @@ interface AvmBlockProps {
}

export function AvmBlock(props: AvmBlockProps) {
const { t } = useTranslation();
return (
<Stack className={classes.avm}>
<Group justify="space-between">
<Title order={2}>{props.name}</Title>
<Title order={2}>{t(props.name)}</Title>
<Button
component={Link}
href={props.info_link}
target={props.info_link_target}
size="compact-md"
color="var(--ruffle-blue-7)"
>
More Info
{t("compatibility.more")}
</Button>
</Group>

{props.children}

<AvmProgress name="Language" mt="auto" {...props.language} />
<AvmProgress name="API" {...props.api} />
<AvmProgress
name="compatibility.language"
mt="auto"
{...props.language}
/>
<AvmProgress name="compatibility.api" {...props.api} />
</Stack>
);
}
17 changes: 12 additions & 5 deletions src/app/compatibility/avm2/class_box.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ import classes from "./avm2.module.css";
import React from "react";
import {
ClassStatus,
ProgressIcon,
displayedPercentage,
} from "@/app/compatibility/avm2/report_utils";
import { ProgressIcon } from "@/app/compatibility/avm2/icons";
import { useTranslation } from "@/app/translate";

export function ClassBox(props: ClassStatus) {
const { t } = useTranslation();
const [opened, { toggle }] = useDisclosure(false);
const pctDone = displayedPercentage(
props.summary.impl_points - props.summary.stub_penalty,
Expand All @@ -33,21 +35,23 @@ export function ClassBox(props: ClassStatus) {
);
return (
<Card bg="var(--ruffle-blue-9)" className={classes.class}>
<Title order={4}>{props.name || "(Package level)"}</Title>
<Title order={4}>
{props.name || t("compatibility.avm2.package-level")}
</Title>
<ProgressRoot size="xl" radius={10} className={classes.progress}>
<ProgressSection
striped
value={pctDone}
color="var(--mantine-color-green-9)"
title={`${pctDone}% done`}
title={`${pctDone}% ${t("compatibility.done")}`}
></ProgressSection>
{pctStub > 0 && (
<ProgressSection
striped
value={pctStub}
color="ruffle-orange"
className={classes.progressStub}
title={`${pctStub}% partially done`}
title={`${pctStub}% ${t("compatibility.partial")}`}
></ProgressSection>
)}
</ProgressRoot>
Expand All @@ -58,7 +62,10 @@ export function ClassBox(props: ClassStatus) {
className={classes.showMemberButton}
onClick={toggle}
>
{opened ? "Hide" : "Show"} Missing Members
{opened
? t("compatibility.avm2.hide")
: t("compatibility.avm2.show")}{" "}
{t("compatibility.avm2.missing-members")}
</Button>
<List hidden={!opened}>
{props.items.map((item, i) => (
Expand Down
65 changes: 65 additions & 0 deletions src/app/compatibility/avm2/icons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"use client";

import { rem, ThemeIcon } from "@mantine/core";
import { IconCheck, IconProgress, IconX } from "@tabler/icons-react";
import { useTranslation } from "@/app/translate";

export function IconDone() {
const { t } = useTranslation();
return (
<ThemeIcon
size={20}
radius="xl"
color="var(--mantine-color-green-9)"
title={t("compatibility.avm2.done")}
>
<IconCheck
color="white"
style={{ width: rem(12), height: rem(12) }}
stroke={4}
/>
</ThemeIcon>
);
}

export function IconStub() {
const { t } = useTranslation();
return (
<ThemeIcon size={20} radius="xl" title={t("compatibility.avm2.partial")}>
<IconProgress
color="#3c1518"
style={{ width: rem(12), height: rem(12) }}
stroke={4}
/>
</ThemeIcon>
);
}

export function IconMissing() {
const { t } = useTranslation();
return (
<ThemeIcon
size={20}
radius="xl"
color="#3c1518"
title={t("compatibility.avm2.missing")}
>
<IconX
color="white"
style={{ width: rem(12), height: rem(12) }}
stroke={4}
/>
</ThemeIcon>
);
}

export function ProgressIcon(type: "stub" | "missing" | "done") {
switch (type) {
case "stub":
return <IconStub />;
case "missing":
return <IconMissing />;
case "done":
return <IconDone />;
}
}
97 changes: 63 additions & 34 deletions src/app/compatibility/avm2/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"use client";

import {
Container,
Group,
Expand All @@ -8,22 +10,26 @@ import {
Title,
} from "@mantine/core";
import Image from "next/image";
import React from "react";
import React, { useEffect, useState } from "react";
import classes from "./avm2.module.css";
import { ClassBox } from "@/app/compatibility/avm2/class_box";
import {
getReportByNamespace,
NamespaceStatus,
} from "@/app/compatibility/avm2/report_utils";
import {
IconDone,
IconMissing,
IconStub,
NamespaceStatus,
} from "@/app/compatibility/avm2/report_utils";
} from "@/app/compatibility/avm2/icons";
import Link from "next/link";
import { useTranslation, Trans } from "@/app/translate";

function NamespaceBox(props: NamespaceStatus) {
const { t } = useTranslation();
return (
<Stack className={classes.namespace}>
<Title order={2}>{props.name || "(Top Level)"}</Title>
<Title order={2}>{props.name || t("compatibility.avm2.top-level")}</Title>
<Group align="baseline">
{Object.entries(props.classes).map(([classname, classinfo]) => (
<ClassBox key={classname} {...classinfo} />
Expand All @@ -33,8 +39,22 @@ function NamespaceBox(props: NamespaceStatus) {
);
}

export default async function Page() {
const byNamespace = await getReportByNamespace();
export default function Page() {
const { t } = useTranslation();
const [byNamespace, setByNamespace] = useState<
{ [name: string]: NamespaceStatus } | undefined
>(undefined);
useEffect(() => {
const fetchData = async () => {
try {
const byNamespace = await getReportByNamespace();
setByNamespace(byNamespace);
} catch (error) {
console.error("Error fetching data", error);
}
};
fetchData();
}, []);
return (
<Container size="xl">
<Stack gap="xl">
Expand All @@ -48,43 +68,52 @@ export default async function Page() {
className={classes.progressImage}
/>
<Stack className={classes.actionscriptInfo}>
<Title className={classes.title}>ActionScript 3 API Progress</Title>
<Text>
ActionScript 3 contains many different methods and classes - not
all of which is ultimately <i>useful</i> to every application. The
majority of content only uses a small portion of the available
API, so even if we aren&apos;t 100% &quot;complete&quot; across
the entirely of AVM 2, we may have enough for that content to run
completely fine.
</Text>
<Text>
On this page, we list every single ActionScript 3 API that exists
but Ruffle does not yet 100% implement. We classify items into
three different stages:
</Text>
<Title className={classes.title}>
{t("compatibility.avm2.title")}
</Title>
<Text>{t("compatibility.avm2.description")}</Text>
<Text>{t("compatibility.avm2.classification")}</Text>
<List spacing="sm">
<ListItem icon={<IconDone />}>
<b>Implemented</b> items are marked as &quot;Done&quot;, and we
believe they are fully functional. For brevity, we do not list
completed items on this page.
<Trans
i18nKey="compatibility.avm2.implemented-description"
components={[
<b key="implemented">
{t("compatibility.avm2.implemented")}
</b>,
]}
/>
</ListItem>
<ListItem icon={<IconStub />}>
<b>Partial</b> items exist and are enough for most content to
work, but are incomplete. A partial class may be missing items,
or a method may just simply return a value without performing
its intended function.
<Trans
i18nKey="compatibility.avm2.partial-description"
components={[
<b key="partial">{t("compatibility.avm2.partial")}</b>,
]}
/>
</ListItem>
<ListItem icon={<IconMissing />}>
<b>Missing</b> items do not exist at all in Ruffle yet, and
trying to use them will give an error.
<Trans
i18nKey="compatibility.avm2.missing-description"
components={[
<b key="missing">{t("compatibility.avm2.missing")}</b>,
]}
/>
</ListItem>
</List>
<Text>
You can also visualize the progress{" "}
<Link href="/compatibility/avm2/tree.svg" target="_blank">
as a tree graph
</Link>
.
<Trans
i18nKey="compatibility.avm2.tree"
components={[
<Link
key="link"
href="/compatibility/avm2/tree.svg"
target="_blank"
>
{t("compatibility.avm2.tree-link")}
</Link>,
]}
/>
</Text>
</Stack>
</Group>
Expand Down
Loading