feat: initial implementation of translation component

This commit is contained in:
Lewis Crichton 2024-06-08 18:20:12 +01:00
parent 7ed73b49e5
commit 16549695d1
No known key found for this signature in database
4 changed files with 53 additions and 11 deletions

View file

@ -6,5 +6,10 @@ languageIds:
usageMatchRegex: usageMatchRegex:
- "[^\\w\\d]\\$t\\(['\"`]({key})['\"`]" - "[^\\w\\d]\\$t\\(['\"`]({key})['\"`]"
- "<Translate ?.* i18nKey=\\{?['\"`]({key})['\"`]"
refactorTemplates:
- "$t(\"$1\")"
- "<Translate i18nKey=\"$1\" />"
monopoly: true monopoly: true

View file

@ -12,8 +12,8 @@ import ErrorBoundary from "@components/ErrorBoundary";
import { Link } from "@components/Link"; import { Link } from "@components/Link";
import { DevsById } from "@utils/constants"; import { DevsById } from "@utils/constants";
import { fetchUserProfile, getTheme, Theme } from "@utils/discord"; import { fetchUserProfile, getTheme, Theme } from "@utils/discord";
import { pluralise } from "@utils/misc";
import { ModalContent, ModalRoot, openModal } from "@utils/modal"; import { ModalContent, ModalRoot, openModal } from "@utils/modal";
import { Translate } from "@utils/translation";
import { Forms, MaskedLink, showToast, Tooltip, useEffect, useMemo, UserProfileStore, useStateFromStores } from "@webpack/common"; import { Forms, MaskedLink, showToast, Tooltip, useEffect, useMemo, UserProfileStore, useStateFromStores } from "@webpack/common";
import { User } from "discord-types/general"; import { User } from "discord-types/general";
@ -108,15 +108,9 @@ function ContributorModal({ user }: { user: User; }) {
</div> </div>
</div> </div>
{plugins.length ? ( <Translate i18nKey="vencord.components.pluginSettings.contributorModal.contributed" variables={{ count: plugins.length }}>
<Forms.FormText> <Link href="https://vencord.dev/source" />
This person has {ContributedHyperLink} to {pluralise(plugins.length, "plugin")}! </Translate>
</Forms.FormText>
) : (
<Forms.FormText>
This person has not made any plugins. They likely {ContributedHyperLink} to Vencord in other ways!
</Forms.FormText>
)}
{!!plugins.length && ( {!!plugins.length && (
<div className={cl("plugins")}> <div className={cl("plugins")}>

View file

@ -5,7 +5,7 @@
*/ */
import { negotiateLanguages } from "@fluent/langneg"; import { negotiateLanguages } from "@fluent/langneg";
import { FluxDispatcher, i18n } from "@webpack/common"; import { FluxDispatcher, i18n, React } from "@webpack/common";
import translations from "~translations"; import translations from "~translations";
@ -124,3 +124,37 @@ export function $t(key: string, variables?: Record<string, any>): string {
return format(translation as string, variables); return format(translation as string, variables);
} }
interface TranslateProps {
/** The key to translate. */
i18nKey: string;
/** The variables to interpolate into the resultant string. If dealing with plurals, `count` must be set. */
variables?: Record<string, any>;
/** The component(s) to interpolate into the resultant string. */
children: JSX.Element | JSX.Element[];
}
/**
* A translation component. Follows the same rules as {@link $t}, but lets you add components to strings.
* @param param0 Component props.
*/
export function Translate({ i18nKey, variables, children: trueChildren }: TranslateProps): JSX.Element {
const children = [trueChildren].flat();
const translation = $t(i18nKey, variables);
const parts = translation.split(/(<\d+>.*?<\/\d+>)/g);
const finalChildren = parts.map((part, index) => {
const match = part.match(/<(\d+)>(.*?)<\/\d+>/);
if (match) {
const childIndex = parseInt(match[1], 10);
return React.cloneElement(children[childIndex], { key: index }, match[2]);
}
return part;
});
return <>{finalChildren}</>;
}

View file

@ -5,6 +5,15 @@
"error": "An error occurred while rendering this Component. More info can be found below and in your console.", "error": "An error occurred while rendering this Component. More info can be found below and in your console.",
"ohNo": "Oh no!" "ohNo": "Oh no!"
}, },
"pluginSettings": {
"contributorModal": {
"contributed": {
"zero": "This person has not made any plugins. They likely <0>contributed</0> to Vencord in other ways!",
"one": "This person has <0>contributed</0> to one plugin!",
"other": "This person has <0>contributed</0> to {count} plugins!"
}
}
},
"vencordSettings": { "vencordSettings": {
"addonCard": { "addonCard": {
"new": "NEW" "new": "NEW"