i18n
This commit is contained in:
parent
e70e664da9
commit
44551245da
@ -45,7 +45,7 @@ function toI18nString(stringSeq: ReadonlyArray<string>): string {
|
|||||||
/**
|
/**
|
||||||
* Internationalize a string template with arbitrary serialized values.
|
* Internationalize a string template with arbitrary serialized values.
|
||||||
*/
|
*/
|
||||||
export function str(stringSeq: TemplateStringsArray, ...values: any[]): string {
|
export function singular(stringSeq: TemplateStringsArray, ...values: any[]): string {
|
||||||
const s = toI18nString(stringSeq);
|
const s = toI18nString(stringSeq);
|
||||||
const tr = jed
|
const tr = jed
|
||||||
.translate(s)
|
.translate(s)
|
||||||
@ -141,7 +141,9 @@ function stringifyArray(children: Array<any>): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const i18n = {
|
export const i18n = {
|
||||||
str,
|
str: singular,
|
||||||
|
singular,
|
||||||
Translate,
|
Translate,
|
||||||
translate,
|
translate,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -14,15 +14,9 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { setupI18n } from "@gnu-taler/taler-util"
|
|
||||||
import { Fragment } from "preact"
|
import { Fragment } from "preact"
|
||||||
import { strings } from '../src/i18n/strings.ts'
|
|
||||||
import { NavBar } from '../src/popup/popup'
|
import { NavBar } from '../src/popup/popup'
|
||||||
|
import { TranslationProvider } from '../src/context/translation'
|
||||||
const mockConfig = {
|
|
||||||
backendURL: 'http://demo.taler.net',
|
|
||||||
currency: 'KUDOS'
|
|
||||||
}
|
|
||||||
|
|
||||||
export const parameters = {
|
export const parameters = {
|
||||||
controls: { expanded: true },
|
controls: { expanded: true },
|
||||||
@ -38,7 +32,7 @@ export const globalTypes = {
|
|||||||
icon: 'globe',
|
icon: 'globe',
|
||||||
items: [
|
items: [
|
||||||
{ value: 'en', right: '🇺🇸', title: 'English' },
|
{ value: 'en', right: '🇺🇸', title: 'English' },
|
||||||
{ value: 'es', right: '🇪🇸', title: 'Spanish' },
|
{ value: 'de', right: '🇪🇸', title: 'German' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -58,7 +52,7 @@ export const decorators = [
|
|||||||
<Story />
|
<Story />
|
||||||
</div>
|
</div>
|
||||||
} else {
|
} else {
|
||||||
const path = !isTestingHeader ? /popup(\/.*)\/.*/.exec(kind)[1] : ''
|
const path = !isTestingHeader ? /popup(\/.*).*/.exec(kind)[1] : ''
|
||||||
// add a fake header so it looks similar
|
// add a fake header so it looks similar
|
||||||
return <Fragment>
|
return <Fragment>
|
||||||
<NavBar path={path} devMode={path === '/dev'} />
|
<NavBar path={path} devMode={path === '/dev'} />
|
||||||
@ -113,9 +107,7 @@ export const decorators = [
|
|||||||
<Story />
|
<Story />
|
||||||
</div>
|
</div>
|
||||||
},
|
},
|
||||||
(Story, { globals }) => {
|
(Story, { globals }) => <TranslationProvider initial='en' forceLang={globals.locale}>
|
||||||
setupI18n(globals.locale, strings);
|
<Story />
|
||||||
return <Story />
|
</TranslationProvider>,
|
||||||
},
|
|
||||||
// (Story) => <ConfigContextProvider value={mockConfig}> <Story /> </ConfigContextProvider>
|
|
||||||
];
|
];
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# This file is in the public domain.
|
# This file is in the public domain.
|
||||||
[ "also-wallet" == "$1" ] && { pnpm -C ../taler-wallet-core/ compile || exit 1; }
|
[ "also-wallet" == "$1" ] && { pnpm -C ../taler-wallet-core/ compile || exit 1; }
|
||||||
|
[ "also-util" == "$1" ] && { pnpm -C ../taler-util/ prepare || exit 1; }
|
||||||
pnpm clean && pnpm compile && rm -rf extension/ && ./pack.sh && (cd extension/ && unzip taler*.zip)
|
pnpm clean && pnpm compile && rm -rf extension/ && ./pack.sh && (cd extension/ && unzip taler*.zip)
|
||||||
|
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
This file is part of GNU Taler
|
||||||
|
(C) 2019 Taler Systems SA
|
||||||
|
|
||||||
|
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||||
|
terms of the GNU General Public License as published by the Free Software
|
||||||
|
Foundation; either version 3, or (at your option) any later version.
|
||||||
|
|
||||||
|
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { VNode } from "preact";
|
||||||
|
import { useRef, useState } from "preact/hooks";
|
||||||
|
import { JSX } from "preact/jsx-runtime";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
value: string;
|
||||||
|
onChange: (s: string) => void;
|
||||||
|
label: string;
|
||||||
|
list: {
|
||||||
|
[label: string]: string
|
||||||
|
}
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SelectList({ name, value, list, onChange, label, description }: Props): JSX.Element {
|
||||||
|
return <select name={name} id="slct">
|
||||||
|
<option selected disabled>Choose an option</option>
|
||||||
|
{Object.keys(list)
|
||||||
|
.filter((l) => l !== value)
|
||||||
|
.map(key => <option value={key} key={key}>{list[key]}</option> )
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
This file is part of GNU Taler
|
||||||
|
(C) 2021 Taler Systems S.A.
|
||||||
|
|
||||||
|
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||||
|
terms of the GNU General Public License as published by the Free Software
|
||||||
|
Foundation; either version 3, or (at your option) any later version.
|
||||||
|
|
||||||
|
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Sebastian Javier Marchano (sebasjm)
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { createContext, h, VNode } from 'preact'
|
||||||
|
import { useContext, useEffect } from 'preact/hooks'
|
||||||
|
import { useLang } from '../hooks/useLang'
|
||||||
|
//@ts-ignore: type declaration
|
||||||
|
import * as jedLib from "jed";
|
||||||
|
import { strings } from "../i18n/strings";
|
||||||
|
import { setupI18n } from '@gnu-taler/taler-util';
|
||||||
|
|
||||||
|
interface Type {
|
||||||
|
lang: string;
|
||||||
|
changeLanguage: (l: string) => void;
|
||||||
|
}
|
||||||
|
const initial = {
|
||||||
|
lang: 'en',
|
||||||
|
changeLanguage: () => {
|
||||||
|
// do not change anything
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const Context = createContext<Type>(initial)
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
initial?: string,
|
||||||
|
children: any,
|
||||||
|
forceLang?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
//we use forceLang when we don't want to use the saved state, but sone forced
|
||||||
|
//runtime lang predefined lang
|
||||||
|
export const TranslationProvider = ({ initial, children, forceLang }: Props): VNode => {
|
||||||
|
const [lang, changeLanguage] = useLang(initial)
|
||||||
|
useEffect(() => {
|
||||||
|
if (forceLang) {
|
||||||
|
changeLanguage(forceLang)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
useEffect(()=> {
|
||||||
|
setupI18n(lang, strings)
|
||||||
|
},[lang])
|
||||||
|
if (forceLang) {
|
||||||
|
setupI18n(forceLang, strings)
|
||||||
|
} else {
|
||||||
|
setupI18n(lang, strings)
|
||||||
|
}
|
||||||
|
return h(Context.Provider, { value: { lang, changeLanguage }, children });
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useTranslationContext = (): Type => useContext(Context);
|
7
packages/taler-wallet-webextension/src/hooks/useLang.ts
Normal file
7
packages/taler-wallet-webextension/src/hooks/useLang.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { useNotNullLocalStorage } from './useLocalStorage';
|
||||||
|
|
||||||
|
export function useLang(initial?: string): [string, (s:string) => void] {
|
||||||
|
const browserLang: string | undefined = typeof window !== "undefined" ? navigator.language || (navigator as any).userLanguage : undefined;
|
||||||
|
const defaultLang = (browserLang || initial || 'en').substring(0, 2)
|
||||||
|
return useNotNullLocalStorage('lang-preference', defaultLang)
|
||||||
|
}
|
@ -42,3 +42,24 @@ export function useLocalStorage(key: string, initialValue?: string): [string | u
|
|||||||
|
|
||||||
return [storedValue, setValue];
|
return [storedValue, setValue];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: merge with the above function
|
||||||
|
export function useNotNullLocalStorage(key: string, initialValue: string): [string, StateUpdater<string>] {
|
||||||
|
const [storedValue, setStoredValue] = useState<string>((): string => {
|
||||||
|
return typeof window !== "undefined" ? window.localStorage.getItem(key) || initialValue : initialValue;
|
||||||
|
});
|
||||||
|
|
||||||
|
const setValue = (value: string | ((val: string) => string)) => {
|
||||||
|
const valueToStore = value instanceof Function ? value(storedValue) : value;
|
||||||
|
setStoredValue(valueToStore);
|
||||||
|
if (typeof window !== "undefined") {
|
||||||
|
if (!valueToStore) {
|
||||||
|
window.localStorage.removeItem(key)
|
||||||
|
} else {
|
||||||
|
window.localStorage.setItem(key, valueToStore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return [storedValue, setValue];
|
||||||
|
}
|
||||||
|
@ -159,6 +159,76 @@ strings["en-US"] = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
strings["es"] = {
|
||||||
|
domain: "messages",
|
||||||
|
locale_data: {
|
||||||
|
messages: {
|
||||||
|
"": {
|
||||||
|
domain: "messages",
|
||||||
|
plural_forms: "nplurals=2; plural=(n != 1);",
|
||||||
|
lang: "",
|
||||||
|
},
|
||||||
|
"Invalid Wire": [""],
|
||||||
|
"Invalid Test Wire Detail": [""],
|
||||||
|
"Test Wire Acct #%1$s on %2$s": [""],
|
||||||
|
"Unknown Wire Detail": [""],
|
||||||
|
Operation: [""],
|
||||||
|
"time (ms/op)": [""],
|
||||||
|
"The merchant %1$s offers you to purchase:": [""],
|
||||||
|
"The total price is %1$s (plus %2$s fees).": [""],
|
||||||
|
"The total price is %1$s.": [""],
|
||||||
|
Retry: [""],
|
||||||
|
"Confirm payment": [""],
|
||||||
|
Balance: [""],
|
||||||
|
History: ["Historial"],
|
||||||
|
Debug: [""],
|
||||||
|
"You have no balance to show. Need some %1$s getting started?": [""],
|
||||||
|
"%1$s incoming": [""],
|
||||||
|
"%1$s being spent": [""],
|
||||||
|
"Error: could not retrieve balance information.": [""],
|
||||||
|
"Invalid ": [""],
|
||||||
|
"Fees ": [""],
|
||||||
|
"Refresh sessions has completed": [""],
|
||||||
|
"Order Refused": [""],
|
||||||
|
"Order redirected": [""],
|
||||||
|
"Payment aborted": [""],
|
||||||
|
"Payment Sent": [""],
|
||||||
|
"Backup": ["Resguardo"],
|
||||||
|
"Order accepted": [""],
|
||||||
|
"Reserve balance updated": [""],
|
||||||
|
"Payment refund": [""],
|
||||||
|
Withdrawn: [""],
|
||||||
|
"Tip Accepted": [""],
|
||||||
|
"Tip Declined": [""],
|
||||||
|
"%1$s": [""],
|
||||||
|
"Your wallet has no events recorded.": [""],
|
||||||
|
"Wire to bank account": [""],
|
||||||
|
Confirm: ["Confirmar"],
|
||||||
|
Cancel: ["Cancelar"],
|
||||||
|
"Could not get details for withdraw operation:": [""],
|
||||||
|
"Chose different exchange provider": [""],
|
||||||
|
"Please select an exchange. You can review the details before after your selection.": [
|
||||||
|
"",
|
||||||
|
],
|
||||||
|
"Select %1$s": [""],
|
||||||
|
"Select custom exchange": [""],
|
||||||
|
"You are about to withdraw %1$s from your bank account into your wallet.": [
|
||||||
|
"",
|
||||||
|
],
|
||||||
|
"Accept fees and withdraw": [""],
|
||||||
|
"Cancel withdraw operation": [""],
|
||||||
|
"Withdrawal fees:": [""],
|
||||||
|
"Rounding loss:": [""],
|
||||||
|
"Earliest expiration (for deposit): %1$s": [""],
|
||||||
|
"# Coins": [""],
|
||||||
|
Value: [""],
|
||||||
|
"Withdraw Fee": [""],
|
||||||
|
"Refresh Fee": [""],
|
||||||
|
"Deposit Fee": [""],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
strings["fr"] = {
|
strings["fr"] = {
|
||||||
domain: "messages",
|
domain: "messages",
|
||||||
locale_data: {
|
locale_data: {
|
||||||
|
@ -31,7 +31,7 @@ interface Props {
|
|||||||
export function ProviderDetailPage({ pid, onBack }: Props): VNode {
|
export function ProviderDetailPage({ pid, onBack }: Props): VNode {
|
||||||
const status = useProviderStatus(pid)
|
const status = useProviderStatus(pid)
|
||||||
if (!status) {
|
if (!status) {
|
||||||
return <div>Loading...</div>
|
return <div><i18n.Translate>Loading...</i18n.Translate></div>
|
||||||
}
|
}
|
||||||
if (!status.info) {
|
if (!status.info) {
|
||||||
onBack()
|
onBack()
|
||||||
@ -67,26 +67,26 @@ export function ProviderView({ info, onDelete, onSync, onBack, onExtend }: ViewP
|
|||||||
<p>{daysSince(info?.lastSuccessfulBackupTimestamp)} </p>
|
<p>{daysSince(info?.lastSuccessfulBackupTimestamp)} </p>
|
||||||
<p>{descriptionByStatus(info.paymentStatus)}</p>
|
<p>{descriptionByStatus(info.paymentStatus)}</p>
|
||||||
{info.paymentStatus.type === ProviderPaymentType.TermsChanged && <div>
|
{info.paymentStatus.type === ProviderPaymentType.TermsChanged && <div>
|
||||||
<p>terms has changed, extending the service will imply accepting the new terms of service</p>
|
<p><i18n.Translate>terms has changed, extending the service will imply accepting the new terms of service</i18n.Translate></p>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td>old</td>
|
<td><i18n.Translate>old</i18n.Translate></td>
|
||||||
<td> -></td>
|
<td> -></td>
|
||||||
<td>new</td>
|
<td><i18n.Translate>new</i18n.Translate></td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>fee</td>
|
<td><i18n.Translate>fee</i18n.Translate></td>
|
||||||
<td>{info.paymentStatus.oldTerms.annualFee}</td>
|
<td>{info.paymentStatus.oldTerms.annualFee}</td>
|
||||||
<td>-></td>
|
<td>-></td>
|
||||||
<td>{info.paymentStatus.newTerms.annualFee}</td>
|
<td>{info.paymentStatus.newTerms.annualFee}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>storage</td>
|
<td><i18n.Translate>storage</i18n.Translate></td>
|
||||||
<td>{info.paymentStatus.oldTerms.storageLimitInMegabytes}</td>
|
<td>{info.paymentStatus.oldTerms.storageLimitInMegabytes}</td>
|
||||||
<td>-></td>
|
<td>-></td>
|
||||||
<td>{info.paymentStatus.newTerms.storageLimitInMegabytes}</td>
|
<td>{info.paymentStatus.newTerms.storageLimitInMegabytes}</td>
|
||||||
@ -117,11 +117,11 @@ function daysSince(d?: Timestamp) {
|
|||||||
const str = formatDuration(duration, {
|
const str = formatDuration(duration, {
|
||||||
delimiter: ', ',
|
delimiter: ', ',
|
||||||
format: [
|
format: [
|
||||||
duration?.years ? 'years' : (
|
duration?.years ? i18n.str`years` : (
|
||||||
duration?.months ? 'months' : (
|
duration?.months ? i18n.str`months` : (
|
||||||
duration?.days ? 'days' : (
|
duration?.days ? i18n.str`days` : (
|
||||||
duration?.hours ? 'hours' : (
|
duration?.hours ? i18n.str`hours` : (
|
||||||
duration?.minutes ? 'minutes' : 'seconds'
|
duration?.minutes ? i18n.str`minutes` : i18n.str`seconds`
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -139,13 +139,13 @@ function Error({ info }: { info: ProviderInfo }) {
|
|||||||
switch (info.backupProblem.type) {
|
switch (info.backupProblem.type) {
|
||||||
case "backup-conflicting-device":
|
case "backup-conflicting-device":
|
||||||
return <ErrorMessage title={<Fragment>
|
return <ErrorMessage title={<Fragment>
|
||||||
There is conflict with another backup from <b>{info.backupProblem.otherDeviceId}</b>
|
<i18n.Translate>There is conflict with another backup from <b>{info.backupProblem.otherDeviceId}</b></i18n.Translate>
|
||||||
</Fragment>} />
|
</Fragment>} />
|
||||||
case "backup-unreadable":
|
case "backup-unreadable":
|
||||||
return <ErrorMessage title="Backup is not readable" />
|
return <ErrorMessage title="Backup is not readable" />
|
||||||
default:
|
default:
|
||||||
return <ErrorMessage title={<Fragment>
|
return <ErrorMessage title={<Fragment>
|
||||||
Unknown backup problem: {JSON.stringify(info.backupProblem)}
|
<i18n.Translate>Unknown backup problem: {JSON.stringify(info.backupProblem)}</i18n.Translate>
|
||||||
</Fragment>} />
|
</Fragment>} />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -172,15 +172,15 @@ function colorByStatus(status: ProviderPaymentType) {
|
|||||||
function descriptionByStatus(status: ProviderPaymentStatus) {
|
function descriptionByStatus(status: ProviderPaymentStatus) {
|
||||||
switch (status.type) {
|
switch (status.type) {
|
||||||
case ProviderPaymentType.InsufficientBalance:
|
case ProviderPaymentType.InsufficientBalance:
|
||||||
return 'no enough balance to make the payment'
|
return i18n.str`no enough balance to make the payment`
|
||||||
case ProviderPaymentType.Unpaid:
|
case ProviderPaymentType.Unpaid:
|
||||||
return 'not paid yet'
|
return i18n.str`not paid yet`
|
||||||
case ProviderPaymentType.Paid:
|
case ProviderPaymentType.Paid:
|
||||||
case ProviderPaymentType.TermsChanged:
|
case ProviderPaymentType.TermsChanged:
|
||||||
if (status.paidUntil.t_ms === 'never') {
|
if (status.paidUntil.t_ms === 'never') {
|
||||||
return 'service paid.'
|
return i18n.str`service paid`
|
||||||
} else {
|
} else {
|
||||||
return `service paid until ${format(status.paidUntil.t_ms, 'yyyy/MM/dd HH:mm:ss')}`
|
return i18n.str`service paid until ${format(status.paidUntil.t_ms, 'yyyy/MM/dd HH:mm:ss')}`
|
||||||
}
|
}
|
||||||
case ProviderPaymentType.Pending:
|
case ProviderPaymentType.Pending:
|
||||||
return ''
|
return ''
|
||||||
|
@ -15,18 +15,23 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
import { i18n } from "@gnu-taler/taler-util";
|
||||||
import { VNode } from "preact";
|
import { VNode } from "preact";
|
||||||
import { Checkbox } from "../components/Checkbox";
|
import { Checkbox } from "../components/Checkbox";
|
||||||
import { EditableText } from "../components/EditableText";
|
import { EditableText } from "../components/EditableText";
|
||||||
import { useDevContext } from "../context/useDevContext";
|
import { SelectList } from "../components/SelectList";
|
||||||
|
import { useDevContext } from "../context/devContext";
|
||||||
import { useBackupDeviceName } from "../hooks/useBackupDeviceName";
|
import { useBackupDeviceName } from "../hooks/useBackupDeviceName";
|
||||||
import { useExtendedPermissions } from "../hooks/useExtendedPermissions";
|
import { useExtendedPermissions } from "../hooks/useExtendedPermissions";
|
||||||
|
import { useLang } from "../hooks/useLang";
|
||||||
|
|
||||||
export function SettingsPage(): VNode {
|
export function SettingsPage(): VNode {
|
||||||
const [permissionsEnabled, togglePermissions] = useExtendedPermissions();
|
const [permissionsEnabled, togglePermissions] = useExtendedPermissions();
|
||||||
const { devMode, toggleDevMode } = useDevContext()
|
const { devMode, toggleDevMode } = useDevContext()
|
||||||
const { name, update } = useBackupDeviceName()
|
const { name, update } = useBackupDeviceName()
|
||||||
|
const [lang, changeLang] = useLang()
|
||||||
return <SettingsView
|
return <SettingsView
|
||||||
|
lang={lang} changeLang={changeLang}
|
||||||
deviceName={name} setDeviceName={update}
|
deviceName={name} setDeviceName={update}
|
||||||
permissionsEnabled={permissionsEnabled} togglePermissions={togglePermissions}
|
permissionsEnabled={permissionsEnabled} togglePermissions={togglePermissions}
|
||||||
developerMode={devMode} toggleDeveloperMode={toggleDevMode}
|
developerMode={devMode} toggleDeveloperMode={toggleDevMode}
|
||||||
@ -34,6 +39,8 @@ export function SettingsPage(): VNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ViewProps {
|
export interface ViewProps {
|
||||||
|
lang: string;
|
||||||
|
changeLang: (s: string) => void;
|
||||||
deviceName: string;
|
deviceName: string;
|
||||||
setDeviceName: (s: string) => Promise<void>;
|
setDeviceName: (s: string) => Promise<void>;
|
||||||
permissionsEnabled: boolean;
|
permissionsEnabled: boolean;
|
||||||
@ -42,20 +49,43 @@ export interface ViewProps {
|
|||||||
toggleDeveloperMode: () => void;
|
toggleDeveloperMode: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SettingsView({ deviceName, setDeviceName, permissionsEnabled, togglePermissions, developerMode, toggleDeveloperMode }: ViewProps): VNode {
|
import { strings as messages } from '../i18n/strings'
|
||||||
|
|
||||||
|
type LangsNames = {
|
||||||
|
[P in keyof typeof messages]: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const names: LangsNames = {
|
||||||
|
es: 'Español [es]',
|
||||||
|
en: 'English [en]',
|
||||||
|
fr: 'Français [fr]',
|
||||||
|
de: 'Deutsch [de]',
|
||||||
|
sv: 'Svenska [sv]',
|
||||||
|
it: 'Italiano [it]',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function SettingsView({ lang, changeLang, deviceName, setDeviceName, permissionsEnabled, togglePermissions, developerMode, toggleDeveloperMode }: ViewProps): VNode {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<section style={{ height: 'calc(320px - 34px - 16px)', overflow: 'auto' }}>
|
<section style={{ height: 'calc(320px - 34px - 16px)', overflow: 'auto' }}>
|
||||||
|
<h2><i18n.Translate>Wallet</i18n.Translate></h2>
|
||||||
<h2>Wallet</h2>
|
<SelectList
|
||||||
|
value={lang}
|
||||||
|
onChange={changeLang}
|
||||||
|
name="lang"
|
||||||
|
list={names}
|
||||||
|
label={i18n.str`Lang`}
|
||||||
|
description="(Choose your preferred lang)"
|
||||||
|
/>
|
||||||
<EditableText
|
<EditableText
|
||||||
value={deviceName}
|
value={deviceName}
|
||||||
onChange={setDeviceName}
|
onChange={setDeviceName}
|
||||||
name="device-id"
|
name="device-id"
|
||||||
label="Device name"
|
label={i18n.str`Device name`}
|
||||||
description="(This is how you will recognize the wallet in the backup provider)"
|
description="(This is how you will recognize the wallet in the backup provider)"
|
||||||
/>
|
/>
|
||||||
<h2>Permissions</h2>
|
<h2><i18n.Translate>Permissions</i18n.Translate></h2>
|
||||||
<Checkbox label="Automatically open wallet based on page content"
|
<Checkbox label="Automatically open wallet based on page content"
|
||||||
name="perm"
|
name="perm"
|
||||||
description="(Enabling this option below will make using the wallet faster, but requires more permissions from your browser.)"
|
description="(Enabling this option below will make using the wallet faster, but requires more permissions from your browser.)"
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
import { i18n } from "@gnu-taler/taler-util";
|
import { i18n } from "@gnu-taler/taler-util";
|
||||||
import { ComponentChildren, JSX } from "preact";
|
import { ComponentChildren, JSX } from "preact";
|
||||||
import Match from "preact-router/match";
|
import Match from "preact-router/match";
|
||||||
import { useDevContext } from "../context/useDevContext";
|
import { useDevContext } from "../context/devContext";
|
||||||
import { PopupNavigation } from '../components/styled'
|
import { PopupNavigation } from '../components/styled'
|
||||||
|
|
||||||
export enum Pages {
|
export enum Pages {
|
||||||
|
@ -25,7 +25,7 @@ import { createHashHistory } from "history";
|
|||||||
import { render } from "preact";
|
import { render } from "preact";
|
||||||
import Router, { route, Route } from "preact-router";
|
import Router, { route, Route } from "preact-router";
|
||||||
import { useEffect } from "preact/hooks";
|
import { useEffect } from "preact/hooks";
|
||||||
import { DevContextProvider } from "./context/useDevContext";
|
import { DevContextProvider } from "./context/devContext";
|
||||||
import { useTalerActionURL } from "./hooks/useTalerActionURL";
|
import { useTalerActionURL } from "./hooks/useTalerActionURL";
|
||||||
import { strings } from "./i18n/strings";
|
import { strings } from "./i18n/strings";
|
||||||
import { BackupPage } from "./popup/BackupPage";
|
import { BackupPage } from "./popup/BackupPage";
|
||||||
|
Loading…
Reference in New Issue
Block a user