Skip to content

Commit

Permalink
wip(feat): add language selection on settings page
Browse files Browse the repository at this point in the history
  • Loading branch information
oleonardolima committed Feb 9, 2024
1 parent 28b48ae commit 2b57676
Show file tree
Hide file tree
Showing 11 changed files with 197 additions and 4 deletions.
101 changes: 101 additions & 0 deletions src/components/ChooseLanguage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { createForm } from "@modular-forms/solid";
import { useNavigate } from "@solidjs/router";
import { createSignal, For, Show } from "solid-js";

import { Button, ExternalLink, InfoBox, NiceP, VStack } from "~/components";
import { useI18n } from "~/i18n/context";
import { useMegaStore } from "~/state/megaStore";
import {
Language,
eify,
timeout,
LANGUAGE_OPTIONS,
EN_OPTION
} from "~/utils";

type ChooseLanguageForm = {
selectedLanguage: string;
};

const COMBINED_OPTIONS: Language[] = [...LANGUAGE_OPTIONS];

export function ChooseLanguage() {
const i18n = useI18n();
const [error, setError] = createSignal<Error>();
const [_state, actions] = useMegaStore();
const [loading, setLoading] = createSignal(false);
const navigate = useNavigate();

function findLanguageByValue(value: string) {
return (
COMBINED_OPTIONS.find((language) => language.value === value) ??
EN_OPTION
);
}

const [_chooseLanguageForm, { Form, Field }] =
createForm<ChooseLanguageForm>({
initialValues: {
selectedLanguage: ""
},
validate: (values) => {
const errors: Record<string, string> = {};
if (values.selectedLanguage === undefined) {
errors.selectedLanguage = i18n.t(
"settings.currency.error_unsupported_currency"
);
}
return errors;
}
});

const handleFormSubmit = async (f: ChooseLanguageForm) => {
setLoading(true);
try {
actions.saveLanguage(findLanguageByValue(f.selectedLanguage).label);

await timeout(1000);
navigate("/");
} catch (e) {
console.error(e);
setError(eify(e));
setLoading(false);
}
};

return (
<VStack>
<Form onSubmit={handleFormSubmit} class="flex flex-col gap-4">
<NiceP>{i18n.t("settings.language.caption")}</NiceP>
<ExternalLink href="https://github.com/MutinyWallet/mutiny-web/issues/new">
{i18n.t("settings.language.request_language_support_link")}
</ExternalLink>
<div />
<VStack>
<Field name="selectedLanguage">
{(field, props) => (
<select
{...props}
value={field.value}
class="w-full rounded-lg bg-m-grey-750 py-2 pl-4 pr-12 text-base font-normal text-white"
>
<For each={COMBINED_OPTIONS}>
{({ value, label }) => (
<option value={value}>{value}</option>
)}
</For>
</select>
)}
</Field>
<Show when={error()}>
<InfoBox accent="red">{error()?.message}</InfoBox>
</Show>
<div />
<Button intent="blue" loading={loading()}>
{i18n.t("settings.language.select_language")}
</Button>
</VStack>
</Form>
</VStack>
);
}
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export * from "./AmountEditable";
export * from "./BalanceBox";
export * from "./BetaWarningModal";
export * from "./ChooseCurrency";
export * from "./ChooseLanguage";
export * from "./ContactEditor";
export * from "./ContactForm";
export * from "./ContactViewer";
Expand Down
6 changes: 4 additions & 2 deletions src/i18n/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@ const i18n = use(LanguageDetector).init(
fallbackNS: false,
debug: true,
detection: {
order: ["querystring", "navigator", "htmlTag"],
lookupQuerystring: "lang"
order: ["localStorage", "querystring", "navigator", "htmlTag"],
lookupQuerystring: "lang",
lookupLocalStorage: "i18nextLng",
caches: ['localStorage'],
},
resources: resources
// FIXME: this doesn't work when deployed
Expand Down
12 changes: 12 additions & 0 deletions src/i18n/en/translations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,18 @@ export default {
"Request support for more currencies",
error_unsupported_currency: "Please Select a supported currency."
},
// TODO: (@leonardo) check which language fields would be really needed
language: {
title: "Language",
caption: "Choose your preferred language",
select_language: "Select Language",
select_language_label: "Language",
select_language_caption:
"Choosing a new currency will change the wallet language, ignoring current browser language",
request_language_support_link:
"Request support for more languages",
error_unsupported_language: "Please Select a supported language."
},
lnurl_auth: {
title: "LNURL Auth",
auth: "Auth",
Expand Down
2 changes: 2 additions & 0 deletions src/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
Channels,
Connections,
Currency,
Language,
EmergencyKit,
Encrypt,
Gift,
Expand Down Expand Up @@ -109,6 +110,7 @@ export function Router() {
<Route path="/channels" component={Channels} />
<Route path="/connections" component={Connections} />
<Route path="/currency" component={Currency} />
<Route path="/language" component={Language} />
<Route path="/emergencykit" component={EmergencyKit} />
<Route path="/encrypt" component={Encrypt} />
<Route path="/gift" component={Gift} />
Expand Down
35 changes: 35 additions & 0 deletions src/routes/settings/Language.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {
BackLink,
Card,
ChooseLanguage,
DefaultMain,
LargeHeader,
MutinyWalletGuard,
NavBar,
SafeArea
} from "~/components";
import { useI18n } from "~/i18n/context";

export function Language() {
const i18n = useI18n();
return (
<MutinyWalletGuard>
<SafeArea>
<DefaultMain>
<BackLink
href="/settings"
title={i18n.t("settings.header")}
/>
<LargeHeader>
{i18n.t("settings.language.title")}
</LargeHeader>
<Card title={i18n.t("settings.language.select_language")}>
<ChooseLanguage />
</Card>
<div class="h-full" />
</DefaultMain>
<NavBar activeTab="settings" />
</SafeArea>
</MutinyWalletGuard>
);
}
5 changes: 5 additions & 0 deletions src/routes/settings/Root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ export function Settings() {
text: i18n.t("settings.currency.title"),
caption: i18n.t("settings.currency.caption")
},
{
href: "/settings/language",
text: i18n.t("settings.language.title"),
caption: i18n.t("settings.language.caption")
},
{
href: "/settings/servers",
text: i18n.t("settings.servers.title"),
Expand Down
1 change: 1 addition & 0 deletions src/routes/settings/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export * from "./Backup";
export * from "./Channels";
export * from "./Connections";
export * from "./Currency";
export * from "./Language";
export * from "./EmergencyKit";
export * from "./Encrypt";
export * from "./Gift";
Expand Down
13 changes: 11 additions & 2 deletions src/state/megaStore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
BTC_OPTION,
Currency,
eify,
Language,
subscriptionValid,
USD_OPTION
} from "~/utils";
Expand All @@ -54,6 +55,7 @@ type MegaStore = [
price_sync_backoff_multiple?: number;
price: number;
fiat: Currency;
lang?: string;
has_backed_up: boolean;
wallet_loading: boolean;
setup_error?: Error;
Expand Down Expand Up @@ -83,6 +85,7 @@ type MegaStore = [
checkForSubscription(justPaid?: boolean): Promise<void>;
fetchPrice(fiat: Currency): Promise<number>;
saveFiat(fiat: Currency): void;
saveLanguage(lang: string): void;
saveNpub(npub: string): void;
setPreferredInvoiceType(
type: "unified" | "lightning" | "onchain"
Expand Down Expand Up @@ -132,6 +135,7 @@ export const Provider: ParentComponent = (props) => {
load_stage: "fresh" as LoadStage,
settings: undefined as MutinyWalletSettingStrings | undefined,
safe_mode: searchParams.safe_mode === "true",
lang: localStorage.getItem("lang") || undefined,
npub: localStorage.getItem("npub") || undefined,
preferredInvoiceType: "unified" as "unified" | "lightning" | "onchain",
betaWarned: localStorage.getItem("betaWarned") === "true",
Expand Down Expand Up @@ -332,6 +336,11 @@ export const Provider: ParentComponent = (props) => {
fiat: fiat
});
},
saveLanguage(lang: string) {
localStorage.setItem("i18nextLng", lang);
setState({ lang });
window.location.reload();
},
saveNpub(npub: string) {
localStorage.setItem("npub", npub);
setState({ npub });
Expand Down Expand Up @@ -386,7 +395,7 @@ export const Provider: ParentComponent = (props) => {
if (result.value?.fedimint_invite) {
navigate(
"/settings/federations?fedimint_invite=" +
encodeURIComponent(result.value?.fedimint_invite)
encodeURIComponent(result.value?.fedimint_invite)
);
actions.setScanResult(undefined);
}
Expand All @@ -397,7 +406,7 @@ export const Provider: ParentComponent = (props) => {
);
navigate(
"/settings/connections/?nwa=" +
encodeURIComponent(result.value?.nostr_wallet_auth)
encodeURIComponent(result.value?.nostr_wallet_auth)
);
}
}
Expand Down
1 change: 1 addition & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export * from "./vibrate";
export * from "./openLinkProgrammatically";
export * from "./nostr";
export * from "./currencies";
export * from "./languages";
export * from "./bech32";
export * from "./keypad";
export * from "./debounce";
24 changes: 24 additions & 0 deletions src/utils/languages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export interface Language {
value: string;
label: string;
hasSymbol?: string;
}

export const EN_OPTION: Language = {
value: "English",
label: "en",
hasSymbol: "EN"
};


export const LANGUAGE_OPTIONS: Language[] = [
{
value: "Português",
label: "pt",
hasSymbol: "PT",
}, {
value: "Korean",
label: "ko",
hasSymbol: "KO",
}
];

0 comments on commit 2b57676

Please sign in to comment.