Skip to content

Commit e7402e4

Browse files
committed
i18n: Create simple component to provide translations with placeholder
1 parent 0d8af8a commit e7402e4

File tree

4 files changed

+70
-32
lines changed

4 files changed

+70
-32
lines changed

src/app/downloads/nightlies.tsx

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import {
2424
githubReleasesUrl,
2525
webLinks,
2626
} from "@/app/downloads/config";
27-
import { useTranslation } from "@/app/translate";
27+
import { useTranslation, Trans } from "@/app/translate";
2828

2929
function DownloadLink({
3030
link,
@@ -130,15 +130,19 @@ export function NightlyList({
130130
<Stack>
131131
<Title id="nightly-releases">{t("downloads.nightly-releases")}</Title>
132132
<Text>
133-
{t("downloads.nightly-releases-description")}{" "}
134-
<Link
135-
href={githubReleasesUrl}
136-
className={classes.moreNightlies}
137-
target="_blank"
138-
>
139-
{t("footer.github")}
140-
</Link>
141-
{t("common.line-ender")}
133+
<Trans
134+
i18nKey="downloads.nightly-releases-description"
135+
components={[
136+
<Link
137+
key="link"
138+
href={githubReleasesUrl}
139+
className={classes.moreNightlies}
140+
target="_blank"
141+
>
142+
{t("footer.github")}
143+
</Link>,
144+
]}
145+
/>
142146
</Text>
143147
<Table
144148
horizontalSpacing="md"

src/app/downloads/page.tsx

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import {
2121
maxNightlies,
2222
} from "@/app/downloads/config";
2323
import { getLatestReleases } from "@/app/downloads/github";
24-
import { useTranslation } from "@/app/translate";
24+
import { useTranslation, Trans } from "@/app/translate";
2525

2626
function WebDownload({ latest }: { latest: GithubRelease | null }) {
2727
const { t } = useTranslation();
@@ -33,24 +33,34 @@ function WebDownload({ latest }: { latest: GithubRelease | null }) {
3333
{'<script src="https://unpkg.com/@ruffle-rs/ruffle"></script>'}
3434
</Code>
3535
<Text>
36-
{t("downloads.self-host-description-start")}{" "}
37-
<Link
38-
href={latest?.downloads?.web || githubReleasesUrl}
39-
target="_blank"
40-
>
41-
{t("downloads.self-host-description-link")}
42-
</Link>{" "}
43-
{t("downloads.self-host-description-end")}
36+
<Trans
37+
i18nKey="downloads.self-host-description"
38+
components={[
39+
<Link
40+
key="link"
41+
href={latest?.downloads?.web || githubReleasesUrl}
42+
target="_blank"
43+
>
44+
{t("downloads.self-host-description-link")}
45+
</Link>,
46+
]}
47+
/>
4448
</Text>
4549
<Code block className={classes.cdn}>
4650
{'<script src="path/to/ruffle.js"></script>'}
4751
</Code>
4852
<Text>
49-
{t("downloads.advanced-usage-description-start")}{" "}
50-
<Link href="https://github.com/ruffle-rs/ruffle/wiki/Using-Ruffle#javascript-api">
51-
{t("downloads.advanced-usage-description-link")}
52-
</Link>{" "}
53-
{t("downloads.advanced-usage-description-end")}
53+
<Trans
54+
i18nKey="downloads.advanced-usage-description"
55+
components={[
56+
<Link
57+
key="link"
58+
href="https://github.com/ruffle-rs/ruffle/wiki/Using-Ruffle#javascript-api"
59+
>
60+
{t("downloads.advanced-usage-description-link")}
61+
</Link>,
62+
]}
63+
/>
5464
</Text>
5565
</Stack>
5666
);

src/app/translate.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,35 @@ export function useTranslation() {
111111
return { t };
112112
}
113113

114+
interface TransProps {
115+
i18nKey: string; // Translation key
116+
components?: React.ReactNode[]; // Components to inject into placeholders
117+
}
118+
119+
export const Trans: React.FC<TransProps> = ({ i18nKey, components = [] }) => {
120+
const { t } = useTranslation();
121+
const translation = t(i18nKey);
122+
123+
const renderWithPlaceholders = (template: string) => {
124+
const parts = template.split(/({{.*?}})/g); // Split on placeholders like {{key}}
125+
return parts.map((part) => {
126+
const match = part.match(/{{(.*?)}}/); // Match placeholders
127+
if (match) {
128+
const placeholderKey = match[1];
129+
const component = components.find(
130+
(comp) => React.isValidElement(comp) && comp.key === placeholderKey,
131+
);
132+
if (component) {
133+
return component;
134+
}
135+
}
136+
return part; // Return plain text if no placeholder
137+
});
138+
};
139+
140+
return <>{renderWithPlaceholders(translation)}</>;
141+
};
142+
114143
export const LanguageSelector: React.FC<LanguageSelectorProps> = ({
115144
className,
116145
}) => {

src/i18n/translations.en.json

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,20 +64,15 @@
6464
"browser-extension": "Browser Extension",
6565
"browser-extension-description": "If you visit websites that have Flash content but aren't using Ruffle, or you want to ensure you're using the latest and greatest version of Ruffle on every website, then our browser extension is the perfect thing for you!",
6666
"nightly-releases": "Nightly Releases",
67-
"nightly-releases-description": "If none of the above are suitable for you, you can manually download the latest Nightly release. These are automatically built every day (approximately midnight UTC), unless there are no changes on that day. Older nightly releases are available on",
67+
"nightly-releases-description": "If none of the above are suitable for you, you can manually download the latest Nightly release. These are automatically built every day (approximately midnight UTC), unless there are no changes on that day. Older nightly releases are available on {{link}}.",
6868
"web-package": "Web Package",
6969
"web-package-description": "You can install Ruffle onto a website using one single line of code by using a CDN, no extra work required! It'll always stay up to date with the latest available version of Ruffle.",
70-
"self-host-description-start": "If you'd like to host it yourself, you can grab",
70+
"self-host-description": "If you'd like to host it yourself, you can grab {{link}} and upload it to your server. Then, include it on your page like so:",
7171
"self-host-description-link": "the latest self-hosted package",
72-
"self-host-description-end": "and upload it to your server. Then, include it on your page like so:",
73-
"advanced-usage-description-start": "For advanced usage, consult",
72+
"advanced-usage-description": "For advanced usage, consult {{link}} for our JavaScript API and installation options.",
7473
"advanced-usage-description-link": "our documentation",
75-
"advanced-usage-description-end": "for our JavaScript API and installation options.",
7674
"chrome-extension-alt": "Available in the Chrome Web Store",
7775
"firefox-extension-alt": "Get the Add-On for Firefox",
7876
"edge-extension-alt": "Get it from Microsoft for Edge"
79-
},
80-
"common": {
81-
"line-ender": "."
8277
}
8378
}

0 commit comments

Comments
 (0)