266 lines
7.4 KiB
TypeScript
266 lines
7.4 KiB
TypeScript
import { For, createMemo } from "solid-js";
|
|
|
|
import { Trans, useLingui } from "@lingui-solid/solid/macro";
|
|
|
|
import { Language, Languages, browserPreferredLanguage } from "@revolt/i18n";
|
|
import type { LanguageEntry } from "@revolt/i18n/Languages";
|
|
import { timeLocale } from "@revolt/i18n/dayjs";
|
|
import { UnicodeEmoji } from "@revolt/markdown/emoji";
|
|
import { useState } from "@revolt/state";
|
|
import {
|
|
CategoryButton,
|
|
CategoryButtonGroup,
|
|
CategoryCollapse,
|
|
Checkbox,
|
|
Column,
|
|
Row,
|
|
Time,
|
|
iconSize,
|
|
} from "@revolt/ui";
|
|
|
|
import MdErrorFill from "@material-design-icons/svg/filled/error.svg?component-solid";
|
|
import MdVerifiedFill from "@material-design-icons/svg/filled/verified.svg?component-solid";
|
|
import MdCalendarMonth from "@material-design-icons/svg/outlined/calendar_month.svg?component-solid";
|
|
import MdLanguage from "@material-design-icons/svg/outlined/language.svg?component-solid";
|
|
import MdSchedule from "@material-design-icons/svg/outlined/schedule.svg?component-solid";
|
|
import MdTranslate from "@material-design-icons/svg/outlined/translate.svg?component-solid";
|
|
|
|
/**
|
|
* Language
|
|
*/
|
|
export function LanguageSettings() {
|
|
return (
|
|
<Column gap="lg">
|
|
<CategoryButtonGroup>
|
|
<PickLanguage />
|
|
{/* <ConfigureRTL /> */}
|
|
</CategoryButtonGroup>
|
|
<CategoryButtonGroup>
|
|
<PickDateFormat />
|
|
<PickTimeFormat />
|
|
</CategoryButtonGroup>
|
|
<CategoryButtonGroup>
|
|
<ContributeLanguageLink />
|
|
</CategoryButtonGroup>
|
|
</Column>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Pick user's preferred language
|
|
*/
|
|
function PickLanguage() {
|
|
const state = useState();
|
|
const { i18n } = useLingui();
|
|
|
|
/**
|
|
* Determine the current language
|
|
*/
|
|
const currentLanguage = () =>
|
|
Languages[i18n().locale as never] as LanguageEntry;
|
|
|
|
// Generate languages array.
|
|
const languages = createMemo(() => {
|
|
const languages = Object.keys(Languages).map(
|
|
(x) => [x, Languages[x as keyof typeof Languages]] as const,
|
|
);
|
|
|
|
const preferredLanguage = browserPreferredLanguage();
|
|
|
|
if (preferredLanguage) {
|
|
// This moves the user's system language to the top of the language list
|
|
const prefLangKey = languages.find(
|
|
(lang) => lang[0].replace(/_/g, "-") == preferredLanguage,
|
|
);
|
|
|
|
if (prefLangKey) {
|
|
languages.splice(
|
|
0,
|
|
0,
|
|
languages.splice(languages.indexOf(prefLangKey), 1)[0],
|
|
);
|
|
}
|
|
}
|
|
|
|
return languages;
|
|
});
|
|
|
|
return (
|
|
<CategoryCollapse
|
|
icon={<MdLanguage {...iconSize(22)} />}
|
|
title={<Trans>Select your language</Trans>}
|
|
description={currentLanguage().display}
|
|
scrollable
|
|
>
|
|
<For each={languages()}>
|
|
{([id, lang]) => (
|
|
<CategoryButton
|
|
icon={<UnicodeEmoji emoji={lang.emoji} />}
|
|
action={<Checkbox checked={id === i18n().locale} />}
|
|
onClick={() => state.locale.switch(id as Language)}
|
|
>
|
|
<Row>
|
|
{lang.display}{" "}
|
|
{lang.verified && (
|
|
<MdVerifiedFill
|
|
{...iconSize(18)}
|
|
fill="var(--md-sys-color-on-surface)"
|
|
/>
|
|
)}{" "}
|
|
{lang.incomplete && (
|
|
<MdErrorFill
|
|
{...iconSize(18)}
|
|
fill="var(--md-sys-color-on-surface)"
|
|
/>
|
|
)}
|
|
</Row>
|
|
</CategoryButton>
|
|
)}
|
|
</For>
|
|
</CategoryCollapse>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Pick user's preferred date format
|
|
*/
|
|
function PickDateFormat() {
|
|
const state = useState();
|
|
const { t } = useLingui();
|
|
const date = () => timeLocale()[1].formats.L;
|
|
|
|
const LastWeek = new Date();
|
|
LastWeek.setDate(LastWeek.getDate() - 7);
|
|
|
|
return (
|
|
<CategoryCollapse
|
|
icon={<MdCalendarMonth {...iconSize(22)} />}
|
|
title="Select date format"
|
|
description={
|
|
date() === "DD/MM/YYYY"
|
|
? t`Traditional (DD/MM/YYYY)`
|
|
: date() === "MM/DD/YYYY"
|
|
? t`American (MM/DD/YYYY)`
|
|
: date() === "YYYY-MM-DD"
|
|
? t`ISO Standard (YYYY-MM-DD)`
|
|
: date()
|
|
}
|
|
>
|
|
<CategoryButton
|
|
icon={"blank"}
|
|
onClick={() => state.locale.setDateFormat("DD/MM/YYYY")}
|
|
action={<Checkbox checked={date() === "DD/MM/YYYY"} />}
|
|
description={<Time format="date" value={LastWeek} />}
|
|
>
|
|
<Trans>Traditional (DD/MM/YYYY)</Trans>
|
|
</CategoryButton>
|
|
<CategoryButton
|
|
icon={"blank"}
|
|
onClick={() => state.locale.setDateFormat("MM/DD/YYYY")}
|
|
action={<Checkbox checked={date() === "MM/DD/YYYY"} />}
|
|
description={<Time format="dateAmerican" value={LastWeek} />}
|
|
>
|
|
<Trans>American (MM/DD/YYYY)</Trans>
|
|
</CategoryButton>
|
|
<CategoryButton
|
|
icon={"blank"}
|
|
onClick={() => state.locale.setDateFormat("YYYY-MM-DD")}
|
|
action={<Checkbox checked={date() === "YYYY-MM-DD"} />}
|
|
description={<Time format="iso8601" value={LastWeek} />}
|
|
>
|
|
<Trans>ISO Standard (YYYY-MM-DD)</Trans>
|
|
</CategoryButton>
|
|
</CategoryCollapse>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Pick user's preferred time format
|
|
*/
|
|
function PickTimeFormat() {
|
|
const state = useState();
|
|
const { t } = useLingui();
|
|
const time = () => timeLocale()[1].formats.LT;
|
|
|
|
return (
|
|
<CategoryCollapse
|
|
icon={<MdSchedule {...iconSize(22)} />}
|
|
title="Select time format"
|
|
description={time() === "HH:mm" ? t`24 hours` : t`12 hours`}
|
|
>
|
|
<CategoryButton
|
|
icon={"blank"}
|
|
onClick={() => state.locale.setTimeFormat("HH:mm")}
|
|
action={<Checkbox checked={time() === "HH:mm"} />}
|
|
description={<Time format="time24" value={new Date()} />}
|
|
>
|
|
<Trans>24 hours</Trans>
|
|
</CategoryButton>
|
|
<CategoryButton
|
|
icon={"blank"}
|
|
onClick={() => state.locale.setTimeFormat("h:mm A")}
|
|
action={<Checkbox checked={time() === "h:mm A"} />}
|
|
description={<Time format="time12" value={new Date()} />}
|
|
>
|
|
<Trans>12 hours</Trans>
|
|
</CategoryButton>
|
|
</CategoryCollapse>
|
|
);
|
|
}
|
|
|
|
// /**
|
|
// * Configure right-to-left display
|
|
// */
|
|
// function ConfigureRTL() {
|
|
// /**
|
|
// * Determine the current language
|
|
// */
|
|
// const currentLanguage = () => Languages[language()];
|
|
|
|
// return (
|
|
// <Switch
|
|
// fallback={
|
|
// <CategoryButton
|
|
// icon={<MdKeyboardTabRtl {...iconSize(22)} />}
|
|
// description={<Trans>Flip the user interface right to left</Trans>}
|
|
// action={<Checkbox />}
|
|
// onClick={() => void 0}
|
|
// >
|
|
// <Trans>Enable RTL layout</Trans>
|
|
// </CategoryButton>
|
|
// }
|
|
// >
|
|
// <Match when={currentLanguage().rtl}>
|
|
// <CategoryButton
|
|
// icon={<MdKeyboardTab {...iconSize(22)} />}
|
|
// description={<Trans>Keep the user interface left to right</Trans>}
|
|
// action={<Checkbox />}
|
|
// onClick={() => void 0}
|
|
// >
|
|
// <Trans>Force LTR layout</Trans>
|
|
// </CategoryButton>
|
|
// </Match>
|
|
// </Switch>
|
|
// );
|
|
// }
|
|
|
|
/**
|
|
* Language contribution link
|
|
*/
|
|
function ContributeLanguageLink() {
|
|
return (
|
|
<a href="https://weblate.insrt.uk/engage/revolt/" target="_blank">
|
|
<CategoryButton
|
|
action="external"
|
|
icon={<MdTranslate {...iconSize(22)} />}
|
|
onClick={() => void 0}
|
|
description={
|
|
<Trans>Help contribute to an existing or new language</Trans>
|
|
}
|
|
>
|
|
<Trans>Contribute a language</Trans>
|
|
</CategoryButton>
|
|
</a>
|
|
);
|
|
}
|