commit 6d040035819e5c90a1bbe7940f4d204b2de5c1f4 parent 744c1d2e9258352218d5fe05f9c6c31afdf55476 Author: Sebastian <sebasjm@gmail.com> Date: Mon, 3 May 2021 01:26:16 -0300 new translation system Diffstat:
115 files changed, 11457 insertions(+), 3064 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md @@ -26,7 +26,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - cleanup instance and token management, because code is a mess and can be refactored - unlock a product when is locked - + - check that there is no place where the taxes are suming up + - translation missing: yup (check for some other dynamic message) ## [Unreleased] - fixed bug when updating token and not admin - showing a yellow bar on non-default instance navigation (admin) diff --git a/DESIGN.md b/DESIGN.md @@ -120,3 +120,25 @@ follow this structure: action associated with it * (Then) a particular set of observable consequences should be expected + +# Accessibility + +Pages and components should be built with accessibility in mind. + +https://github.com/nickcolley/jest-axe +https://orkhanhuseyn.medium.com/accessibility-testing-in-react-with-jest-axe-e08c2a3f3289 +http://accesibilidadweb.dlsi.ua.es/?menu=jaws +https://webaim.org/projects/screenreadersurvey8/#intro +https://www.gov.uk/service-manual/technology/testing-with-assistive-technologies#how-to-test +https://es.reactjs.org/docs/accessibility.html + +# Internationalization + +Every non translated message should be written in english and wrapped into: + + * i18n function from useTranslator() hook + * <Translate /> component + +Makefile has a i18n that will parse source files and update the po template. +When *.po are updated, running the i18n target will create the strings.ts that +the application will use in runtime. diff --git a/README.md b/README.md @@ -9,6 +9,14 @@ Merchant Admin Frontend is a Single Page Application (SPA) that connect with a r - make - python>=3.8 +For the latest version of @gnu-taler npm packages add + +```shell +@gnu-taler:registry=https://gitlab.com/api/v4/packages/npm/ +``` + +into `.npmrc` file in your home folder. + ## Compiling from source Check the requirements and run `./bootstrap` and `./configure` diff --git a/build-system/Makefile b/build-system/Makefile @@ -1,8 +1,7 @@ # This Makefile has been placed in the public domain. -src = src - PORT = 8080 + include ./build-system/config.mk .PHONY: compile @@ -36,7 +35,7 @@ build: pnpm run build .PHONY: build -build-single: compile +build-single: pnpm run build-single --filter merchant-backoffice @echo Build done, result at: 'packages/frontend/single/index.html' @@ -45,7 +44,7 @@ submodules-update: git submodule update --recursive --remote .PHONY: check -check: compile +check: compile lint pnpm run check .PHONY: dev @@ -83,3 +82,7 @@ install-view: install -m 644 -D $$file ${prefix}/$${file#packages/frontend/storybook-static/}; \ done +.PHONY: i18n +i18n: + ./build-translations.sh + diff --git a/build-translations.sh b/build-translations.sh @@ -0,0 +1,25 @@ +#!/bin/bash +cd packages/frontend; + +PONAME=taler-merchant-backoffice +POGEN=node_modules/@gnu-taler/pogen/bin/pogen.js + +find src \( -name '*.ts' -or -name '*.tsx' \) ! -name '*.d.ts' \ + | xargs node $POGEN \ + | msguniq \ + | msgmerge src/i18n/poheader - \ + > src/i18n/$PONAME.pot + +# merge existing translations +for pofile in src/i18n/*.po; do + echo merging $pofile; + msgmerge -o $pofile $pofile src/i18n/$PONAME.pot; +done; + +# generate .ts file containing all translations +cat src/i18n/strings-prelude > src/i18n/strings.ts +for pofile in src/i18n/*.po; do \ + echo appending $pofile; \ + ./contrib/po2ts $pofile >> src/i18n/strings.ts; \ +done; + diff --git a/packages/frontend/.storybook/main.js b/packages/frontend/.storybook/main.js @@ -27,7 +27,7 @@ module.exports = { ], "addons": [ "@storybook/preset-scss", - // "@storybook/addon-a11y", + "@storybook/addon-a11y", "@storybook/addon-essentials" //docs, control, actions, viewpot, toolbar, background ], webpackFinal: async (config, { configType }) => { diff --git a/packages/frontend/.storybook/preview.js b/packages/frontend/.storybook/preview.js @@ -15,10 +15,8 @@ */ import "../src/scss/main.scss" -import { MessageProvider } from "preact-messages"; -import { ConfigContextProvider } from '../src/context/backend' -import * as messages from '../src/messages' -import { h } from 'preact'; +import { ConfigContextProvider } from '../src/context/config' +import { TranslationProvider } from '../src/context/translation' const mockConfig = { backendURL: 'http://demo.taler.net', @@ -48,9 +46,9 @@ export const globalTypes = { export const decorators = [ (Story, { globals }) => { - return <MessageProvider locale={globals.locale} onError="warn" messages={messages[globals.locale]} pathSep={null} onError={() => null}> + return <TranslationProvider initial={globals.locale}> <Story /> - </MessageProvider> + </TranslationProvider> }, (Story) => <ConfigContextProvider value={mockConfig}> <Story /> </ConfigContextProvider> ]; diff --git a/packages/frontend/contrib/po2ts b/packages/frontend/contrib/po2ts @@ -0,0 +1,42 @@ +#!/usr/bin/env node +/* + This file is part of GNU Taler + (C) 2020 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/> + */ + +/** + * Convert a <lang>.po file into a JavaScript / TypeScript expression. + */ + +const po2json = require("po2json"); + +const filename = process.argv[2]; + +if (!filename) { + console.error("error: missing filename"); + process.exit(1); +} + +const m = filename.match(/([a-zA-Z0-9-_]+).po/); + +if (!m) { + console.error("error: unexpected filename (expected <lang>.po)"); + process.exit(1); +} + +const lang = m[1]; +const pojson = po2json.parseFileSync(filename, { format: "jed1.x", fuzzy: true }); +const s = + "strings['" + lang + "'] = " + JSON.stringify(pojson, null, " ") + ";\n"; +console.log(s); diff --git a/packages/frontend/package.json b/packages/frontend/package.json @@ -43,12 +43,12 @@ ] }, "dependencies": { + "@gnu-taler/taler-util": "^0.8.2", "axios": "^0.21.1", "date-fns": "^2.21.1", "history": "4.10.1", - "messageformat": "^2.3.0", + "jed": "^1.1.1", "preact": "^10.5.13", - "preact-messages": "workspace:*", "preact-router": "^3.2.1", "swr": "^0.5.5", "yup": "^0.32.9" @@ -57,6 +57,7 @@ "@babel/core": "^7.13.16", "@babel/plugin-transform-react-jsx-source": "^7.12.13", "@creativebulma/bulma-tooltip": "^1.2.0", + "@gnu-taler/pogen": "^0.0.5", "@storybook/addon-a11y": "^6.2.9", "@storybook/addon-actions": "^6.2.9", "@storybook/addon-essentials": "^6.2.9", @@ -71,7 +72,6 @@ "@types/mocha": "^8.2.2", "@typescript-eslint/eslint-plugin": "^4.22.0", "@typescript-eslint/parser": "^4.22.0", - "ava": "^3.15.0", "babel-loader": "^8.2.2", "base64-inline-loader": "^1.1.1", "bulma": "^0.9.2", @@ -93,8 +93,8 @@ "inline-chunk-html-plugin": "^1.1.1", "jest": "^26.6.3", "jest-preset-preact": "^4.0.2", - "messageformat-po-loader": "^0.3.0", "node-sass": "^5.0.0", + "po2json": "^0.4.5", "preact-cli": "^3.0.5", "preact-render-to-json": "^3.6.6", "preact-render-to-string": "^5.1.19", diff --git a/packages/frontend/src/ApplicationReadyRoutes.tsx b/packages/frontend/src/ApplicationReadyRoutes.tsx @@ -26,10 +26,10 @@ import { InstanceRoutes } from "./InstanceRoutes"; import LoginPage from './paths/login'; import { INSTANCE_ID_LOOKUP } from './utils/constants'; import { NotYetReadyAppMenu, Menu, NotificationCard } from './components/menu'; -import { useMessageTemplate } from 'preact-messages'; +import { useTranslator } from './i18n'; export function ApplicationReadyRoutes(): VNode { - const i18n = useMessageTemplate(); + const i18n = useTranslator(); const { url: backendURL, changeBackend, updateToken, clearAllTokens } = useBackendContext(); const updateLoginStatus = (url: string, token?: string) => { diff --git a/packages/frontend/src/InstanceRoutes.tsx b/packages/frontend/src/InstanceRoutes.tsx @@ -21,14 +21,15 @@ import { createHashHistory } from 'history'; import { Fragment, FunctionComponent, h, VNode } from 'preact'; -import { useMessageTemplate } from 'preact-messages'; import { Route, route, Router } from 'preact-router'; import { useCallback, useEffect, useMemo, useState } from "preact/hooks"; import { Loading } from './components/exception/loading'; import { NotificationCard } from './components/menu'; -import { InstanceContextProvider, useBackendContext } from './context/backend'; +import { useBackendContext } from './context/backend'; +import { InstanceContextProvider } from './context/instance'; import { useBackendDefaultToken, useBackendInstanceToken } from './hooks'; import { HttpError } from "./hooks/backend"; +import { useTranslator } from './i18n'; import InstanceCreatePage from "./paths/admin/create"; import InstanceListPage from './paths/admin/list'; import OrderCreatePage from './paths/instance/orders/create'; @@ -83,8 +84,8 @@ export function InstanceRoutes({ id, admin }: Props): VNode { const [token, updateToken] = useBackendInstanceToken(id); const { changeBackend, addTokenCleaner } = useBackendContext(); const cleaner = useCallback(() => { updateToken(undefined); }, [id]); - const i18n = useMessageTemplate(''); - const [globalNotification, setGlobalNotification] = useState<Notification & {to:string} | undefined>(undefined) + const i18n = useTranslator(); + const [globalNotification, setGlobalNotification] = useState<Notification & { to: string } | undefined>(undefined) useEffect(() => { addTokenCleaner(cleaner); @@ -104,8 +105,8 @@ export function InstanceRoutes({ id, admin }: Props): VNode { const ServerErrorRedirectTo = (to: InstancePaths | AdminPaths) => (error: HttpError) => { setGlobalNotification({ - message: `HTTP status #${error.status}: Server reported a problem`, - description: `Got message: "${error.message}" from: ${error.info?.url}`, + message: i18n`HTTP status #${error.status}: Server reported a problem`, + description: i18n`Got message: "${error.message}" from: ${error.info?.url}`, type: 'ERROR', to }) @@ -122,8 +123,8 @@ export function InstanceRoutes({ id, admin }: Props): VNode { if (admin && id === 'default') { return <Fragment> <NotificationCard notification={{ - message: 'No default instance', - description: 'in order to use merchant backoffice, you should create the default instance', + message: i18n`No default instance`, + description: i18n`in order to use merchant backoffice, you should create the default instance`, type: 'INFO' }} /> <InstanceCreatePage forceId="default" onConfirm={() => { @@ -210,7 +211,7 @@ export function InstanceRoutes({ id, admin }: Props): VNode { onBack={() => { route(InstancePaths.product_list); }} onNotFound={IfAdminCreateDefaultOr(NotFoundPage)} /> - <Route path={InstancePaths.product_new} + <Route path={InstancePaths.product_new} component={ProductCreatePage} onConfirm={() => { route(InstancePaths.product_list); }} onBack={() => { route(InstancePaths.product_list); }} @@ -272,19 +273,27 @@ function AdminInstanceUpdatePage({ id, ...rest }: { id: string } & InstanceUpdat if (token) updateToken(token); }; - const i18n = useMessageTemplate(''); + const i18n = useTranslator(); return <InstanceContextProvider value={value}> <InstanceUpdatePage {...rest} onLoadError={(error: HttpError) => { return <Fragment> - <NotificationCard notification={{ message: `Server reported a problem: HTTP status #${error.status}`, description: `Got message: ${error.message} from: ${error.info?.url}`, type: 'ERROR' }} /> + <NotificationCard notification={{ + message: i18n`Server reported a problem: HTTP status #${error.status}`, + description: i18n`Got message: ${error.message} from: ${error.info?.url}`, + type: 'ERROR' + }} /> <LoginPage onConfirm={updateLoginStatus} /> </Fragment> }} onUnauthorized={() => { return <Fragment> - <NotificationCard notification={{ message: i18n`Access denied`, description: i18n`Check your token is valid`, type: 'ERROR', }} /> + <NotificationCard notification={{ + message: i18n`Access denied`, + description: i18n`Check your token is valid`, + type: 'ERROR', + }} /> <LoginPage onConfirm={updateLoginStatus} /> </Fragment> }} diff --git a/packages/frontend/src/components/exception/login.tsx b/packages/frontend/src/components/exception/login.tsx @@ -20,9 +20,10 @@ */ import { h, VNode } from "preact"; -import { useMessageTemplate } from "preact-messages"; import { useState } from "preact/hooks"; -import { useBackendContext, useInstanceContext } from "../../context/backend"; +import { useBackendContext } from "../../context/backend"; +import { useInstanceContext } from "../../context/instance"; +import { Translate, useTranslator } from "../../i18n"; import { Notification } from "../../utils/types"; interface Props { @@ -36,7 +37,7 @@ export function LoginModal({ onConfirm, withMessage }: Props): VNode { const [token, setToken] = useState(!admin ? baseToken : instanceToken || '') const [url, setURL] = useState(backendUrl) - const i18n = useMessageTemplate() + const i18n = useTranslator() return <div class="columns is-centered"> <div class="column is-two-thirds " > @@ -82,7 +83,7 @@ export function LoginModal({ onConfirm, withMessage }: Props): VNode { <footer class="modal-card-foot " style={{ justifyContent: 'flex-end', border: '1px solid', borderTop: 0 }} > <button class="button is-info" onClick={(): void => { onConfirm(url, token ? token : undefined); - }} >Confirm</button> + }} ><Translate>Confirm</Translate></button> </footer> </div> </div> diff --git a/packages/frontend/src/components/form/FormProvider.tsx b/packages/frontend/src/components/form/FormProvider.tsx @@ -60,14 +60,8 @@ export function useFormContext<T>() { return useContext<FormType<T>>(FormContext) } -export type ValidationError = { - type?: string; - message: string; - params?: any; -} - export type FormErrors<T> = { - [P in keyof T]?: ValidationError + [P in keyof T]?: string } export type FormtoStr<T> = { diff --git a/packages/frontend/src/components/form/Input.tsx b/packages/frontend/src/components/form/Input.tsx @@ -19,12 +19,9 @@ * @author Sebastian Javier Marchano (sebasjm) */ import { ComponentChildren, h, VNode } from "preact"; -import { Message, useMessage } from "preact-messages"; -import { useField } from "./useField"; +import { useField, InputProps } from "./useField"; -interface Props<T> { - name: T; - readonly?: boolean; +interface Props<T> extends InputProps<T> { inputType?: 'text' | 'number' | 'multiline'; expand?: boolean; toStr?: (v?: any) => string; @@ -41,16 +38,13 @@ const TextInput = ({ inputType, error, ...rest }: any) => inputType === 'multili <textarea {...rest} class={error ? "textarea is-danger" : "textarea"} rows="3" /> : <input {...rest} class={error ? "input is-danger" : "input"} type={inputType} />; -export function Input<T>({ name, readonly, expand, children, inputType, inputExtra, side, fromStr = defaultFromString, toStr = defaultToString }: Props<keyof T>): VNode { - const { error, value, onChange, formName } = useField<T>(name); - - const placeholder = useMessage(`fields.${!formName ? 'instance' : formName}.${name}.placeholder`); - const tooltip = useMessage(`fields.${!formName ? 'instance' : formName}.${name}.tooltip`); +export function Input<T>({ name, readonly, placeholder, tooltip, label, expand, help, children, inputType, inputExtra, side, fromStr = defaultFromString, toStr = defaultToString }: Props<keyof T>): VNode { + const { error, value, onChange } = useField<T>(name); return <div class="field is-horizontal"> <div class="field-label is-normal"> <label class="label"> - <Message id={`fields.${!formName ? 'instance' : formName}.${name}.label`} /> + {label} {tooltip && <span class="icon" data-tooltip={tooltip}> <i class="mdi mdi-information" /> </span>} @@ -64,12 +58,10 @@ export function Input<T>({ name, readonly, expand, children, inputType, inputExt placeholder={placeholder} readonly={readonly} name={String(name)} value={toStr(value)} onChange={(e: h.JSX.TargetedEvent<HTMLInputElement>): void => onChange(fromStr(e.currentTarget.value))} /> - <Message id={`fields.${!formName ? 'instance' : formName}.${name}.help`}> </Message> + {help} {children} </p> - {error ? <p class="help is-danger"> - <Message id={`validation.${error.type}`} fields={error.params}>{error.message} </Message> - </p> : null} + {error && <p class="help is-danger">{error}</p>} </div> {side} </div> diff --git a/packages/frontend/src/components/form/InputArray.tsx b/packages/frontend/src/components/form/InputArray.tsx @@ -19,14 +19,11 @@ * @author Sebastian Javier Marchano (sebasjm) */ import { h, VNode } from "preact"; -import { Message, useMessage, useMessageTemplate } from "preact-messages"; import { useState } from "preact/hooks"; -import { ValidationError } from "./FormProvider"; -import { useField } from "./useField"; +import { useTranslator } from "../../i18n"; +import { InputProps, useField } from "./useField"; -export interface Props<T> { - name: T; - readonly?: boolean; +export interface Props<T> extends InputProps<T> { isValid?: (e: any) => boolean; addonBefore?: string; toStr?: (v?: any) => string; @@ -36,22 +33,20 @@ export interface Props<T> { const defaultToString = (f?: any): string => f || '' const defaultFromString = (v: string): any => v as any -export function InputArray<T>({ name, readonly, addonBefore, isValid = () => true, fromStr = defaultFromString, toStr = defaultToString }: Props<keyof T>): VNode { - const { error: formError, value, onChange, formName } = useField<T>(name); - const [localError, setLocalError] = useState<ValidationError | null>(null) - const placeholder = useMessage(`fields.${!formName ? 'instance' : formName}.${name}.placeholder`); - const tooltip = useMessage(`fields.${!formName ? 'instance' : formName}.${name}.tooltip`); +export function InputArray<T>({ name, readonly, placeholder, tooltip, label, help, addonBefore, isValid = () => true, fromStr = defaultFromString, toStr = defaultToString }: Props<keyof T>): VNode { + const { error: formError, value, onChange } = useField<T>(name); + const [localError, setLocalError] = useState<string | null>(null) const error = formError || localError const array: any[] = (value ? value! : []) as any; const [currentValue, setCurrentValue] = useState(''); - const i18n = useMessageTemplate(); + const i18n = useTranslator(); return <div class="field is-horizontal"> <div class="field-label is-normal"> <label class="label"> - <Message id={`fields.${!formName ? 'instance' : formName}.${name}.label`} /> + {label} {tooltip && <span class="icon" data-tooltip={tooltip}> <i class="mdi mdi-information" /> </span>} @@ -68,13 +63,13 @@ export function InputArray<T>({ name, readonly, addonBefore, isValid = () => tru placeholder={placeholder} readonly={readonly} disabled={readonly} name={String(name)} value={currentValue} onChange={(e): void => setCurrentValue(e.currentTarget.value)} /> - <Message id={`fields.${!formName ? 'instance' : formName}.${name}.help`}> </Message> + {help} </p> <p class="control"> <button class="button is-info" onClick={(): void => { const v = fromStr(currentValue) if (!isValid(v)) { - setLocalError({ message: i18n`The value ${v} is invalid for a payment url` }) + setLocalError(i18n`The value ${v} is invalid for a payment url`) return; } setLocalError(null) @@ -84,9 +79,7 @@ export function InputArray<T>({ name, readonly, addonBefore, isValid = () => tru }}>add</button> </p> </div> - {error ? <p class="help is-danger"> - <Message id={`validation.${error.type}`} fields={error.params}>{error.message}</Message> - </p> : null} + {error && <p class="help is-danger"> {help} </p>} {array.map((v,i) => <div key={i} class="tags has-addons mt-3 mb-0"> <span class="tag is-medium is-info mb-0" style={{ maxWidth: '90%' }}>{v}</span> <a class="tag is-medium is-danger is-delete mb-0" onClick={() => { diff --git a/packages/frontend/src/components/form/InputBoolean.tsx b/packages/frontend/src/components/form/InputBoolean.tsx @@ -19,10 +19,9 @@ * @author Sebastian Javier Marchano (sebasjm) */ import { h, VNode } from "preact"; -import { Message, useMessage } from "preact-messages"; -import { useField } from "./useField"; +import { InputProps, useField } from "./useField"; -interface Props<T> { +interface Props<T> extends InputProps<T> { name: T; readonly?: boolean; expand?: boolean; @@ -35,12 +34,8 @@ const defaultToBoolean = (f?: any): boolean | undefined => f || '' const defaultFromBoolean = (v: boolean | undefined): any => v as any - -export function InputBoolean<T>({ name, readonly, threeState, expand, fromBoolean = defaultFromBoolean, toBoolean = defaultToBoolean }: Props<keyof T>): VNode { - const { error, value, onChange, formName } = useField<T>(name); - - const placeholder = useMessage(`fields.${!formName ? 'instance' : formName}.${name}.placeholder`); - const tooltip = useMessage(`fields.${!formName ? 'instance' : formName}.${name}.tooltip`); +export function InputBoolean<T>({ name, readonly, placeholder, tooltip, label, help, threeState, expand, fromBoolean = defaultFromBoolean, toBoolean = defaultToBoolean }: Props<keyof T>): VNode { + const { error, value, onChange } = useField<T>(name); const onCheckboxClick = (): void => { const c = toBoolean(value) @@ -51,7 +46,7 @@ export function InputBoolean<T>({ name, readonly, threeState, expand, fromBoolea return <div class="field is-horizontal"> <div class="field-label is-normal"> <label class="label"> - <Message id={`fields.${!formName ? 'instance' : formName}.${name}.label`} /> + {label} {tooltip && <span class="icon has-tooltip-right" data-tooltip={tooltip}> <i class="mdi mdi-information" /> </span>} @@ -69,11 +64,9 @@ export function InputBoolean<T>({ name, readonly, threeState, expand, fromBoolea <span class="check" /> </label> - <Message id={`fields.${!formName ? 'instance' : formName}.${name}.help`}> </Message> + {help} </p> - {error ? <p class="help is-danger"> - <Message id={`validation.${error.type}`} fields={error.params}>{error.message} </Message> - </p> : null} + {error && <p class="help is-danger">{error}</p>} </div> </div> </div>; diff --git a/packages/frontend/src/components/form/InputCurrency.tsx b/packages/frontend/src/components/form/InputCurrency.tsx @@ -19,23 +19,23 @@ * @author Sebastian Javier Marchano (sebasjm) */ import { ComponentChildren, h } from "preact"; -import { useConfigContext } from "../../context/backend"; +import { useConfigContext } from "../../context/config"; import { Amount } from "../../declaration"; import { InputWithAddon } from "./InputWithAddon"; +import { InputProps } from "./useField"; -export interface Props<T> { - name: keyof T; - readonly?: boolean; +export interface Props<T> extends InputProps<T> { expand?: boolean; addonAfter?: ComponentChildren; children?: ComponentChildren; side?: ComponentChildren; } -export function InputCurrency<T>({ name, readonly, expand, addonAfter, children, side }: Props<T>) { +export function InputCurrency<T>({ name, readonly, label, placeholder, help, tooltip, expand, addonAfter, children, side }: Props<keyof T>) { const config = useConfigContext() return <InputWithAddon<T> name={name} readonly={readonly} addonBefore={config.currency} - side={side} + side={side} + label={label} placeholder={placeholder} help={help} tooltip={tooltip} addonAfter={addonAfter} inputType='number' expand={expand} toStr={(v?: Amount) => v?.split(':')[1] || ''} diff --git a/packages/frontend/src/components/form/InputDate.tsx b/packages/frontend/src/components/form/InputDate.tsx @@ -20,27 +20,23 @@ */ import { format } from "date-fns"; import { h, VNode } from "preact"; -import { Message, useMessage } from "preact-messages"; import { useState } from "preact/hooks"; +import { Translate, useTranslator } from "../../i18n"; import { DatePicker } from "./DatePicker"; -import { useField } from "./useField"; +import { InputProps, useField } from "./useField"; -export interface Props<T> { - name: keyof T; +export interface Props<T> extends InputProps<T> { readonly?: boolean; expand?: boolean; //FIXME: create separated components InputDate and InputTimestamp withTimestampSupport?: boolean; } -export function InputDate<T>({ name, readonly, expand, withTimestampSupport }: Props<T>): VNode { +export function InputDate<T>({ name, readonly, label, placeholder, help, tooltip, expand, withTimestampSupport }: Props<keyof T>): VNode { const [opened, setOpened] = useState(false) - // const [editing, setEditing] = useState(false) - - const { error, value, onChange, formName } = useField<T>(name); - - // const placeholder = useMessage(`fields.${!formName ? 'instance' : formName}.${name}.placeholder`); - const tooltip = useMessage(`fields.${!formName ? 'instance' : formName}.${name}.tooltip`); + const i18n = useTranslator() + + const { error, value, onChange } = useField<T>(name); let strValue = '' if (!value) { @@ -56,7 +52,7 @@ export function InputDate<T>({ name, readonly, expand, withTimestampSupport }: P return <div class="field is-horizontal"> <div class="field-label is-normal"> <label class="label"> - <Message id={`fields.${!formName ? 'instance' : formName}.${name}.label`} /> + {label} {tooltip && <span class="icon" data-tooltip={tooltip}> <i class="mdi mdi-information" /> </span>} @@ -68,10 +64,10 @@ export function InputDate<T>({ name, readonly, expand, withTimestampSupport }: P <p class={expand ? "control is-expanded" : "control"}> <input class="input" type="text" readonly value={strValue} - placeholder="pick a date" + placeholder={i18n`pick a date`} onClick={() => setOpened(true)} /> - <Message id={`fields.${!formName ? 'instance' : formName}.${name}.help`}> </Message> + {help} </p> <div class="control" onClick={() => setOpened(true)}> <a class="button is-static" > @@ -79,12 +75,12 @@ export function InputDate<T>({ name, readonly, expand, withTimestampSupport }: P </a> </div> </div> - {error ? <p class="help is-danger"><Message id={`validation.${error.type}`} fields={error.params}>{error.message}</Message></p> : null} + {error && <p class="help is-danger">{error}</p>} </div> - <button class="button is-info mr-3" onClick={() => onChange(undefined as any)} >clear</button> + <button class="button is-info mr-3" onClick={() => onChange(undefined as any)} ><Translate>clear</Translate></button> {withTimestampSupport && - <button class="button is-info" onClick={() => onChange({ t_ms: 'never' } as any)}>never</button> + <button class="button is-info" onClick={() => onChange({ t_ms: 'never' } as any)}><Translate>never</Translate></button> } </div> <DatePicker @@ -92,7 +88,7 @@ export function InputDate<T>({ name, readonly, expand, withTimestampSupport }: P closeFunction={() => setOpened(false)} dateReceiver={(d) => { if (withTimestampSupport) { - onChange({t_ms: d.getTime()} as any) + onChange({ t_ms: d.getTime() } as any) } else { onChange(d as any) } diff --git a/packages/frontend/src/components/form/InputDuration.tsx b/packages/frontend/src/components/form/InputDuration.tsx @@ -21,19 +21,19 @@ import { formatDuration, intervalToDuration } from "date-fns"; import { h, VNode } from "preact"; import { RelativeTime } from "../../declaration"; -import { useField } from "./useField"; +import { InputProps, useField } from "./useField"; import { InputWithAddon } from "./InputWithAddon"; -export interface Props<T> { - name: keyof T; +export interface Props<T> extends InputProps<T> { expand?: boolean; readonly?: boolean; } -export function InputDuration<T>({ name, expand, readonly }: Props<T>): VNode { +export function InputDuration<T>({ name, expand, placeholder, tooltip, label, help, readonly }: Props<keyof T>): VNode { const { value } = useField<T>(name); return <InputWithAddon<T> name={name} readonly={readonly} addonAfter={readableDuration(value as any)} expand={expand} + label={label} placeholder={placeholder} help={help} tooltip={tooltip} toStr={(v?: RelativeTime) => `${(v && v.d_ms !== "forever" && v.d_ms ? v.d_ms : '')}`} fromStr={(v: string) => ({ d_ms: (parseInt(v, 10)) || undefined })} /> diff --git a/packages/frontend/src/components/form/InputGroup.tsx b/packages/frontend/src/components/form/InputGroup.tsx @@ -19,25 +19,24 @@ * @author Sebastian Javier Marchano (sebasjm) */ import { ComponentChildren, h, VNode } from "preact"; -import { Message } from "preact-messages"; import { useState } from "preact/hooks"; import { useGroupField } from "./useGroupField"; export interface Props<T> { - name: keyof T; + name: T; children: ComponentChildren; - description?: string; + label: string; alternative?: ComponentChildren; } -export function InputGroup<T>({ name, description, children, alternative}: Props<T>): VNode { +export function InputGroup<T>({ name, label, children, alternative }: Props<keyof T>): VNode { const [active, setActive] = useState(false); const group = useGroupField<T>(name); - + return <div class="card"> <header class="card-header"> - <p class={ !group?.hasError ? "card-header-title" : "card-header-title has-text-danger"}> - { description ? description : <Message id={`fields.groups.${String(name)}.label`} /> } + <p class={!group?.hasError ? "card-header-title" : "card-header-title has-text-danger"}> + {label} </p> <button class="card-header-icon" aria-label="more options" onClick={(): void => setActive(!active)}> <span class="icon"> @@ -47,16 +46,16 @@ export function InputGroup<T>({ name, description, children, alternative}: Props </span> </button> </header> - { active ? <div class="card-content"> + {active ? <div class="card-content"> <div class="content"> {children} </div> </div> : ( alternative ? <div class="card-content"> - <div class="content"> - {alternative} - </div> - </div> : undefined - ) } + <div class="content"> + {alternative} + </div> + </div> : undefined + )} </div>; } diff --git a/packages/frontend/src/components/form/InputImage.tsx b/packages/frontend/src/components/form/InputImage.tsx @@ -19,24 +19,20 @@ * @author Sebastian Javier Marchano (sebasjm) */ import { ComponentChildren, h } from "preact"; -import { Message, useMessage } from "preact-messages"; import { useRef, useState } from "preact/hooks"; import emptyImage from "../../assets/empty.png"; -import { useField } from "./useField"; +import { Translate } from "../../i18n"; +import { InputProps, useField } from "./useField"; -export interface Props<T> { - name: keyof T; - readonly?: boolean; +export interface Props<T> extends InputProps<T> { expand?: boolean; addonAfter?: ComponentChildren; children?: ComponentChildren; } -export function InputImage<T>({ name, readonly, children, expand }: Props<T>) { - const { error, value, onChange, formName } = useField<T>(name); +export function InputImage<T>({ name, readonly, placeholder, tooltip, label, help, children, expand }: Props<keyof T>) { + const { error, value, onChange } = useField<T>(name); - const placeholder = useMessage(`fields.${!formName ? 'instance' : formName}.${name}.placeholder`); - const tooltip = useMessage(`fields.${!formName ? 'instance' : formName}.${name}.tooltip`); const image = useRef<HTMLInputElement>(null) const [sizeError, setSizeError] = useState(false) @@ -44,7 +40,7 @@ export function InputImage<T>({ name, readonly, children, expand }: Props<T>) { return <div class="field is-horizontal"> <div class="field-label is-normal"> <label class="label"> - <Message id={`fields.${!formName ? 'instance' : formName}.${name}.label`} /> + {label} {tooltip && <span class="icon" data-tooltip={tooltip}> <i class="mdi mdi-information" /> </span>} @@ -63,7 +59,7 @@ export function InputImage<T>({ name, readonly, children, expand }: Props<T>) { if (!f || f.length != 1) { return onChange(emptyImage) } - if (f[0].size > 1024*1024) { + if (f[0].size > 1024 * 1024) { setSizeError(true) return onChange(emptyImage) } @@ -76,15 +72,13 @@ export function InputImage<T>({ name, readonly, children, expand }: Props<T>) { onChange(`data:${f[0].type};base64,${b64}` as any) }) }} /> - <Message id={`fields.${!formName ? 'instance' : formName}.${name}.help`}> </Message> + {help} {children} </p> - {error ? <p class="help is-danger"> - <Message id={`validation.${error.type}`} fields={error.params}>{error.message} </Message> - </p> : null} - {sizeError ? <p class="help is-danger"> - <Message id={`validation.imageSizeLimit`} /> - </p> : null} + {error && <p class="help is-danger">{error}</p>} + {sizeError && <p class="help is-danger"> + <Translate>Image should be smaller than 1 MB</Translate> + </p>} </div> </div> </div> diff --git a/packages/frontend/src/components/form/InputNumber.tsx b/packages/frontend/src/components/form/InputNumber.tsx @@ -19,23 +19,21 @@ * @author Sebastian Javier Marchano (sebasjm) */ import { ComponentChildren, h } from "preact"; -import { useConfigContext } from "../../context/backend"; -import { Amount } from "../../declaration"; -import { Input } from "./Input"; import { InputWithAddon } from "./InputWithAddon"; +import { InputProps } from "./useField"; -export interface Props<T> { - name: keyof T; +export interface Props<T> extends InputProps<T> { readonly?: boolean; expand?: boolean; side?: ComponentChildren; children?: ComponentChildren; } -export function InputNumber<T>({ name, readonly, expand, children, side }: Props<T>) { +export function InputNumber<T>({ name, readonly, placeholder, tooltip, label, help, expand, children, side }: Props<keyof T>) { return <InputWithAddon<T> name={name} readonly={readonly} fromStr={(v) => parseInt(v, 10)} toStr={(v) => `${v}`} inputType='number' expand={expand} + label={label} placeholder={placeholder} help={help} tooltip={tooltip} inputExtra={{ min: 0 }} children={children} side={side} diff --git a/packages/frontend/src/components/form/InputPayto.tsx b/packages/frontend/src/components/form/InputPayto.tsx @@ -21,17 +21,16 @@ import { h, VNode } from "preact"; import { InputArray } from "./InputArray"; import { PAYTO_REGEX } from "../../utils/constants"; +import { InputProps } from "./useField"; -export interface Props<T> { - name: keyof T; - readonly?: boolean; -} +export type Props<T> = InputProps<T>; const PAYTO_START_REGEX = /^payto:\/\// -export function InputPayto<T>({ name, readonly }: Props<T>): VNode { +export function InputPayto<T>({ name, readonly, placeholder, tooltip, label, help }: Props<keyof T>): VNode { return <InputArray<T> name={name} readonly={readonly} addonBefore="payto://" + label={label} placeholder={placeholder} help={help} tooltip={tooltip} isValid={(v) => v && PAYTO_REGEX.test(v) } toStr={(v?: string) => !v ? '': v.replace(PAYTO_START_REGEX, '')} fromStr={(v: string) => `payto://${v}` } diff --git a/packages/frontend/src/components/form/InputSearchProduct.tsx b/packages/frontend/src/components/form/InputSearchProduct.tsx @@ -23,6 +23,7 @@ import { useState } from "preact/hooks"; import emptyImage from "../../assets/empty.png"; import { MerchantBackend, WithId } from "../../declaration"; import { useInstanceProducts } from "../../hooks/product"; +import { Translate, useTranslator } from "../../i18n"; import { FormErrors, FormProvider } from "./FormProvider"; import { InputWithAddon } from "./InputWithAddon"; @@ -43,6 +44,8 @@ export function InputSearchProduct({ selected, onChange }: Props): VNode { const errors: FormErrors<ProductSearch> = { name: undefined } + const i18n = useTranslator() + if (selected) { return <article class="media"> @@ -53,8 +56,8 @@ export function InputSearchProduct({ selected, onChange }: Props): VNode { </figure> <div class="media-content"> <div class="content"> - <p class="media-meta">Product id: <b>{selected.id}</b></p> - <p>Description: {selected.description}</p> + <p class="media-meta"><Translate>Product id</Translate>: <b>{selected.id}</b></p> + <p><Translate>Description</Translate>: {selected.description}</p> <div class="buttons is-right mt-5"> <button class="button" onClick={() => onChange(undefined)}>clear</button> </div> @@ -67,12 +70,15 @@ export function InputSearchProduct({ selected, onChange }: Props): VNode { <InputWithAddon<ProductSearch> name="name" + label={i18n`Name`} addonBefore={<span class="icon" ><i class="mdi mdi-magnify" /></span>} > - <ProductList name={prodForm.name} onSelect={(p) => { - setProdName({ name: '' }) - onChange(p) - }} /> + <div> + <ProductList name={prodForm.name} onSelect={(p) => { + setProdName({ name: '' }) + onChange(p) + }} /> + </div> </InputWithAddon> </FormProvider> @@ -93,13 +99,13 @@ function ProductList({ name, onSelect }: ProductListProps) { if (result.loading) { products = <div class="dropdown-content"> - <div class="dropdown-item">loading...</div> + <div class="dropdown-item"><Translate>loading...</Translate></div> </div> } else if (result.ok && !!name) { if (!result.data.length) { products = <div class="dropdown-content"> <div class="dropdown-item"> - no products found + <Translate>no products found</Translate> </div> </div> } else { @@ -107,7 +113,7 @@ function ProductList({ name, onSelect }: ProductListProps) { products = <div class="dropdown-content"> {!filtered.length ? <div class="dropdown-item" > - no results + <Translate>no results</Translate> </div> : result.data.filter(p => re.test(p.id) || re.test(p.description)).map(p => ( <div key={p.id} class="dropdown-item" onClick={() => onSelect(p)} style={{ cursor: 'pointer' }}> diff --git a/packages/frontend/src/components/form/InputSecured.stories.tsx b/packages/frontend/src/components/form/InputSecured.stories.tsx @@ -35,14 +35,14 @@ export const InitialValueEmpty = (): VNode => { const [state, setState] = useState<Partial<T>>({ auth_token: '' }) return <FormProvider<T> object={state} errors={{}} valueHandler={setState}> Initial value: '' - <InputSecured<T> name="auth_token" /> + <InputSecured<T> name="auth_token" label="token" /> </FormProvider> } export const InitialValueToken = (): VNode => { const [state, setState] = useState<Partial<T>>({ auth_token: 'token' }) return <FormProvider<T> object={state} errors={{}} valueHandler={setState}> - <InputSecured<T> name="auth_token" /> + <InputSecured<T> name="auth_token" label="token" /> </FormProvider> } @@ -50,6 +50,6 @@ export const InitialValueNull = (): VNode => { const [state, setState] = useState<Partial<T>>({ auth_token: null }) return <FormProvider<T> object={state} errors={{}} valueHandler={setState}> Initial value: '' - <InputSecured<T> name="auth_token" /> + <InputSecured<T> name="auth_token" label="token" /> </FormProvider> } diff --git a/packages/frontend/src/components/form/InputSecured.tsx b/packages/frontend/src/components/form/InputSecured.tsx @@ -19,30 +19,24 @@ * @author Sebastian Javier Marchano (sebasjm) */ import { Fragment, h, VNode } from "preact"; -import { Message, useMessage } from "preact-messages"; import { useState } from "preact/hooks"; -import { useField } from "./useField"; +import { Translate } from "../../i18n"; +import { InputProps, useField } from "./useField"; -export interface Props<T> { - name: keyof T; - readonly?: boolean; -} +export type Props<T> = InputProps<T>; const TokenStatus = ({ prev, post }: any) => { if ((prev === undefined || prev === null) && (post === undefined || post === null)) return null return (prev === post) ? null : ( post === null ? - <span class="tag is-danger is-align-self-center ml-2">Deleting</span> : - <span class="tag is-warning is-align-self-center ml-2">Changing</span> + <span class="tag is-danger is-align-self-center ml-2"><Translate>Deleting</Translate></span> : + <span class="tag is-warning is-align-self-center ml-2"><Translate>Changing</Translate></span> ) } -export function InputSecured<T>({ name, readonly }: Props<T>): VNode { - const { error, value, initial, onChange, toStr, fromStr, formName } = useField<T>(name); - - const placeholder = useMessage(`fields.${!formName ? 'instance' : formName}.${name}.placeholder`, {}); - const tooltip = useMessage(`fields.${!formName ? 'instance' : formName}.${name}.tooltip`, {}); +export function InputSecured<T>({ name, readonly, placeholder, tooltip, label, help }: Props<keyof T>): VNode { + const { error, value, initial, onChange, toStr, fromStr } = useField<T>(name); const [active, setActive] = useState(false); const [newValue, setNuewValue] = useState("") @@ -51,7 +45,7 @@ export function InputSecured<T>({ name, readonly }: Props<T>): VNode { <div class="field is-horizontal"> <div class="field-label is-normal"> <label class="label"> - <Message id={`fields.${!formName ? 'instance' : formName}.${name}.label`} /> + {label} {tooltip && <span class="icon" data-tooltip={tooltip}> <i class="mdi mdi-information" /> </span>} @@ -63,7 +57,7 @@ export function InputSecured<T>({ name, readonly }: Props<T>): VNode { <div class="field has-addons"> <button class="button" onClick={(): void => { setActive(!active); }} > <div class="icon is-left"><i class="mdi mdi-lock-reset" /></div> - <span>Manage token</span> + <span><Translate>Manage token</Translate></span> </button> <TokenStatus prev={initial} post={value} /> </div> @@ -81,35 +75,35 @@ export function InputSecured<T>({ name, readonly }: Props<T>): VNode { onInput={(e): void => { setNuewValue(e.currentTarget.value) }} /> - <Message id={`fields.${!formName ? 'instance' : formName}.${name}.help`}> </Message> + {help} </div> <div class="control"> <button class="button is-info" disabled={fromStr(newValue) === value} onClick={(): void => { onChange(fromStr(newValue)); setActive(!active); setNuewValue(""); }} > <div class="icon is-left"><i class="mdi mdi-lock-outline" /></div> - <span>Update</span> + <span><Translate>Update</Translate></span> </button> </div> </div> </Fragment> } - {error ? <p class="help is-danger"><Message id={`validation.${error.type}`} fields={error.params}>{error.message}</Message></p> : null} + {error ? <p class="help is-danger">{error}</p> : null} </div> </div> {active && <div class="field is-horizontal"> <div class="field-body is-flex-grow-3"> - <div class="level" style={{width:'100%'}}> + <div class="level" style={{ width: '100%' }}> <div class="level-right is-flex-grow-1"> <div class="level-item"> <button class="button is-danger" disabled={null === value || undefined === value} onClick={(): void => { onChange(null!); setActive(!active); setNuewValue(""); }} > <div class="icon is-left"><i class="mdi mdi-lock-open-variant" /></div> - <span>Remove</span> + <span><Translate>Remove</Translate></span> </button> </div> <div class="level-item"> <button class="button " onClick={(): void => { onChange(initial!); setActive(!active); setNuewValue(""); }} > <div class="icon is-left"><i class="mdi mdi-lock-open-variant" /></div> - <span>Cancel</span> + <span><Translate>Cancel</Translate></span> </button> </div> </div> diff --git a/packages/frontend/src/components/form/InputSelector.tsx b/packages/frontend/src/components/form/InputSelector.tsx @@ -19,11 +19,9 @@ * @author Sebastian Javier Marchano (sebasjm) */ import { h, VNode } from "preact"; -import { Message, useMessage } from "preact-messages"; -import { useField } from "./useField"; +import { InputProps, useField } from "./useField"; -interface Props<T> { - name: T; +interface Props<T> extends InputProps<T> { readonly?: boolean; expand?: boolean; values: string[]; @@ -34,16 +32,14 @@ interface Props<T> { const defaultToString = (f?: any): string => f || '' const defaultFromString = (v: string): any => v as any -export function InputSelector<T>({ name, readonly, expand, values, fromStr = defaultFromString, toStr = defaultToString }: Props<keyof T>): VNode { - const { error, value, onChange, formName } = useField<T>(name); +export function InputSelector<T>({ name, readonly, expand, placeholder, tooltip, label, help, values, fromStr = defaultFromString, toStr = defaultToString }: Props<keyof T>): VNode { + const { error, value, onChange } = useField<T>(name); - const placeholder = useMessage(`fields.${!formName ? 'instance' : formName}.${name}.placeholder`); - const tooltip = useMessage(`fields.${!formName ? 'instance' : formName}.${name}.tooltip`); return <div class="field is-horizontal"> <div class="field-label is-normal"> <label class="label"> - <Message id={`fields.${!formName ? 'instance' : formName}.${name}.label`} /> + {label} {tooltip && <span class="icon" data-tooltip={tooltip}> <i class="mdi mdi-information" /> </span>} @@ -57,13 +53,11 @@ export function InputSelector<T>({ name, readonly, expand, values, fromStr = def onChange={(e) => { onChange(fromStr(e.currentTarget.value)) }}> <option>{placeholder}</option> {values - .map((v,i) => <option key={i} value={toStr(v)}>{toStr(v)}</option>)} + .map((v, i) => <option key={i} value={toStr(v)}>{toStr(v)}</option>)} </select> - <Message id={`fields.${!formName ? 'instance' : formName}.${name}.help`}> </Message> + {help} </p> - {error ? <p class="help is-danger"> - <Message id={`validation.${error.type}`} fields={error.params}>{error.message} </Message> - </p> : null} + {error && <p class="help is-danger">{error}</p>} </div> </div> </div>; diff --git a/packages/frontend/src/components/form/InputStock.stories.tsx b/packages/frontend/src/components/form/InputStock.stories.tsx @@ -35,7 +35,7 @@ type T = { stock?: Stock } export const CreateStockEmpty = () => { const [state, setState] = useState<Partial<T>>({}) return <FormProvider<T> name="product" object={state} errors={{}} valueHandler={setState}> - <InputStock<T> name="stock" /> + <InputStock<T> name="stock" label="Stock" /> <div><pre>{JSON.stringify(state, undefined, 2)}</pre></div> </FormProvider> } @@ -49,7 +49,7 @@ export const CreateStockUnknownRestock = () => { } }) return <FormProvider<T> name="product" object={state} errors={{}} valueHandler={setState}> - <InputStock<T> name="stock" /> + <InputStock<T> name="stock" label="Stock" /> <div><pre>{JSON.stringify(state, undefined, 2)}</pre></div> </FormProvider> } @@ -64,7 +64,7 @@ export const CreateStockNoRestock = () => { } }) return <FormProvider<T> name="product" object={state} errors={{}} valueHandler={setState}> - <InputStock<T> name="stock" /> + <InputStock<T> name="stock" label="Stock" /> <div><pre>{JSON.stringify(state, undefined, 2)}</pre></div> </FormProvider> } @@ -79,7 +79,7 @@ export const CreateStockWithRestock = () => { } }) return <FormProvider<T> name="product" object={state} errors={{}} valueHandler={setState}> - <InputStock<T> name="stock" /> + <InputStock<T> name="stock" label="Stock" /> <div><pre>{JSON.stringify(state, undefined, 2)}</pre></div> </FormProvider> } @@ -94,7 +94,7 @@ export const UpdatingProductWithManagedStock = () => { } }) return <FormProvider<T> name="product" object={state} errors={{}} valueHandler={setState}> - <InputStock<T> name="stock" alreadyExist /> + <InputStock<T> name="stock" label="Stock" alreadyExist /> <div><pre>{JSON.stringify(state, undefined, 2)}</pre></div> </FormProvider> } @@ -102,7 +102,7 @@ export const UpdatingProductWithManagedStock = () => { export const UpdatingProductWithInfiniteStock = () => { const [state, setState] = useState<Partial<T>>({}) return <FormProvider<T> name="product" object={state} errors={{}} valueHandler={setState}> - <InputStock<T> name="stock" alreadyExist /> + <InputStock<T> name="stock" label="Stock" alreadyExist /> <div><pre>{JSON.stringify(state, undefined, 2)}</pre></div> </FormProvider> } diff --git a/packages/frontend/src/components/form/InputStock.tsx b/packages/frontend/src/components/form/InputStock.tsx @@ -20,18 +20,16 @@ */ import { Fragment, h } from "preact"; import { MerchantBackend, Timestamp } from "../../declaration"; -import { useField } from "./useField"; +import { InputProps, useField } from "./useField"; import { FormProvider, FormErrors } from "./FormProvider"; import { useLayoutEffect, useState } from "preact/hooks"; import { Input } from "./Input"; -import { Message, useMessage } from "preact-messages"; import { InputGroup } from "./InputGroup"; import { InputNumber } from "./InputNumber"; import { InputDate } from "./InputDate"; +import { Translate, useTranslator } from "../../i18n"; -export interface Props<T> { - name: keyof T; - readonly?: boolean; +export interface Props<T> extends InputProps<T> { alreadyExist?: boolean; } @@ -52,15 +50,15 @@ interface StockDelta { } -export function InputStock<T>({ name, readonly, alreadyExist }: Props<T>) { - const { error, value, onChange, formName } = useField<T>(name); +export function InputStock<T>({ name, readonly, placeholder, tooltip, label, help, alreadyExist }: Props<keyof T>) { + const { error, value, onChange } = useField<T>(name); const [errors, setErrors] = useState<FormErrors<Entity>>({}) - const tooltip = useMessage(`fields.${!formName ? 'instance' : formName}.${name}.tooltip`, {}); - const [formValue, valueHandler] = useState<Partial<Entity>>(value) const [addedStock, setAddedStock] = useState<StockDelta>({ incoming: 0, lost: 0 }) + const i18n = useTranslator() + useLayoutEffect(() => { if (!formValue) { @@ -79,7 +77,7 @@ export function InputStock<T>({ name, readonly, alreadyExist }: Props<T>) { <div class="field is-horizontal"> <div class="field-label is-normal"> <label class="label"> - <Message id={`fields.${!formName ? 'instance' : formName}.${name}.label`} /> + {label} {tooltip && <span class="icon" data-tooltip={tooltip}> <i class="mdi mdi-information" /> </span>} @@ -89,9 +87,9 @@ export function InputStock<T>({ name, readonly, alreadyExist }: Props<T>) { <div class="field has-addons"> {!alreadyExist ? <button class="button" onClick={(): void => { valueHandler({ current: 0, lost: 0, sold: 0 } as Stock as any); }} > - <span>Manage stock</span> + <span><Translate>Manage stock</Translate></span> </button> : <button class="button" disabled > - <span>Infinite</span> + <span><Translate>Infinite</Translate></span> </button> } </div> @@ -103,29 +101,32 @@ export function InputStock<T>({ name, readonly, alreadyExist }: Props<T>) { const currentStock = (formValue.current || 0) - (formValue.lost || 0) - (formValue.sold || 0) const stockAddedErrors: FormErrors<typeof addedStock> = { - lost: currentStock + addedStock.incoming < addedStock.lost ? { - message: `lost cannot be greater that current + incoming (max ${currentStock + addedStock.incoming})` - } : undefined + lost: currentStock + addedStock.incoming < addedStock.lost ? + i18n`lost cannot be greater that current + incoming (max ${currentStock + addedStock.incoming})` + : undefined } const stockUpdateDescription = stockAddedErrors.lost ? '' : ( !!addedStock.incoming || !!addedStock.lost ? - `current stock will change from ${currentStock} to ${currentStock + addedStock.incoming - addedStock.lost}` : - `current stock will stay at ${currentStock}` + i18n`current stock will change from ${currentStock} to ${currentStock + addedStock.incoming - addedStock.lost}` : + i18n`current stock will stay at ${currentStock}` ) return <Fragment> <div class="card"> <header class="card-header"> - <p class="card-header-title">Stock</p> + {label} + {tooltip && <span class="icon" data-tooltip={tooltip}> + <i class="mdi mdi-information" /> + </span>} </header> <div class="card-content"> <FormProvider<Entity> name="stock" errors={errors} object={formValue} valueHandler={valueHandler}> {alreadyExist ? <Fragment> <FormProvider name="added" errors={stockAddedErrors} object={addedStock} valueHandler={setAddedStock as any}> - <InputNumber name="incoming" /> - <InputNumber name="lost" /> + <InputNumber name="incoming" label={i18n`Incoming`} /> + <InputNumber name="lost" label={i18n`Lost`} /> </FormProvider> <div class="field is-horizontal"> @@ -137,32 +138,34 @@ export function InputStock<T>({ name, readonly, alreadyExist }: Props<T>) { </div> </div> </Fragment> : <InputNumber<Entity> name="current" + label={i18n`Current`} side={ <button class="button is-danger" onClick={(): void => { valueHandler(undefined as any) }} > - <span>without stock</span> + <span><Translate>without stock</Translate></span> </button> } />} - <InputDate<Entity> name="nextRestock" withTimestampSupport /> + <InputDate<Entity> name="nextRestock" label={i18n`Next restock`} withTimestampSupport /> - <InputGroup<Entity> name="address"> + <InputGroup<Entity> name="address" label={i18n`Delivery address`}> - <Input name="address.country" /> + <Input name="address.country" label={i18n`Country`} /> <Input name="address.address_lines" inputType="multiline" + label={i18n`Address`} toStr={(v: string[] | undefined) => !v ? '' : v.join('\n')} fromStr={(v: string) => v.split('\n')} /> - <Input name="address.building_number" /> - <Input name="address.building_name" /> - <Input name="address.street" /> - <Input name="address.post_code" /> - <Input name="address.town_location" /> - <Input name="address.town" /> - <Input name="address.district" /> - <Input name="address.country_subdivision" /> + <Input name="address.building_number" label={i18n`Building number`} /> + <Input name="address.building_name" label={i18n`Building name`} /> + <Input name="address.street" label={i18n`Street`} /> + <Input name="address.post_code" label={i18n`Post code`} /> + <Input name="address.town_location" label={i18n`Town location`} /> + <Input name="address.town" label={i18n`Town`} /> + <Input name="address.district" label={i18n`District`} /> + <Input name="address.country_subdivision" label={i18n`Country subdivision`} /> </InputGroup> </FormProvider> </div> diff --git a/packages/frontend/src/components/form/InputTaxes.tsx b/packages/frontend/src/components/form/InputTaxes.tsx @@ -22,19 +22,19 @@ import { h, VNode } from "preact"; import { useCallback, useState } from "preact/hooks"; import * as yup from 'yup'; import { MerchantBackend } from "../../declaration"; +import { Translate, useTranslator } from "../../i18n"; import { TaxSchema as schema } from '../../schemas'; import { FormErrors, FormProvider } from "./FormProvider"; import { Input } from "./Input"; import { InputGroup } from "./InputGroup"; -import { useField } from "./useField"; +import { InputProps, useField } from "./useField"; -export interface Props<T> { - name: keyof T; - readonly?: boolean; +export interface Props<T> extends InputProps<T> { isValid?: (e: any) => boolean; } + type Entity = MerchantBackend.Tax -export function InputTaxes<T>({ name, readonly }: Props<T>): VNode { +export function InputTaxes<T>({ name, readonly, label }: Props<keyof T>): VNode { const { value: taxes, onChange, } = useField<T>(name); const [value, valueHandler] = useState<Partial<Entity>>({}) @@ -47,19 +47,22 @@ export function InputTaxes<T>({ name, readonly }: Props<T>): VNode { valueHandler({}) } catch (err) { const errors = err.inner as yup.ValidationError[] - const pathMessages = errors.reduce((prev, cur) => !cur.path ? prev : ({ ...prev, [cur.path]: { type: cur.type, params: cur.params, message: cur.message } }), {}) + const pathMessages = errors.reduce((prev, cur) => !cur.path ? prev : ({ ...prev, [cur.path]: cur.message }), {}) setErrors(pathMessages) } }, [value]) + const i18n = useTranslator() + + //FIXME: translating plural singular return ( - <InputGroup name="tax" alternative={taxes.length > 0 && <p>this product has {taxes.length} taxes</p>}> + <InputGroup name="tax" label={label} alternative={taxes.length > 0 && <p>this product has {taxes.length} taxes</p>}> <FormProvider<Entity> name="tax" errors={errors} object={value} valueHandler={valueHandler} > <div class="field is-horizontal"> <div class="field-label is-normal" /> <div class="field-body" style={{ display: 'block' }}> - {taxes.map((v: any, i:number) => <div key={i} class="tags has-addons mt-3 mb-0 mr-3" style={{ flexWrap: 'nowrap' }}> + {taxes.map((v: any, i: number) => <div key={i} class="tags has-addons mt-3 mb-0 mr-3" style={{ flexWrap: 'nowrap' }}> <span class="tag is-medium is-info mb-0" style={{ maxWidth: '90%' }}><b>{v.tax}</b>: {v.name}</span> <a class="tag is-medium is-danger is-delete mb-0" onClick={() => { onChange(taxes.filter((f: any) => f !== v) as any); @@ -67,21 +70,19 @@ export function InputTaxes<T>({ name, readonly }: Props<T>): VNode { }} /> </div> )} - {!taxes.length && 'this product has no taxes'} + {!taxes.length && i18n`this product has no taxes`} </div> </div> - <Input<Entity> name="tax" > - currency and value separated with colon <b>USD:2.3</b> + <Input<Entity> name="tax" label={i18n`Amount`}> + <Translate>currency and value separated with colon</Translate> <b>USD:2.3</b> </Input> - <Input<Entity> name="name" /> + <Input<Entity> name="name" label={i18n`Name`} /> <div class="buttons is-right mt-5"> - <button class="button is-info" onClick={submit}>add</button> + <button class="button is-info" onClick={submit}><Translate>Add</Translate></button> </div> - - </FormProvider> </InputGroup> ) diff --git a/packages/frontend/src/components/form/InputWithAddon.tsx b/packages/frontend/src/components/form/InputWithAddon.tsx @@ -19,12 +19,10 @@ * @author Sebastian Javier Marchano (sebasjm) */ import { ComponentChildren, h, VNode } from "preact"; -import { Message, useMessage } from "preact-messages"; -import { useField } from "./useField"; +import { useTranslator } from "../../i18n"; +import { InputProps, useField } from "./useField"; -export interface Props<T> { - name: keyof T; - readonly?: boolean; +export interface Props<T> extends InputProps<T> { expand?: boolean; inputType?: 'text' | 'number'; addonBefore?: ComponentChildren; @@ -36,19 +34,16 @@ export interface Props<T> { side?: ComponentChildren; } -const defaultToString = (f?: any):string => f || '' -const defaultFromString = (v: string):any => v as any +const defaultToString = (f?: any): string => f || '' +const defaultFromString = (v: string): any => v as any -export function InputWithAddon<T>({ name, readonly, addonBefore, children, expand, inputType, inputExtra, side, addonAfter, toStr = defaultToString, fromStr = defaultFromString }: Props<T>): VNode { - const { error, value, onChange, formName } = useField<T>(name); - - const placeholder = useMessage(`fields.${!formName ? 'instance' : formName}.${name}.placeholder`); - const tooltip = useMessage(`fields.${!formName ? 'instance' : formName}.${name}.tooltip`); +export function InputWithAddon<T>({ name, readonly, addonBefore, children, expand, label, placeholder, help, tooltip, inputType, inputExtra, side, addonAfter, toStr = defaultToString, fromStr = defaultFromString }: Props<keyof T>): VNode { + const { error, value, onChange } = useField<T>(name); return <div class="field is-horizontal"> <div class="field-label is-normal"> <label class="label"> - <Message id={`fields.${!formName ? 'instance' : formName}.${name}.label`} /> + {label} {tooltip && <span class="icon" data-tooltip={tooltip}> <i class="mdi mdi-information" /> </span>} @@ -60,21 +55,21 @@ export function InputWithAddon<T>({ name, readonly, addonBefore, children, expan {addonBefore && <div class="control"> <a class="button is-static">{addonBefore}</a> </div>} - <p class={ expand ? "control is-expanded" : "control" }> - <input {...(inputExtra||{})} class={error ? "input is-danger" : "input"} type={inputType} - placeholder={placeholder} readonly={readonly} + <p class={expand ? "control is-expanded" : "control"}> + <input {...(inputExtra || {})} class={error ? "input is-danger" : "input"} type={inputType} + placeholder={placeholder} readonly={readonly} name={String(name)} value={toStr(value)} onChange={(e): void => onChange(fromStr(e.currentTarget.value))} /> - <Message id={`fields.${!formName ? 'instance' : formName}.${name}.help`}> </Message> + {help} {children} </p> {addonAfter && <div class="control"> <a class="button is-static">{addonAfter}</a> </div>} </div> - {error ? <p class="help is-danger"><Message id={`validation.${error.type}`} fields={error.params}>{error.message}</Message></p> : null} + {error && <p class="help is-danger">{error}</p>} </div> - {side} + {side} </div> </div>; } diff --git a/packages/frontend/src/components/form/useField.tsx b/packages/frontend/src/components/form/useField.tsx @@ -19,11 +19,11 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { ValidationError } from "yup"; +import { VNode } from "preact"; import { useFormContext } from "./FormProvider"; interface Use<V> { - error?: ValidationError; + error?: string; value: any; formName: string; initial: any; @@ -73,3 +73,11 @@ const setValueDeeper = (object: any, names: string[], value: any): any => { return {...object, [head]: setValueDeeper(object[head] || {}, rest, value) } } +export interface InputProps<T> { + name: T; + label: string; + placeholder?: string; + tooltip?: string; + readonly?: boolean; + help?:VNode; +} +\ No newline at end of file diff --git a/packages/frontend/src/components/menu/LangSelector.tsx b/packages/frontend/src/components/menu/LangSelector.tsx @@ -14,11 +14,16 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ - import { h, VNode } from "preact"; +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +import { h, VNode } from "preact"; import { useState } from "preact/hooks"; import langIcon from '../../assets/icons/languageicon.svg'; -import { useBackendContext } from "../../context/backend"; -import * as messages from '../../messages'; +import { useTranslationContext } from "../../context/translation"; +import { strings as messages } from '../../i18n/strings' type LangsNames = { [P in keyof typeof messages]: string @@ -36,7 +41,7 @@ function getLangName(s: keyof LangsNames | string) { export function LangSelector(): VNode { const [updatingLang, setUpdatingLang] = useState(false) - const { lang, setLang } = useBackendContext() + const { lang, changeLanguage } = useTranslationContext() return <div class="dropdown is-active "> <div class="dropdown-trigger"> <button class="button" aria-haspopup="true" aria-controls="dropdown-menu" onClick={() => setUpdatingLang(!updatingLang)}> @@ -53,7 +58,7 @@ export function LangSelector(): VNode { <div class="dropdown-content"> {Object.keys(messages) .filter((l) => l !== lang) - .map(l => <a key={l} class="dropdown-item" value={l} onClick={() => { setLang(l); setUpdatingLang(false) }}>{getLangName(l)}</a>)} + .map(l => <a key={l} class="dropdown-item" value={l} onClick={() => { changeLanguage(l); setUpdatingLang(false) }}>{getLangName(l)}</a>)} </div> </div>} </div> diff --git a/packages/frontend/src/components/menu/SideBar.tsx b/packages/frontend/src/components/menu/SideBar.tsx @@ -21,7 +21,9 @@ import { Fragment, h, VNode } from 'preact'; -import { useBackendContext, useConfigContext } from '../../context/backend'; +import { useBackendContext } from '../../context/backend'; +import { useConfigContext } from '../../context/config'; +import { Translate } from '../../i18n'; import { LangSelector } from './LangSelector'; interface Props { @@ -47,32 +49,34 @@ export function Sidebar({ mobile, instance, onLogout, admin }: Props): VNode { </div> </div> <div class="menu is-menu-main"> - <p class="menu-label">Instance</p> + <p class="menu-label"> + <Translate>Instance</Translate> + </p> <ul class="menu-list"> <li> <a href="/update" class="has-icon"> <span class="icon"><i class="mdi mdi-square-edit-outline" /></span> - <span class="menu-item-label">Settings</span> + <span class="menu-item-label"><Translate>Settings</Translate></span> </a> </li> <li> <a href="/orders" class="has-icon"> <span class="icon"><i class="mdi mdi-cash-register" /></span> - <span class="menu-item-label">Orders</span> + <span class="menu-item-label"><Translate>Orders</Translate></span> </a> </li> <li> <a href="/products" class="has-icon"> <span class="icon"><i class="mdi mdi-shopping" /></span> - <span class="menu-item-label">Products</span> + <span class="menu-item-label"><Translate>Products</Translate></span> </a> </li> - {/* <li> + <li> <a href="/transfers" class="has-icon"> <span class="icon"><i class="mdi mdi-bank" /></span> - <span class="menu-item-label">Transfers</span> + <span class="menu-item-label"><Translate>Transfers</Translate></span> </a> - </li> */} + </li> {/* <li> <a href="/tips" class="has-icon"> <span class="icon"><i class="mdi mdi-cash" /></span> @@ -80,7 +84,7 @@ export function Sidebar({ mobile, instance, onLogout, admin }: Props): VNode { </a> </li> */} </ul> - <p class="menu-label">Connection</p> + <p class="menu-label"><Translate>Connection</Translate></p> <ul class="menu-list"> <li> <div> @@ -105,24 +109,24 @@ export function Sidebar({ mobile, instance, onLogout, admin }: Props): VNode { </div> </li> {admin && <Fragment> - <p class="menu-label">Instances</p> + <p class="menu-label"><Translate>Instances</Translate></p> <li> <a href="/instance/new" class="has-icon"> <span class="icon"><i class="mdi mdi-plus" /></span> - <span class="menu-item-label">New</span> + <span class="menu-item-label"><Translate>New</Translate></span> </a> </li> <li> <a href="/instances" class="has-icon"> <span class="icon"><i class="mdi mdi-format-list-bulleted" /></span> - <span class="menu-item-label">List</span> + <span class="menu-item-label"><Translate>List</Translate></span> </a> </li> </Fragment>} <li> <a class="has-icon is-state-info is-hoverable" onClick={(): void => onLogout()}> <span class="icon"><i class="mdi mdi-logout default" /></span> - <span class="menu-item-label">Log out</span> + <span class="menu-item-label"><Translate>Log out</Translate></span> </a> </li> </ul> diff --git a/packages/frontend/src/components/modal/index.tsx b/packages/frontend/src/components/modal/index.tsx @@ -21,8 +21,8 @@ import { ComponentChildren, h, VNode } from "preact"; -import { Message } from "preact-messages"; import { useState } from "preact/hooks"; +import { Translate, useTranslator } from "../../i18n"; import { FormProvider } from "../form/FormProvider"; import { Input } from "../form/Input"; @@ -41,16 +41,16 @@ export function ConfirmModal({ active, description, onCancel, onConfirm, childre <div class="modal-background " onClick={onCancel} /> <div class="modal-card"> <header class="modal-card-head"> - {!description ? null : <p class="modal-card-title"> <Message id={description} /></p>} + {!description ? null : <p class="modal-card-title">{description}</p>} <button class="delete " aria-label="close" onClick={onCancel} /> </header> <section class="modal-card-body"> {children} </section> <footer class="modal-card-foot"> - <div class="buttons is-right" style={{width: '100%'}}> - <button class="button " onClick={onCancel} ><Message id="Cancel" /></button> - <button class={danger ? "button is-danger " : "button is-info "} disabled={disabled} onClick={onConfirm} ><Message id="Confirm" /></button> + <div class="buttons is-right" style={{ width: '100%' }}> + <button class="button " onClick={onCancel} ><Translate>Cancel</Translate></button> + <button class={danger ? "button is-danger " : "button is-info "} disabled={disabled} onClick={onConfirm} ><Translate>Confirm</Translate></button> </div> </footer> </div> @@ -63,16 +63,16 @@ export function ClearConfirmModal({ description, onCancel, onClear, onConfirm, c <div class="modal-background " onClick={onCancel} /> <div class="modal-card"> <header class="modal-card-head"> - {!description ? null : <p class="modal-card-title"> <Message id={description} /></p>} + {!description ? null : <p class="modal-card-title">{description}</p>} <button class="delete " aria-label="close" onClick={onCancel} /> </header> <section class="modal-card-body"> {children} </section> <footer class="modal-card-foot"> - <button class="button " onClick={onCancel} ><Message id="Cancel" /></button> - <button class="button is-danger" onClick={onClear} disabled={disabled} ><Message id="Clear" /></button> - <button class="button is-info" onClick={onConfirm} disabled={disabled} ><Message id="Confirm" /></button> + <button class="button " onClick={onCancel} ><Translate>Cancel</Translate></button> + <button class="button is-danger" onClick={onClear} disabled={disabled} ><Translate>Clear</Translate></button> + <button class="button is-info" onClick={onConfirm} disabled={disabled} ><Translate>Confirm</Translate></button> </footer> </div> <button class="modal-close is-large " aria-label="close" onClick={onCancel} /> @@ -105,24 +105,26 @@ export function UpdateTokenModal({ element, onCancel, onClear, onConfirm, oldTok const [form, setValue] = useState<Partial<State>>({ old_token: '', new_token: '' }) - + const i18n = useTranslator() const errors = { - old_token: oldToken && oldToken !== form.old_token ? { message: 'should be the same' } : undefined, - new_token: !form.new_token ? { message: 'should be the same' } : (form.new_token === form.old_token ? { message: 'cant repeat' } : undefined), + old_token: oldToken && oldToken !== form.old_token ? i18n`should be the same` : undefined, + new_token: !form.new_token ? i18n`should be the same` : (form.new_token === form.old_token ? i18n`cannot be the same as before` : undefined), } + const text = i18n`You are updating the authorization token from instance ${element.name} with id ${element.id}` + return <ClearConfirmModal description="update_token" onCancel={onCancel} onConfirm={() => onConfirm(form.new_token!)} onClear={onClear} disabled={!!errors.new_token || !!errors.old_token} > - <p>You are updating the authorization token from instance {element.name} with id <b>{element.id}</b></p> + <p>{text}</p> <FormProvider errors={errors} object={form} valueHandler={setValue}> - <Input name="old_token" /> - <Input name="new_token" /> + <Input name="old_token" label={i18n`Old token`} /> + <Input name="new_token" label={i18n`New token`} /> </FormProvider> - <p>Clearing the auth token will mean public access to the instance</p> + <p><Translate>Clearing the auth token will mean public access to the instance</Translate></p> </ClearConfirmModal> } diff --git a/packages/frontend/src/components/product/ProductForm.tsx b/packages/frontend/src/components/product/ProductForm.tsx @@ -13,11 +13,18 @@ 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 { h } from "preact"; import { useCallback, useEffect, useState } from "preact/hooks"; import * as yup from 'yup'; import { useBackendContext } from "../../context/backend"; import { MerchantBackend } from "../../declaration"; +import { useTranslator } from "../../i18n"; import { ProductCreateSchema as createSchema, ProductUpdateSchema as updateSchema } from '../../schemas'; @@ -71,7 +78,7 @@ export function ProductForm({ onSubscribe, initial, alreadyExist, }: Props) { return value as MerchantBackend.Products.ProductDetail & { product_id: string } } catch (err) { const errors = err.inner as yup.ValidationError[] - const pathMessages = errors.reduce((prev, cur) => !cur.path ? prev : ({ ...prev, [cur.path]: { type: cur.type, params: cur.params, message: cur.message } }), {}) + const pathMessages = errors.reduce((prev, cur) => !cur.path ? prev : ({ ...prev, [cur.path]: cur.message }), {}) setErrors(pathMessages) } }, [value]) @@ -81,20 +88,21 @@ export function ProductForm({ onSubscribe, initial, alreadyExist, }: Props) { }, [submit]) const backend = useBackendContext(); + const i18n = useTranslator() return <div> <FormProvider<Entity> name="product" errors={errors} object={value} valueHandler={valueHandler} > - {alreadyExist ? undefined : <InputWithAddon<Entity> name="product_id" addonBefore={`${backend.url}/product/`} />} + {alreadyExist ? undefined : <InputWithAddon<Entity> name="product_id" addonBefore={`${backend.url}/product/`} label={i18n`ID`} />} - <InputImage<Entity> name="image" /> - <Input<Entity> name="description" inputType="multiline" /> - <Input<Entity> name="unit" /> - <InputCurrency<Entity> name="price" /> + <InputImage<Entity> name="image" label={i18n`Image`} /> + <Input<Entity> name="description" inputType="multiline" label={i18n`Description`} /> + <Input<Entity> name="unit" label={i18n`Unit`} /> + <InputCurrency<Entity> name="price" label={i18n`Price`} /> - <InputStock name="stock" alreadyExist={alreadyExist} /> + <InputStock name="stock" label={i18n`Stock`} alreadyExist={alreadyExist} /> - <InputTaxes<Entity> name="taxes" /> + <InputTaxes<Entity> name="taxes" label={i18n`Taxes`} /> </FormProvider> </div> diff --git a/packages/frontend/src/context/backend.ts b/packages/frontend/src/context/backend.ts @@ -13,10 +13,17 @@ 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 { createContext } from 'preact' -import { useContext } from 'preact/hooks' -export interface BackendContextType { +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +import { createContext, h, VNode } from 'preact' +import { useCallback, useContext, useState } from 'preact/hooks' +import { useBackendDefaultToken, useBackendURL } from '../hooks'; + +interface BackendContextType { url: string; token?: string; triedToLog: boolean; @@ -25,24 +32,10 @@ export interface BackendContextType { clearAllTokens: () => void; addTokenCleaner: (c: () => void) => void; updateToken: (token?:string) => void; - lang: string; - setLang: (lang: string) => void; -} - -export interface ConfigContextType { - currency: string; - version: string; -} - -export interface InstanceContextType { - id: string; - token?: string; - admin?: boolean; } const BackendContext = createContext<BackendContextType>({ url: '', - lang: 'en', token: undefined, triedToLog: false, changeBackend: () => null, @@ -50,17 +43,33 @@ const BackendContext = createContext<BackendContextType>({ clearAllTokens: () => null, addTokenCleaner: () => null, updateToken: () => null, - setLang: () => null, }) -const ConfigContext = createContext<ConfigContextType>(null!) +export function useBackendContextState(): BackendContextType { + const [url, triedToLog, changeBackend, resetBackend] = useBackendURL(); + const [token, updateToken] = useBackendDefaultToken(); -const InstanceContext = createContext<InstanceContextType>({} as any) + const tokenCleaner = useCallback(() => { updateToken(undefined) }, []) + const [cleaners, setCleaners] = useState([tokenCleaner]) + const addTokenCleaner = (c: () => void) => setCleaners(cs => [...cs, c]) + const addTokenCleanerMemo = useCallback((c: () => void) => { addTokenCleaner(c) }, [tokenCleaner]) -export const ConfigContextProvider = ConfigContext.Provider -export const useConfigContext = (): ConfigContextType => useContext(ConfigContext); -export const BackendContextProvider = BackendContext.Provider -export const useBackendContext = (): BackendContextType => useContext(BackendContext); -export const InstanceContextProvider = InstanceContext.Provider -export const useInstanceContext = (): InstanceContextType => useContext(InstanceContext); + const clearAllTokens = () => { + cleaners.forEach(c => c()) + for (let i = 0; i < localStorage.length; i++) { + const k = localStorage.key(i) + if (k && /^backend-token/.test(k)) localStorage.removeItem(k) + } + resetBackend() + } + + return { url, token, triedToLog, changeBackend, updateToken, resetBackend, clearAllTokens, addTokenCleaner: addTokenCleanerMemo } +} +export const BackendContextProvider = ({children}:{children:any}):VNode => { + const value = useBackendContextState() + + return h(BackendContext.Provider, {value, children}); +} + +export const useBackendContext = (): BackendContextType => useContext(BackendContext); diff --git a/packages/frontend/src/context/config.ts b/packages/frontend/src/context/config.ts @@ -0,0 +1,32 @@ +/* + 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 } from 'preact' +import { useContext } from 'preact/hooks' + +interface Type { + currency: string; + version: string; +} +const Context = createContext<Type>(null!) + +export const ConfigContextProvider = Context.Provider +export const useConfigContext = (): Type => useContext(Context); diff --git a/packages/frontend/src/context/instance.ts b/packages/frontend/src/context/instance.ts @@ -0,0 +1,34 @@ +/* + 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 } from 'preact' +import { useContext } from 'preact/hooks' + +interface Type { + id: string; + token?: string; + admin?: boolean; +} + +const Context = createContext<Type>({} as any) + +export const InstanceContextProvider = Context.Provider +export const useInstanceContext = (): Type => useContext(Context); diff --git a/packages/frontend/src/context/translation.ts b/packages/frontend/src/context/translation.ts @@ -0,0 +1,53 @@ +/* + 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 } from 'preact/hooks' +import { useLang } from '../hooks' +import * as jedLib from "jed"; +import { strings } from "../i18n/strings"; + +interface Type { + lang: string; + handler: any; + changeLanguage: (l: string) => void; +} +const initial = { + lang: 'en', + handler: null, + changeLanguage: () => { + // do not change anything + } +} +const Context = createContext<Type>(initial) + +interface Props { + initial?: string, + children: any, +} + +export const TranslationProvider = ({ initial, children }: Props): VNode => { + const [lang, changeLanguage] = useLang(initial) + const handler = new jedLib.Jed(strings[lang]); + return h(Context.Provider, { value: { lang, handler, changeLanguage }, children }); +} + +export const useTranslationContext = (): Type => useContext(Context); +\ No newline at end of file diff --git a/packages/frontend/src/custom.d.ts b/packages/frontend/src/custom.d.ts @@ -17,6 +17,10 @@ declare module '*.po' { const content: any; export default content; } +declare module 'jed' { + const x: any; + export = x; +} declare module "*.jpeg" { const content: any; export default content; diff --git a/packages/frontend/src/declaration.d.ts b/packages/frontend/src/declaration.d.ts @@ -328,6 +328,8 @@ export namespace MerchantBackend { // Merchant name corresponding to this instance. name: string; + deleted?: boolean; + // Merchant instance this response is about ($INSTANCE) id: string; diff --git a/packages/frontend/src/hooks/index.ts b/packages/frontend/src/hooks/index.ts @@ -20,32 +20,9 @@ */ import { StateUpdater, useCallback, useState } from "preact/hooks"; -import { BackendContextType } from "../context/backend"; import { ValueOrFunction } from '../utils/types'; -export function useBackendContextState(): BackendContextType { - const [lang, setLang] = useLang() - const [url, triedToLog, changeBackend, resetBackend] = useBackendURL(); - const [token, updateToken] = useBackendDefaultToken(); - - const tokenCleaner = useCallback(() => { updateToken(undefined) }, []) - const [cleaners, setCleaners] = useState([tokenCleaner]) - const addTokenCleaner = (c: () => void) => setCleaners(cs => [...cs, c]) - const addTokenCleanerMemo = useCallback((c: () => void) => { addTokenCleaner(c) }, [tokenCleaner]) - - const clearAllTokens = () => { - cleaners.forEach(c => c()) - for (let i = 0; i < localStorage.length; i++) { - const k = localStorage.key(i) - if (k && /^backend-token/.test(k)) localStorage.removeItem(k) - } - resetBackend() - } - - return { url, token, triedToLog, changeBackend, updateToken, lang, setLang, resetBackend, clearAllTokens, addTokenCleaner: addTokenCleanerMemo } -} - export const calculateRootPath = () => { const rootPath = typeof window !== undefined ? window.location.origin + window.location.pathname : '/' return rootPath @@ -82,9 +59,9 @@ export function useBackendInstanceToken(id: string): [string | undefined, StateU return [token, setToken] } -export function useLang(): [string, StateUpdater<string>] { +export function useLang(initial?:string): [string, StateUpdater<string>] { const browserLang = typeof window !== "undefined" ? navigator.language || (navigator as any).userLanguage : undefined; - const defaultLang = (browserLang || 'en').substring(0,2) + const defaultLang = (browserLang || initial || 'en').substring(0,2) return useNotNullLocalStorage('lang-preference', defaultLang) } diff --git a/packages/frontend/src/hooks/instance.ts b/packages/frontend/src/hooks/instance.ts @@ -14,9 +14,10 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ import { MerchantBackend } from '../declaration'; -import { useBackendContext, useInstanceContext } from '../context/backend'; +import { useBackendContext } from '../context/backend'; import { fetcher, HttpError, HttpResponse, HttpResponseOk, request, SwrError } from './backend'; import useSWR, { mutate } from 'swr'; +import { useInstanceContext } from '../context/instance'; interface InstanceAPI { diff --git a/packages/frontend/src/hooks/order.ts b/packages/frontend/src/hooks/order.ts @@ -15,7 +15,8 @@ */ import { useEffect, useState } from 'preact/hooks'; import useSWR from 'swr'; -import { useBackendContext, useInstanceContext } from '../context/backend'; +import { useBackendContext } from '../context/backend'; +import { useInstanceContext } from '../context/instance'; import { MerchantBackend } from '../declaration'; import { MAX_RESULT_SIZE, PAGE_SIZE } from '../utils/constants'; import { fetcher, HttpError, HttpResponse, HttpResponseOk, HttpResponsePaginated, mutateAll, request } from './backend'; diff --git a/packages/frontend/src/hooks/product.ts b/packages/frontend/src/hooks/product.ts @@ -15,7 +15,8 @@ */ import { useEffect } from 'preact/hooks'; import useSWR, { trigger, useSWRInfinite, cache, mutate } from 'swr'; -import { useBackendContext, useInstanceContext } from '../context/backend'; +import { useBackendContext } from '../context/backend'; +import { useInstanceContext } from '../context/instance'; import { MerchantBackend, WithId } from '../declaration'; import { fetcher, HttpError, HttpResponse, HttpResponseOk, mutateAll, request } from './backend'; @@ -133,7 +134,7 @@ export function useInstanceProducts(): HttpResponse<(MerchantBackend.Products.Pr const { data: list, error: listError, isValidating: listLoading } = useSWR<HttpResponseOk<MerchantBackend.Products.InventorySummaryResponse>, HttpError>([`/private/products`, token, url], fetcher); - const { data: products, error: productError, setSize } = useSWRInfinite<HttpResponseOk<MerchantBackend.Products.ProductDetail>, HttpError>((pageIndex: number) => { + const { data: products, error: productError, setSize, size } = useSWRInfinite<HttpResponseOk<MerchantBackend.Products.ProductDetail>, HttpError>((pageIndex: number) => { if (!list?.data || !list.data.products.length || listError || listLoading) return null return [`/private/products/${list.data.products[pageIndex].product_id}`, token, url] }, fetcher, { @@ -141,7 +142,6 @@ export function useInstanceProducts(): HttpResponse<(MerchantBackend.Products.Pr }) useEffect(() => { - if (listLoading) setSize(0) if (list?.data && list.data.products.length > 0) { setSize(list.data.products.length) } diff --git a/packages/frontend/src/hooks/tips.ts b/packages/frontend/src/hooks/tips.ts @@ -14,7 +14,8 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ import useSWR from 'swr'; -import { useBackendContext, useInstanceContext } from '../context/backend'; +import { useBackendContext } from '../context/backend'; +import { useInstanceContext } from '../context/instance'; import { MerchantBackend } from '../declaration'; import { fetcher, HttpError, HttpResponse, HttpResponseOk, mutateAll, request } from './backend'; diff --git a/packages/frontend/src/hooks/transfer.ts b/packages/frontend/src/hooks/transfer.ts @@ -14,9 +14,10 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ import { MerchantBackend } from '../declaration'; -import { useBackendContext, useInstanceContext } from '../context/backend'; +import { useBackendContext } from '../context/backend'; import { request, mutateAll, HttpResponse, HttpError, HttpResponseOk } from './backend'; import useSWR from 'swr'; +import { useInstanceContext } from '../context/instance'; async function transferFetcher<T>(url: string, token: string, backend: string): Promise<HttpResponseOk<T>> { return request<T>(`${backend}${url}`, { token, params: { payto_uri: '' } }) diff --git a/packages/frontend/src/i18n/de.po b/packages/frontend/src/i18n/de.po @@ -0,0 +1,1010 @@ +# This file is part of TALER +# (C) 2016 GNUnet e.V. +# +# 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. +# +# 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 +# TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Taler Wallet\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-11-23 00:00+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: src/ApplicationReadyRoutes.tsx:50 src/InstanceRoutes.tsx:117 +#: src/InstanceRoutes.tsx:293 +#, c-format +msgid "Access denied" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:51 src/InstanceRoutes.tsx:117 +#: src/InstanceRoutes.tsx:294 +#, c-format +msgid "Check your token is valid" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:72 +#, c-format +msgid "Couldn't access the server." +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:73 +#, c-format +msgid "Could not infer instance id from url %1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:108 +#, c-format +msgid "HTTP status #%1$s: Server reported a problem" +msgstr "" + +#: src/InstanceRoutes.tsx:109 +#, c-format +msgid "Got message: \"%1$s\" from: %2$s" +msgstr "" + +#: src/InstanceRoutes.tsx:126 +#, c-format +msgid "No default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:127 +#, c-format +msgid "" +"in order to use merchant backoffice, you should create the default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:282 +#, c-format +msgid "Server reported a problem: HTTP status #%1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:283 +#, c-format +msgid "Got message: %1$s from: %2$s" +msgstr "" + +#: src/components/exception/login.tsx:46 +#, c-format +msgid "Login required" +msgstr "" + +#: src/components/exception/login.tsx:49 +#, c-format +msgid "" +"Please enter your auth token. Token should have \"secret-token:\" and start " +"with Bearer or ApiKey" +msgstr "" + +#: src/components/exception/login.tsx:86 src/components/modal/index.tsx:53 +#: src/components/modal/index.tsx:75 src/paths/admin/create/CreatePage.tsx:140 +#: src/paths/instance/orders/create/CreatePage.tsx:337 +#: src/paths/instance/products/create/CreatePage.tsx:51 +#: src/paths/instance/products/list/Table.tsx:174 +#: src/paths/instance/products/list/Table.tsx:228 +#: src/paths/instance/products/update/UpdatePage.tsx:55 +#: src/paths/instance/update/UpdatePage.tsx:159 +#, c-format +msgid "Confirm" +msgstr "" + +#: src/components/form/InputArray.tsx:72 +#, c-format +msgid "The value %1$s is invalid for a payment url" +msgstr "" + +#: src/components/form/InputDate.tsx:67 +#: src/paths/instance/orders/list/index.tsx:123 +#, c-format +msgid "pick a date" +msgstr "" + +#: src/components/form/InputDate.tsx:81 +#, c-format +msgid "clear" +msgstr "" + +#: src/components/form/InputDate.tsx:83 +#, c-format +msgid "never" +msgstr "" + +#: src/components/form/InputImage.tsx:80 +#, c-format +msgid "Image should be smaller than 1 MB" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:59 +#, c-format +msgid "Product id" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:60 +#: src/components/product/ProductForm.tsx:99 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:122 +#: src/paths/instance/orders/list/Table.tsx:227 +#: src/paths/instance/products/list/Table.tsx:86 +#, c-format +msgid "Description" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:73 +#: src/components/form/InputTaxes.tsx:81 +#: src/paths/admin/create/CreatePage.tsx:86 src/paths/admin/list/Table.tsx:110 +#: src/paths/instance/details/DetailPage.tsx:76 +#: src/paths/instance/transfers/list/Table.tsx:112 +#: src/paths/instance/update/UpdatePage.tsx:105 +#, c-format +msgid "Name" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:102 +#, c-format +msgid "loading..." +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:108 +#, c-format +msgid "no products found" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:116 +#, c-format +msgid "no results" +msgstr "" + +#: src/components/form/InputSecured.tsx:33 +#, c-format +msgid "Deleting" +msgstr "" + +#: src/components/form/InputSecured.tsx:34 +#, c-format +msgid "Changing" +msgstr "" + +#: src/components/form/InputSecured.tsx:60 +#, c-format +msgid "Manage token" +msgstr "" + +#: src/components/form/InputSecured.tsx:83 +#, c-format +msgid "Update" +msgstr "" + +#: src/components/form/InputSecured.tsx:100 +#: src/paths/instance/orders/create/CreatePage.tsx:251 +#: src/paths/instance/orders/create/CreatePage.tsx:272 +#, c-format +msgid "Remove" +msgstr "" + +#: src/components/form/InputSecured.tsx:106 src/components/modal/index.tsx:52 +#: src/components/modal/index.tsx:73 src/paths/admin/create/CreatePage.tsx:139 +#: src/paths/instance/orders/create/CreatePage.tsx:336 +#: src/paths/instance/products/create/CreatePage.tsx:50 +#: src/paths/instance/products/list/Table.tsx:166 +#: src/paths/instance/products/list/Table.tsx:218 +#: src/paths/instance/products/update/UpdatePage.tsx:54 +#: src/paths/instance/update/UpdatePage.tsx:158 +#, c-format +msgid "Cancel" +msgstr "" + +#: src/components/form/InputStock.tsx:90 +#, c-format +msgid "Manage stock" +msgstr "" + +#: src/components/form/InputStock.tsx:92 +#, c-format +msgid "Infinite" +msgstr "" + +#: src/components/form/InputStock.tsx:104 +#, c-format +msgid "lost cannot be greater that current + incoming (max %1$s)" +msgstr "" + +#: src/components/form/InputStock.tsx:110 +#, c-format +msgid "current stock will change from %1$s to %2$s" +msgstr "" + +#: src/components/form/InputStock.tsx:111 +#, c-format +msgid "current stock will stay at %1$s" +msgstr "" + +#: src/components/form/InputStock.tsx:128 +#: src/paths/instance/products/list/Table.tsx:204 +#, c-format +msgid "Incoming" +msgstr "" + +#: src/components/form/InputStock.tsx:129 +#: src/paths/instance/products/list/Table.tsx:205 +#, c-format +msgid "Lost" +msgstr "" + +#: src/components/form/InputStock.tsx:141 +#, c-format +msgid "Current" +msgstr "" + +#: src/components/form/InputStock.tsx:144 +#, c-format +msgid "without stock" +msgstr "" + +#: src/components/form/InputStock.tsx:149 +#, c-format +msgid "Next restock" +msgstr "" + +#: src/components/form/InputStock.tsx:151 +#, c-format +msgid "Delivery address" +msgstr "" + +#: src/components/form/InputStock.tsx:153 +#: src/paths/admin/create/CreatePage.tsx:99 +#: src/paths/admin/create/CreatePage.tsx:116 +#: src/paths/instance/orders/create/CreatePage.tsx:308 +#: src/paths/instance/update/UpdatePage.tsx:118 +#: src/paths/instance/update/UpdatePage.tsx:135 +#, c-format +msgid "Country" +msgstr "" + +#: src/components/form/InputStock.tsx:156 +#: src/paths/admin/create/CreatePage.tsx:98 +#: src/paths/admin/create/CreatePage.tsx:101 +#: src/paths/admin/create/CreatePage.tsx:118 +#: src/paths/instance/orders/create/CreatePage.tsx:310 +#: src/paths/instance/update/UpdatePage.tsx:117 +#: src/paths/instance/update/UpdatePage.tsx:120 +#: src/paths/instance/update/UpdatePage.tsx:137 +#, c-format +msgid "Address" +msgstr "" + +#: src/components/form/InputStock.tsx:161 +#: src/paths/admin/create/CreatePage.tsx:105 +#: src/paths/admin/create/CreatePage.tsx:122 +#: src/paths/instance/orders/create/CreatePage.tsx:314 +#: src/paths/instance/update/UpdatePage.tsx:124 +#: src/paths/instance/update/UpdatePage.tsx:141 +#, c-format +msgid "Building number" +msgstr "" + +#: src/components/form/InputStock.tsx:162 +#: src/paths/admin/create/CreatePage.tsx:106 +#: src/paths/admin/create/CreatePage.tsx:123 +#: src/paths/instance/orders/create/CreatePage.tsx:315 +#: src/paths/instance/update/UpdatePage.tsx:125 +#: src/paths/instance/update/UpdatePage.tsx:142 +#, c-format +msgid "Building name" +msgstr "" + +#: src/components/form/InputStock.tsx:163 +#: src/paths/admin/create/CreatePage.tsx:107 +#: src/paths/admin/create/CreatePage.tsx:124 +#: src/paths/instance/orders/create/CreatePage.tsx:316 +#: src/paths/instance/update/UpdatePage.tsx:126 +#: src/paths/instance/update/UpdatePage.tsx:143 +#, c-format +msgid "Street" +msgstr "" + +#: src/components/form/InputStock.tsx:164 +#: src/paths/admin/create/CreatePage.tsx:108 +#: src/paths/admin/create/CreatePage.tsx:125 +#: src/paths/instance/orders/create/CreatePage.tsx:317 +#: src/paths/instance/update/UpdatePage.tsx:127 +#: src/paths/instance/update/UpdatePage.tsx:144 +#, c-format +msgid "Post code" +msgstr "" + +#: src/components/form/InputStock.tsx:165 +#: src/paths/admin/create/CreatePage.tsx:109 +#: src/paths/admin/create/CreatePage.tsx:126 +#: src/paths/instance/orders/create/CreatePage.tsx:318 +#: src/paths/instance/update/UpdatePage.tsx:128 +#: src/paths/instance/update/UpdatePage.tsx:145 +#, c-format +msgid "Town location" +msgstr "" + +#: src/components/form/InputStock.tsx:166 +#: src/paths/admin/create/CreatePage.tsx:110 +#: src/paths/admin/create/CreatePage.tsx:127 +#: src/paths/instance/orders/create/CreatePage.tsx:319 +#: src/paths/instance/update/UpdatePage.tsx:129 +#: src/paths/instance/update/UpdatePage.tsx:146 +#, c-format +msgid "Town" +msgstr "" + +#: src/components/form/InputStock.tsx:167 +#: src/paths/admin/create/CreatePage.tsx:111 +#: src/paths/admin/create/CreatePage.tsx:128 +#: src/paths/instance/orders/create/CreatePage.tsx:320 +#: src/paths/instance/update/UpdatePage.tsx:130 +#: src/paths/instance/update/UpdatePage.tsx:147 +#, c-format +msgid "District" +msgstr "" + +#: src/components/form/InputStock.tsx:168 +#: src/paths/admin/create/CreatePage.tsx:112 +#: src/paths/admin/create/CreatePage.tsx:129 +#: src/paths/instance/orders/create/CreatePage.tsx:321 +#: src/paths/instance/update/UpdatePage.tsx:131 +#: src/paths/instance/update/UpdatePage.tsx:148 +#, c-format +msgid "Country subdivision" +msgstr "" + +#: src/components/form/InputTaxes.tsx:73 +#, c-format +msgid "this product has no taxes" +msgstr "" + +#: src/components/form/InputTaxes.tsx:77 +#: src/paths/instance/orders/details/DetailPage.tsx:145 +#: src/paths/instance/orders/details/DetailPage.tsx:296 +#: src/paths/instance/orders/list/Table.tsx:116 +#, c-format +msgid "Amount" +msgstr "" + +#: src/components/form/InputTaxes.tsx:78 +#, c-format +msgid "currency and value separated with colon" +msgstr "" + +#: src/components/form/InputTaxes.tsx:84 +#: src/paths/instance/orders/create/InventoryProductForm.tsx:78 +#, c-format +msgid "Add" +msgstr "" + +#: src/components/menu/SideBar.tsx:53 +#, c-format +msgid "Instance" +msgstr "" + +#: src/components/menu/SideBar.tsx:59 +#, c-format +msgid "Settings" +msgstr "" + +#: src/components/menu/SideBar.tsx:65 +#: src/paths/instance/orders/list/Table.tsx:60 +#, c-format +msgid "Orders" +msgstr "" + +#: src/components/menu/SideBar.tsx:71 +#: src/paths/instance/orders/create/CreatePage.tsx:257 +#: src/paths/instance/products/list/Table.tsx:48 +#, c-format +msgid "Products" +msgstr "" + +#: src/components/menu/SideBar.tsx:77 +#: src/paths/instance/transfers/list/Table.tsx:59 +#, c-format +msgid "Transfers" +msgstr "" + +#: src/components/menu/SideBar.tsx:87 +#, c-format +msgid "Connection" +msgstr "" + +#: src/components/menu/SideBar.tsx:112 src/paths/admin/list/Table.tsx:57 +#, c-format +msgid "Instances" +msgstr "" + +#: src/components/menu/SideBar.tsx:116 +#, c-format +msgid "New" +msgstr "" + +#: src/components/menu/SideBar.tsx:122 +#, c-format +msgid "List" +msgstr "" + +#: src/components/menu/SideBar.tsx:129 +#, c-format +msgid "Log out" +msgstr "" + +#: src/components/modal/index.tsx:74 +#, c-format +msgid "Clear" +msgstr "" + +#: src/components/modal/index.tsx:110 src/components/modal/index.tsx:111 +#, c-format +msgid "should be the same" +msgstr "" + +#: src/components/modal/index.tsx:111 +#, c-format +msgid "cannot be the same as before" +msgstr "" + +#: src/components/modal/index.tsx:114 +#, c-format +msgid "" +"You are updating the authorization token from instance %1$s with id %2$s" +msgstr "" + +#: src/components/modal/index.tsx:124 +#, c-format +msgid "Old token" +msgstr "" + +#: src/components/modal/index.tsx:125 +#, c-format +msgid "New token" +msgstr "" + +#: src/components/modal/index.tsx:127 +#, c-format +msgid "Clearing the auth token will mean public access to the instance" +msgstr "" + +#: src/components/product/ProductForm.tsx:96 +#: src/paths/admin/create/CreatePage.tsx:84 src/paths/admin/list/Table.tsx:109 +#: src/paths/instance/transfers/list/Table.tsx:111 +#, c-format +msgid "ID" +msgstr "" + +#: src/components/product/ProductForm.tsx:98 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:121 +#: src/paths/instance/products/list/Table.tsx:85 +#, c-format +msgid "Image" +msgstr "" + +#: src/components/product/ProductForm.tsx:100 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:123 +#, c-format +msgid "Unit" +msgstr "" + +#: src/components/product/ProductForm.tsx:101 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:124 +#: src/paths/instance/products/list/Table.tsx:162 +#: src/paths/instance/products/list/Table.tsx:214 +#, c-format +msgid "Price" +msgstr "" + +#: src/components/product/ProductForm.tsx:103 +#: src/paths/instance/products/list/Table.tsx:90 +#, c-format +msgid "Stock" +msgstr "" + +#: src/components/product/ProductForm.tsx:105 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:128 +#: src/paths/instance/products/list/Table.tsx:88 +#, c-format +msgid "Taxes" +msgstr "" + +#: src/index.tsx:75 +#, c-format +msgid "Server not found" +msgstr "" + +#: src/index.tsx:85 +#, c-format +msgid "Couldn't access the server" +msgstr "" + +#: src/index.tsx:87 src/index.tsx:99 +#, c-format +msgid "Got message %1$s from %2$s" +msgstr "" + +#: src/index.tsx:97 +#, c-format +msgid "Unexpected Error" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:88 +#: src/paths/instance/update/UpdatePage.tsx:107 +#, c-format +msgid "Auth token" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:90 +#: src/paths/instance/details/DetailPage.tsx:77 +#: src/paths/instance/update/UpdatePage.tsx:109 +#, c-format +msgid "Account address" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:92 +#: src/paths/instance/update/UpdatePage.tsx:111 +#, c-format +msgid "Default max deposit fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:94 +#: src/paths/instance/update/UpdatePage.tsx:113 +#, c-format +msgid "Default max wire fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:96 +#: src/paths/instance/update/UpdatePage.tsx:115 +#, c-format +msgid "Default wire fee amortization" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:115 +#: src/paths/instance/update/UpdatePage.tsx:134 +#, c-format +msgid "Jurisdiction" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:132 +#: src/paths/instance/update/UpdatePage.tsx:151 +#, c-format +msgid "Default pay delay" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:134 +#: src/paths/instance/update/UpdatePage.tsx:153 +#, c-format +msgid "Default wire transfer delay" +msgstr "" + +#: src/paths/admin/create/index.tsx:58 +#, c-format +msgid "could not create instance" +msgstr "" + +#: src/paths/admin/list/Table.tsx:63 src/paths/admin/list/Table.tsx:131 +#, c-format +msgid "Delete" +msgstr "" + +#: src/paths/admin/list/Table.tsx:128 +#, c-format +msgid "Edit" +msgstr "" + +#: src/paths/admin/list/Table.tsx:149 +#: src/paths/instance/products/list/Table.tsx:245 +#, c-format +msgid "There is no instances yet, add more pressing the + sign" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:236 +#, c-format +msgid "Inventory products" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:285 +#, c-format +msgid "Total price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:286 +#, c-format +msgid "Total tax" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:288 +#: src/paths/instance/orders/create/CreatePage.tsx:296 +#, c-format +msgid "Order price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:294 +#, c-format +msgid "Net" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:299 +#: src/paths/instance/orders/details/DetailPage.tsx:144 +#: src/paths/instance/orders/details/DetailPage.tsx:295 +#: src/paths/instance/orders/list/Table.tsx:117 +#, c-format +msgid "Summary" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:301 +#, c-format +msgid "Payments options" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:302 +#, c-format +msgid "Auto refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:303 +#, c-format +msgid "Refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:304 +#, c-format +msgid "Pay deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:306 +#, c-format +msgid "Delivery date" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:307 +#, c-format +msgid "Location" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:324 +#, c-format +msgid "Max fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:325 +#, c-format +msgid "Max wire fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:326 +#, c-format +msgid "Wire fee amortization" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:327 +#, c-format +msgid "Fullfilment url" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:330 +#, c-format +msgid "Extra information" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:44 +#, c-format +msgid "select a product first" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:51 +#, c-format +msgid "should be greater than 0" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:58 +#, c-format +msgid "" +"cannot be greater than current stock and quantity previously added. max: %1$s" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:64 +#, c-format +msgid "cannot be greater than current stock %1$s" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:76 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:126 +#, c-format +msgid "Quantity" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:92 +#: src/paths/instance/orders/details/DetailPage.tsx:235 +#: src/paths/instance/orders/details/DetailPage.tsx:333 +#, c-format +msgid "Order" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:93 +#, c-format +msgid "claimed" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:110 +#: src/paths/instance/orders/details/DetailPage.tsx:261 +#: src/paths/instance/orders/list/Table.tsx:136 +#, c-format +msgid "copy url" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:126 +#: src/paths/instance/orders/details/DetailPage.tsx:349 +#, c-format +msgid "pay at" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:127 +#: src/paths/instance/orders/details/DetailPage.tsx:350 +#, c-format +msgid "created at" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:138 +#: src/paths/instance/orders/details/DetailPage.tsx:289 +#, c-format +msgid "Timeline" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:142 +#: src/paths/instance/orders/details/DetailPage.tsx:293 +#, c-format +msgid "Payment details" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:146 +#: src/paths/instance/orders/details/DetailPage.tsx:299 +#: src/paths/instance/orders/details/DetailPage.tsx:363 +#, c-format +msgid "Order status" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:156 +#: src/paths/instance/orders/details/DetailPage.tsx:308 +#, c-format +msgid "Product list" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:236 +#, c-format +msgid "paid" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:238 +#, c-format +msgid "wired" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:241 +#, c-format +msgid "refunded" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:258 +#, c-format +msgid "refund" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:297 +#, c-format +msgid "Refunded amount" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:298 +#, c-format +msgid "Deposit total" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:336 +#, c-format +msgid "unpaid" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:364 +#, c-format +msgid "Order status URL" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:365 +#, c-format +msgid "Pay URI" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:383 +#, c-format +msgid "" +"Unknown order status. This is an error, please contact the administrator." +msgstr "" + +#: src/paths/instance/orders/details/index.tsx:56 +#: src/paths/instance/orders/list/index.tsx:147 +#, c-format +msgid "refund created successfully" +msgstr "" + +#: src/paths/instance/orders/details/index.tsx:59 +#: src/paths/instance/orders/list/index.tsx:150 +#, c-format +msgid "could not create the refund" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:111 +#, c-format +msgid "load newer orders" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:115 +#, c-format +msgid "Date" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:131 +#: src/paths/instance/orders/list/Table.tsx:223 +#, c-format +msgid "Refund" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:145 +#, c-format +msgid "load older orders" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:154 +#, c-format +msgid "No orders has been found" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:202 +#, c-format +msgid "date" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:203 +#, c-format +msgid "amount" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:204 +#, c-format +msgid "reason" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:224 +#, c-format +msgid "Max refundable:" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "Reason" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "duplicated" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "requested by the customer" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "other" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:91 +#, c-format +msgid "go to order id" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:107 +#, c-format +msgid "Paid" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:108 +#, c-format +msgid "Refunded" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:109 +#, c-format +msgid "Not wired" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:110 +#, c-format +msgid "All" +msgstr "" + +#: src/paths/instance/products/create/index.tsx:48 +#: src/paths/instance/products/update/index.tsx:64 +#, c-format +msgid "could not create product" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:87 +#, c-format +msgid "Sell" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:89 +#, c-format +msgid "Profit" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:91 +#, c-format +msgid "Sold" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:59 +#, c-format +msgid "product updated successfully" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:62 +#, c-format +msgid "could not update the product" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:70 +#, c-format +msgid "product delete successfully" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:73 +#, c-format +msgid "could not delete the product" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:59 +#, c-format +msgid "Tips" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:111 +#, c-format +msgid "Committed amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:112 +#, c-format +msgid "Exchange initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:113 +#, c-format +msgid "Merchant initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:148 +#, c-format +msgid "There is no tips yet, add more pressing the + sign" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:147 +#, c-format +msgid "There is no transfer yet, add more pressing the + sign" +msgstr "" diff --git a/packages/frontend/src/i18n/en.po b/packages/frontend/src/i18n/en.po @@ -0,0 +1,1010 @@ +# This file is part of TALER +# (C) 2016 GNUnet e.V. +# +# 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. +# +# 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 +# TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Taler Wallet\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-11-23 00:00+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: src/ApplicationReadyRoutes.tsx:50 src/InstanceRoutes.tsx:117 +#: src/InstanceRoutes.tsx:293 +#, c-format +msgid "Access denied" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:51 src/InstanceRoutes.tsx:117 +#: src/InstanceRoutes.tsx:294 +#, c-format +msgid "Check your token is valid" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:72 +#, c-format +msgid "Couldn't access the server." +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:73 +#, c-format +msgid "Could not infer instance id from url %1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:108 +#, c-format +msgid "HTTP status #%1$s: Server reported a problem" +msgstr "" + +#: src/InstanceRoutes.tsx:109 +#, c-format +msgid "Got message: \"%1$s\" from: %2$s" +msgstr "" + +#: src/InstanceRoutes.tsx:126 +#, c-format +msgid "No default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:127 +#, c-format +msgid "" +"in order to use merchant backoffice, you should create the default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:282 +#, c-format +msgid "Server reported a problem: HTTP status #%1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:283 +#, c-format +msgid "Got message: %1$s from: %2$s" +msgstr "" + +#: src/components/exception/login.tsx:46 +#, c-format +msgid "Login required" +msgstr "" + +#: src/components/exception/login.tsx:49 +#, c-format +msgid "" +"Please enter your auth token. Token should have \"secret-token:\" and start " +"with Bearer or ApiKey" +msgstr "" + +#: src/components/exception/login.tsx:86 src/components/modal/index.tsx:53 +#: src/components/modal/index.tsx:75 src/paths/admin/create/CreatePage.tsx:140 +#: src/paths/instance/orders/create/CreatePage.tsx:337 +#: src/paths/instance/products/create/CreatePage.tsx:51 +#: src/paths/instance/products/list/Table.tsx:174 +#: src/paths/instance/products/list/Table.tsx:228 +#: src/paths/instance/products/update/UpdatePage.tsx:55 +#: src/paths/instance/update/UpdatePage.tsx:159 +#, c-format +msgid "Confirm" +msgstr "" + +#: src/components/form/InputArray.tsx:72 +#, c-format +msgid "The value %1$s is invalid for a payment url" +msgstr "" + +#: src/components/form/InputDate.tsx:67 +#: src/paths/instance/orders/list/index.tsx:123 +#, c-format +msgid "pick a date" +msgstr "" + +#: src/components/form/InputDate.tsx:81 +#, c-format +msgid "clear" +msgstr "" + +#: src/components/form/InputDate.tsx:83 +#, c-format +msgid "never" +msgstr "" + +#: src/components/form/InputImage.tsx:80 +#, c-format +msgid "Image should be smaller than 1 MB" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:59 +#, c-format +msgid "Product id" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:60 +#: src/components/product/ProductForm.tsx:99 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:122 +#: src/paths/instance/orders/list/Table.tsx:227 +#: src/paths/instance/products/list/Table.tsx:86 +#, c-format +msgid "Description" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:73 +#: src/components/form/InputTaxes.tsx:81 +#: src/paths/admin/create/CreatePage.tsx:86 src/paths/admin/list/Table.tsx:110 +#: src/paths/instance/details/DetailPage.tsx:76 +#: src/paths/instance/transfers/list/Table.tsx:112 +#: src/paths/instance/update/UpdatePage.tsx:105 +#, c-format +msgid "Name" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:102 +#, c-format +msgid "loading..." +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:108 +#, c-format +msgid "no products found" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:116 +#, c-format +msgid "no results" +msgstr "" + +#: src/components/form/InputSecured.tsx:33 +#, c-format +msgid "Deleting" +msgstr "" + +#: src/components/form/InputSecured.tsx:34 +#, c-format +msgid "Changing" +msgstr "" + +#: src/components/form/InputSecured.tsx:60 +#, c-format +msgid "Manage token" +msgstr "" + +#: src/components/form/InputSecured.tsx:83 +#, c-format +msgid "Update" +msgstr "" + +#: src/components/form/InputSecured.tsx:100 +#: src/paths/instance/orders/create/CreatePage.tsx:251 +#: src/paths/instance/orders/create/CreatePage.tsx:272 +#, c-format +msgid "Remove" +msgstr "" + +#: src/components/form/InputSecured.tsx:106 src/components/modal/index.tsx:52 +#: src/components/modal/index.tsx:73 src/paths/admin/create/CreatePage.tsx:139 +#: src/paths/instance/orders/create/CreatePage.tsx:336 +#: src/paths/instance/products/create/CreatePage.tsx:50 +#: src/paths/instance/products/list/Table.tsx:166 +#: src/paths/instance/products/list/Table.tsx:218 +#: src/paths/instance/products/update/UpdatePage.tsx:54 +#: src/paths/instance/update/UpdatePage.tsx:158 +#, c-format +msgid "Cancel" +msgstr "" + +#: src/components/form/InputStock.tsx:90 +#, c-format +msgid "Manage stock" +msgstr "" + +#: src/components/form/InputStock.tsx:92 +#, c-format +msgid "Infinite" +msgstr "" + +#: src/components/form/InputStock.tsx:104 +#, c-format +msgid "lost cannot be greater that current + incoming (max %1$s)" +msgstr "" + +#: src/components/form/InputStock.tsx:110 +#, c-format +msgid "current stock will change from %1$s to %2$s" +msgstr "" + +#: src/components/form/InputStock.tsx:111 +#, c-format +msgid "current stock will stay at %1$s" +msgstr "" + +#: src/components/form/InputStock.tsx:128 +#: src/paths/instance/products/list/Table.tsx:204 +#, c-format +msgid "Incoming" +msgstr "" + +#: src/components/form/InputStock.tsx:129 +#: src/paths/instance/products/list/Table.tsx:205 +#, c-format +msgid "Lost" +msgstr "" + +#: src/components/form/InputStock.tsx:141 +#, c-format +msgid "Current" +msgstr "" + +#: src/components/form/InputStock.tsx:144 +#, c-format +msgid "without stock" +msgstr "" + +#: src/components/form/InputStock.tsx:149 +#, c-format +msgid "Next restock" +msgstr "" + +#: src/components/form/InputStock.tsx:151 +#, c-format +msgid "Delivery address" +msgstr "" + +#: src/components/form/InputStock.tsx:153 +#: src/paths/admin/create/CreatePage.tsx:99 +#: src/paths/admin/create/CreatePage.tsx:116 +#: src/paths/instance/orders/create/CreatePage.tsx:308 +#: src/paths/instance/update/UpdatePage.tsx:118 +#: src/paths/instance/update/UpdatePage.tsx:135 +#, c-format +msgid "Country" +msgstr "" + +#: src/components/form/InputStock.tsx:156 +#: src/paths/admin/create/CreatePage.tsx:98 +#: src/paths/admin/create/CreatePage.tsx:101 +#: src/paths/admin/create/CreatePage.tsx:118 +#: src/paths/instance/orders/create/CreatePage.tsx:310 +#: src/paths/instance/update/UpdatePage.tsx:117 +#: src/paths/instance/update/UpdatePage.tsx:120 +#: src/paths/instance/update/UpdatePage.tsx:137 +#, c-format +msgid "Address" +msgstr "" + +#: src/components/form/InputStock.tsx:161 +#: src/paths/admin/create/CreatePage.tsx:105 +#: src/paths/admin/create/CreatePage.tsx:122 +#: src/paths/instance/orders/create/CreatePage.tsx:314 +#: src/paths/instance/update/UpdatePage.tsx:124 +#: src/paths/instance/update/UpdatePage.tsx:141 +#, c-format +msgid "Building number" +msgstr "" + +#: src/components/form/InputStock.tsx:162 +#: src/paths/admin/create/CreatePage.tsx:106 +#: src/paths/admin/create/CreatePage.tsx:123 +#: src/paths/instance/orders/create/CreatePage.tsx:315 +#: src/paths/instance/update/UpdatePage.tsx:125 +#: src/paths/instance/update/UpdatePage.tsx:142 +#, c-format +msgid "Building name" +msgstr "" + +#: src/components/form/InputStock.tsx:163 +#: src/paths/admin/create/CreatePage.tsx:107 +#: src/paths/admin/create/CreatePage.tsx:124 +#: src/paths/instance/orders/create/CreatePage.tsx:316 +#: src/paths/instance/update/UpdatePage.tsx:126 +#: src/paths/instance/update/UpdatePage.tsx:143 +#, c-format +msgid "Street" +msgstr "" + +#: src/components/form/InputStock.tsx:164 +#: src/paths/admin/create/CreatePage.tsx:108 +#: src/paths/admin/create/CreatePage.tsx:125 +#: src/paths/instance/orders/create/CreatePage.tsx:317 +#: src/paths/instance/update/UpdatePage.tsx:127 +#: src/paths/instance/update/UpdatePage.tsx:144 +#, c-format +msgid "Post code" +msgstr "" + +#: src/components/form/InputStock.tsx:165 +#: src/paths/admin/create/CreatePage.tsx:109 +#: src/paths/admin/create/CreatePage.tsx:126 +#: src/paths/instance/orders/create/CreatePage.tsx:318 +#: src/paths/instance/update/UpdatePage.tsx:128 +#: src/paths/instance/update/UpdatePage.tsx:145 +#, c-format +msgid "Town location" +msgstr "" + +#: src/components/form/InputStock.tsx:166 +#: src/paths/admin/create/CreatePage.tsx:110 +#: src/paths/admin/create/CreatePage.tsx:127 +#: src/paths/instance/orders/create/CreatePage.tsx:319 +#: src/paths/instance/update/UpdatePage.tsx:129 +#: src/paths/instance/update/UpdatePage.tsx:146 +#, c-format +msgid "Town" +msgstr "" + +#: src/components/form/InputStock.tsx:167 +#: src/paths/admin/create/CreatePage.tsx:111 +#: src/paths/admin/create/CreatePage.tsx:128 +#: src/paths/instance/orders/create/CreatePage.tsx:320 +#: src/paths/instance/update/UpdatePage.tsx:130 +#: src/paths/instance/update/UpdatePage.tsx:147 +#, c-format +msgid "District" +msgstr "" + +#: src/components/form/InputStock.tsx:168 +#: src/paths/admin/create/CreatePage.tsx:112 +#: src/paths/admin/create/CreatePage.tsx:129 +#: src/paths/instance/orders/create/CreatePage.tsx:321 +#: src/paths/instance/update/UpdatePage.tsx:131 +#: src/paths/instance/update/UpdatePage.tsx:148 +#, c-format +msgid "Country subdivision" +msgstr "" + +#: src/components/form/InputTaxes.tsx:73 +#, c-format +msgid "this product has no taxes" +msgstr "" + +#: src/components/form/InputTaxes.tsx:77 +#: src/paths/instance/orders/details/DetailPage.tsx:145 +#: src/paths/instance/orders/details/DetailPage.tsx:296 +#: src/paths/instance/orders/list/Table.tsx:116 +#, c-format +msgid "Amount" +msgstr "" + +#: src/components/form/InputTaxes.tsx:78 +#, c-format +msgid "currency and value separated with colon" +msgstr "" + +#: src/components/form/InputTaxes.tsx:84 +#: src/paths/instance/orders/create/InventoryProductForm.tsx:78 +#, c-format +msgid "Add" +msgstr "" + +#: src/components/menu/SideBar.tsx:53 +#, c-format +msgid "Instance" +msgstr "" + +#: src/components/menu/SideBar.tsx:59 +#, c-format +msgid "Settings" +msgstr "" + +#: src/components/menu/SideBar.tsx:65 +#: src/paths/instance/orders/list/Table.tsx:60 +#, c-format +msgid "Orders" +msgstr "" + +#: src/components/menu/SideBar.tsx:71 +#: src/paths/instance/orders/create/CreatePage.tsx:257 +#: src/paths/instance/products/list/Table.tsx:48 +#, c-format +msgid "Products" +msgstr "" + +#: src/components/menu/SideBar.tsx:77 +#: src/paths/instance/transfers/list/Table.tsx:59 +#, c-format +msgid "Transfers" +msgstr "" + +#: src/components/menu/SideBar.tsx:87 +#, c-format +msgid "Connection" +msgstr "" + +#: src/components/menu/SideBar.tsx:112 src/paths/admin/list/Table.tsx:57 +#, c-format +msgid "Instances" +msgstr "" + +#: src/components/menu/SideBar.tsx:116 +#, c-format +msgid "New" +msgstr "" + +#: src/components/menu/SideBar.tsx:122 +#, c-format +msgid "List" +msgstr "" + +#: src/components/menu/SideBar.tsx:129 +#, c-format +msgid "Log out" +msgstr "" + +#: src/components/modal/index.tsx:74 +#, c-format +msgid "Clear" +msgstr "" + +#: src/components/modal/index.tsx:110 src/components/modal/index.tsx:111 +#, c-format +msgid "should be the same" +msgstr "" + +#: src/components/modal/index.tsx:111 +#, c-format +msgid "cannot be the same as before" +msgstr "" + +#: src/components/modal/index.tsx:114 +#, c-format +msgid "" +"You are updating the authorization token from instance %1$s with id %2$s" +msgstr "" + +#: src/components/modal/index.tsx:124 +#, c-format +msgid "Old token" +msgstr "" + +#: src/components/modal/index.tsx:125 +#, c-format +msgid "New token" +msgstr "" + +#: src/components/modal/index.tsx:127 +#, c-format +msgid "Clearing the auth token will mean public access to the instance" +msgstr "" + +#: src/components/product/ProductForm.tsx:96 +#: src/paths/admin/create/CreatePage.tsx:84 src/paths/admin/list/Table.tsx:109 +#: src/paths/instance/transfers/list/Table.tsx:111 +#, c-format +msgid "ID" +msgstr "" + +#: src/components/product/ProductForm.tsx:98 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:121 +#: src/paths/instance/products/list/Table.tsx:85 +#, c-format +msgid "Image" +msgstr "" + +#: src/components/product/ProductForm.tsx:100 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:123 +#, c-format +msgid "Unit" +msgstr "" + +#: src/components/product/ProductForm.tsx:101 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:124 +#: src/paths/instance/products/list/Table.tsx:162 +#: src/paths/instance/products/list/Table.tsx:214 +#, c-format +msgid "Price" +msgstr "" + +#: src/components/product/ProductForm.tsx:103 +#: src/paths/instance/products/list/Table.tsx:90 +#, c-format +msgid "Stock" +msgstr "" + +#: src/components/product/ProductForm.tsx:105 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:128 +#: src/paths/instance/products/list/Table.tsx:88 +#, c-format +msgid "Taxes" +msgstr "" + +#: src/index.tsx:75 +#, c-format +msgid "Server not found" +msgstr "" + +#: src/index.tsx:85 +#, c-format +msgid "Couldn't access the server" +msgstr "" + +#: src/index.tsx:87 src/index.tsx:99 +#, c-format +msgid "Got message %1$s from %2$s" +msgstr "" + +#: src/index.tsx:97 +#, c-format +msgid "Unexpected Error" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:88 +#: src/paths/instance/update/UpdatePage.tsx:107 +#, c-format +msgid "Auth token" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:90 +#: src/paths/instance/details/DetailPage.tsx:77 +#: src/paths/instance/update/UpdatePage.tsx:109 +#, c-format +msgid "Account address" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:92 +#: src/paths/instance/update/UpdatePage.tsx:111 +#, c-format +msgid "Default max deposit fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:94 +#: src/paths/instance/update/UpdatePage.tsx:113 +#, c-format +msgid "Default max wire fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:96 +#: src/paths/instance/update/UpdatePage.tsx:115 +#, c-format +msgid "Default wire fee amortization" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:115 +#: src/paths/instance/update/UpdatePage.tsx:134 +#, c-format +msgid "Jurisdiction" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:132 +#: src/paths/instance/update/UpdatePage.tsx:151 +#, c-format +msgid "Default pay delay" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:134 +#: src/paths/instance/update/UpdatePage.tsx:153 +#, c-format +msgid "Default wire transfer delay" +msgstr "" + +#: src/paths/admin/create/index.tsx:58 +#, c-format +msgid "could not create instance" +msgstr "" + +#: src/paths/admin/list/Table.tsx:63 src/paths/admin/list/Table.tsx:131 +#, c-format +msgid "Delete" +msgstr "" + +#: src/paths/admin/list/Table.tsx:128 +#, c-format +msgid "Edit" +msgstr "" + +#: src/paths/admin/list/Table.tsx:149 +#: src/paths/instance/products/list/Table.tsx:245 +#, c-format +msgid "There is no instances yet, add more pressing the + sign" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:236 +#, c-format +msgid "Inventory products" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:285 +#, c-format +msgid "Total price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:286 +#, c-format +msgid "Total tax" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:288 +#: src/paths/instance/orders/create/CreatePage.tsx:296 +#, c-format +msgid "Order price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:294 +#, c-format +msgid "Net" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:299 +#: src/paths/instance/orders/details/DetailPage.tsx:144 +#: src/paths/instance/orders/details/DetailPage.tsx:295 +#: src/paths/instance/orders/list/Table.tsx:117 +#, c-format +msgid "Summary" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:301 +#, c-format +msgid "Payments options" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:302 +#, c-format +msgid "Auto refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:303 +#, c-format +msgid "Refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:304 +#, c-format +msgid "Pay deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:306 +#, c-format +msgid "Delivery date" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:307 +#, c-format +msgid "Location" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:324 +#, c-format +msgid "Max fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:325 +#, c-format +msgid "Max wire fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:326 +#, c-format +msgid "Wire fee amortization" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:327 +#, c-format +msgid "Fullfilment url" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:330 +#, c-format +msgid "Extra information" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:44 +#, c-format +msgid "select a product first" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:51 +#, c-format +msgid "should be greater than 0" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:58 +#, c-format +msgid "" +"cannot be greater than current stock and quantity previously added. max: %1$s" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:64 +#, c-format +msgid "cannot be greater than current stock %1$s" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:76 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:126 +#, c-format +msgid "Quantity" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:92 +#: src/paths/instance/orders/details/DetailPage.tsx:235 +#: src/paths/instance/orders/details/DetailPage.tsx:333 +#, c-format +msgid "Order" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:93 +#, c-format +msgid "claimed" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:110 +#: src/paths/instance/orders/details/DetailPage.tsx:261 +#: src/paths/instance/orders/list/Table.tsx:136 +#, c-format +msgid "copy url" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:126 +#: src/paths/instance/orders/details/DetailPage.tsx:349 +#, c-format +msgid "pay at" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:127 +#: src/paths/instance/orders/details/DetailPage.tsx:350 +#, c-format +msgid "created at" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:138 +#: src/paths/instance/orders/details/DetailPage.tsx:289 +#, c-format +msgid "Timeline" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:142 +#: src/paths/instance/orders/details/DetailPage.tsx:293 +#, c-format +msgid "Payment details" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:146 +#: src/paths/instance/orders/details/DetailPage.tsx:299 +#: src/paths/instance/orders/details/DetailPage.tsx:363 +#, c-format +msgid "Order status" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:156 +#: src/paths/instance/orders/details/DetailPage.tsx:308 +#, c-format +msgid "Product list" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:236 +#, c-format +msgid "paid" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:238 +#, c-format +msgid "wired" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:241 +#, c-format +msgid "refunded" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:258 +#, c-format +msgid "refund" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:297 +#, c-format +msgid "Refunded amount" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:298 +#, c-format +msgid "Deposit total" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:336 +#, c-format +msgid "unpaid" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:364 +#, c-format +msgid "Order status URL" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:365 +#, c-format +msgid "Pay URI" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:383 +#, c-format +msgid "" +"Unknown order status. This is an error, please contact the administrator." +msgstr "" + +#: src/paths/instance/orders/details/index.tsx:56 +#: src/paths/instance/orders/list/index.tsx:147 +#, c-format +msgid "refund created successfully" +msgstr "" + +#: src/paths/instance/orders/details/index.tsx:59 +#: src/paths/instance/orders/list/index.tsx:150 +#, c-format +msgid "could not create the refund" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:111 +#, c-format +msgid "load newer orders" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:115 +#, c-format +msgid "Date" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:131 +#: src/paths/instance/orders/list/Table.tsx:223 +#, c-format +msgid "Refund" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:145 +#, c-format +msgid "load older orders" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:154 +#, c-format +msgid "No orders has been found" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:202 +#, c-format +msgid "date" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:203 +#, c-format +msgid "amount" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:204 +#, c-format +msgid "reason" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:224 +#, c-format +msgid "Max refundable:" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "Reason" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "duplicated" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "requested by the customer" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "other" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:91 +#, c-format +msgid "go to order id" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:107 +#, c-format +msgid "Paid" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:108 +#, c-format +msgid "Refunded" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:109 +#, c-format +msgid "Not wired" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:110 +#, c-format +msgid "All" +msgstr "" + +#: src/paths/instance/products/create/index.tsx:48 +#: src/paths/instance/products/update/index.tsx:64 +#, c-format +msgid "could not create product" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:87 +#, c-format +msgid "Sell" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:89 +#, c-format +msgid "Profit" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:91 +#, c-format +msgid "Sold" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:59 +#, c-format +msgid "product updated successfully" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:62 +#, c-format +msgid "could not update the product" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:70 +#, c-format +msgid "product delete successfully" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:73 +#, c-format +msgid "could not delete the product" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:59 +#, c-format +msgid "Tips" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:111 +#, c-format +msgid "Committed amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:112 +#, c-format +msgid "Exchange initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:113 +#, c-format +msgid "Merchant initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:148 +#, c-format +msgid "There is no tips yet, add more pressing the + sign" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:147 +#, c-format +msgid "There is no transfer yet, add more pressing the + sign" +msgstr "" diff --git a/packages/frontend/src/i18n/es.po b/packages/frontend/src/i18n/es.po @@ -0,0 +1,1018 @@ +# This file is part of TALER +# (C) 2016 GNUnet e.V. +# +# 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. +# +# 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 +# TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Taler Wallet\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-11-23 00:00+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: src/ApplicationReadyRoutes.tsx:50 src/InstanceRoutes.tsx:117 +#: src/InstanceRoutes.tsx:293 +#, c-format +msgid "Access denied" +msgstr "Acceso denegado" + +#: src/ApplicationReadyRoutes.tsx:51 src/InstanceRoutes.tsx:117 +#: src/InstanceRoutes.tsx:294 +#, c-format +msgid "Check your token is valid" +msgstr "Verifica que el token sea valido" + +#: src/ApplicationReadyRoutes.tsx:72 +#, c-format +msgid "Couldn't access the server." +msgstr "No se pudo acceder al servidor" + +#: src/ApplicationReadyRoutes.tsx:73 +#, c-format +msgid "Could not infer instance id from url %1$s" +msgstr "No se pudo inferir el id de la instancia con la url %1$s" + +#: src/InstanceRoutes.tsx:108 +#, c-format +msgid "HTTP status #%1$s: Server reported a problem" +msgstr "HTTP status #%1$s: Servidor reporto un problema" + +#: src/InstanceRoutes.tsx:109 +#, fuzzy, c-format +msgid "Got message: \"%1$s\" from: %2$s" +msgstr "Recivimos el mensaje %1$s desde %2$s" + +#: src/InstanceRoutes.tsx:126 +#, c-format +msgid "No default instance" +msgstr "Sin instancia default" + +#: src/InstanceRoutes.tsx:127 +#, c-format +msgid "" +"in order to use merchant backoffice, you should create the default instance" +msgstr "para usar el merchant backoffice, deberÃa crear la instancia default" + +#: src/InstanceRoutes.tsx:282 +#, c-format +msgid "Server reported a problem: HTTP status #%1$s" +msgstr "Servidir reporto un problema: HTTP status #%1$s" + +#: src/InstanceRoutes.tsx:283 +#, fuzzy, c-format +msgid "Got message: %1$s from: %2$s" +msgstr "Recivimos el mensaje %1$s desde %2$s" + +#: src/components/exception/login.tsx:46 +#, c-format +msgid "Login required" +msgstr "Login necesario" + +#: src/components/exception/login.tsx:49 +#, c-format +msgid "" +"Please enter your auth token. Token should have \"secret-token:\" and start " +"with Bearer or ApiKey" +msgstr "" +"Por favor ingrese su token de autorización. El token debe tener \"secret-" +"token\" y comenzar con Bearer o ApiKey" + +#: src/components/exception/login.tsx:86 src/components/modal/index.tsx:53 +#: src/components/modal/index.tsx:75 src/paths/admin/create/CreatePage.tsx:140 +#: src/paths/instance/orders/create/CreatePage.tsx:337 +#: src/paths/instance/products/create/CreatePage.tsx:51 +#: src/paths/instance/products/list/Table.tsx:174 +#: src/paths/instance/products/list/Table.tsx:228 +#: src/paths/instance/products/update/UpdatePage.tsx:55 +#: src/paths/instance/update/UpdatePage.tsx:159 +#, c-format +msgid "Confirm" +msgstr "Confirmar" + +#: src/components/form/InputArray.tsx:72 +#, c-format +msgid "The value %1$s is invalid for a payment url" +msgstr "El valor %1$s es invalido para una URL de pago" + +#: src/components/form/InputDate.tsx:67 +#: src/paths/instance/orders/list/index.tsx:123 +#, c-format +msgid "pick a date" +msgstr "elegir una fecha" + +#: src/components/form/InputDate.tsx:81 +#, fuzzy, c-format +msgid "clear" +msgstr "Limpiar" + +#: src/components/form/InputDate.tsx:83 +#, c-format +msgid "never" +msgstr "nunca" + +#: src/components/form/InputImage.tsx:80 +#, c-format +msgid "Image should be smaller than 1 MB" +msgstr "La imagen debe ser mas chica que 1 MB" + +#: src/components/form/InputSearchProduct.tsx:59 +#, fuzzy, c-format +msgid "Product id" +msgstr "Id de producto" + +#: src/components/form/InputSearchProduct.tsx:60 +#: src/components/product/ProductForm.tsx:99 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:122 +#: src/paths/instance/orders/list/Table.tsx:227 +#: src/paths/instance/products/list/Table.tsx:86 +#, c-format +msgid "Description" +msgstr "Descripcion" + +#: src/components/form/InputSearchProduct.tsx:73 +#: src/components/form/InputTaxes.tsx:81 +#: src/paths/admin/create/CreatePage.tsx:86 src/paths/admin/list/Table.tsx:110 +#: src/paths/instance/details/DetailPage.tsx:76 +#: src/paths/instance/transfers/list/Table.tsx:112 +#: src/paths/instance/update/UpdatePage.tsx:105 +#, c-format +msgid "Name" +msgstr "Nombre" + +#: src/components/form/InputSearchProduct.tsx:102 +#, c-format +msgid "loading..." +msgstr "Cargando..." + +#: src/components/form/InputSearchProduct.tsx:108 +#, c-format +msgid "no products found" +msgstr "No se encontraron productos" + +#: src/components/form/InputSearchProduct.tsx:116 +#, c-format +msgid "no results" +msgstr "Sin resultados" + +#: src/components/form/InputSecured.tsx:33 +#, c-format +msgid "Deleting" +msgstr "Borrando" + +#: src/components/form/InputSecured.tsx:34 +#, c-format +msgid "Changing" +msgstr "Cambiando" + +#: src/components/form/InputSecured.tsx:60 +#, c-format +msgid "Manage token" +msgstr "Administrar token" + +#: src/components/form/InputSecured.tsx:83 +#, c-format +msgid "Update" +msgstr "Actualizar" + +#: src/components/form/InputSecured.tsx:100 +#: src/paths/instance/orders/create/CreatePage.tsx:251 +#: src/paths/instance/orders/create/CreatePage.tsx:272 +#, c-format +msgid "Remove" +msgstr "Eliminar" + +#: src/components/form/InputSecured.tsx:106 src/components/modal/index.tsx:52 +#: src/components/modal/index.tsx:73 src/paths/admin/create/CreatePage.tsx:139 +#: src/paths/instance/orders/create/CreatePage.tsx:336 +#: src/paths/instance/products/create/CreatePage.tsx:50 +#: src/paths/instance/products/list/Table.tsx:166 +#: src/paths/instance/products/list/Table.tsx:218 +#: src/paths/instance/products/update/UpdatePage.tsx:54 +#: src/paths/instance/update/UpdatePage.tsx:158 +#, c-format +msgid "Cancel" +msgstr "Cancelar" + +#: src/components/form/InputStock.tsx:90 +#, c-format +msgid "Manage stock" +msgstr "Administrar stock" + +#: src/components/form/InputStock.tsx:92 +#, c-format +msgid "Infinite" +msgstr "Inifinito" + +#: src/components/form/InputStock.tsx:104 +#, fuzzy, c-format +msgid "lost cannot be greater that current + incoming (max %1$s)" +msgstr "no puede ser mayor al stock actual %1$s" + +#: src/components/form/InputStock.tsx:110 +#, c-format +msgid "current stock will change from %1$s to %2$s" +msgstr "stock actual cambiará desde %1$s a %2$s" + +#: src/components/form/InputStock.tsx:111 +#, c-format +msgid "current stock will stay at %1$s" +msgstr "stock actual seguirá en %1$s" + +#: src/components/form/InputStock.tsx:128 +#: src/paths/instance/products/list/Table.tsx:204 +#, c-format +msgid "Incoming" +msgstr "Ingresando" + +#: src/components/form/InputStock.tsx:129 +#: src/paths/instance/products/list/Table.tsx:205 +#, c-format +msgid "Lost" +msgstr "Perdido" + +#: src/components/form/InputStock.tsx:141 +#, c-format +msgid "Current" +msgstr "Actual" + +#: src/components/form/InputStock.tsx:144 +#, c-format +msgid "without stock" +msgstr "sin stock" + +#: src/components/form/InputStock.tsx:149 +#, c-format +msgid "Next restock" +msgstr "Próximo reabastecimiento" + +#: src/components/form/InputStock.tsx:151 +#, c-format +msgid "Delivery address" +msgstr "Dirección de entrega" + +#: src/components/form/InputStock.tsx:153 +#: src/paths/admin/create/CreatePage.tsx:99 +#: src/paths/admin/create/CreatePage.tsx:116 +#: src/paths/instance/orders/create/CreatePage.tsx:308 +#: src/paths/instance/update/UpdatePage.tsx:118 +#: src/paths/instance/update/UpdatePage.tsx:135 +#, c-format +msgid "Country" +msgstr "PaÃs" + +#: src/components/form/InputStock.tsx:156 +#: src/paths/admin/create/CreatePage.tsx:98 +#: src/paths/admin/create/CreatePage.tsx:101 +#: src/paths/admin/create/CreatePage.tsx:118 +#: src/paths/instance/orders/create/CreatePage.tsx:310 +#: src/paths/instance/update/UpdatePage.tsx:117 +#: src/paths/instance/update/UpdatePage.tsx:120 +#: src/paths/instance/update/UpdatePage.tsx:137 +#, c-format +msgid "Address" +msgstr "Dirección" + +#: src/components/form/InputStock.tsx:161 +#: src/paths/admin/create/CreatePage.tsx:105 +#: src/paths/admin/create/CreatePage.tsx:122 +#: src/paths/instance/orders/create/CreatePage.tsx:314 +#: src/paths/instance/update/UpdatePage.tsx:124 +#: src/paths/instance/update/UpdatePage.tsx:141 +#, c-format +msgid "Building number" +msgstr "Número de edificio" + +#: src/components/form/InputStock.tsx:162 +#: src/paths/admin/create/CreatePage.tsx:106 +#: src/paths/admin/create/CreatePage.tsx:123 +#: src/paths/instance/orders/create/CreatePage.tsx:315 +#: src/paths/instance/update/UpdatePage.tsx:125 +#: src/paths/instance/update/UpdatePage.tsx:142 +#, c-format +msgid "Building name" +msgstr "Nombre de edificio" + +#: src/components/form/InputStock.tsx:163 +#: src/paths/admin/create/CreatePage.tsx:107 +#: src/paths/admin/create/CreatePage.tsx:124 +#: src/paths/instance/orders/create/CreatePage.tsx:316 +#: src/paths/instance/update/UpdatePage.tsx:126 +#: src/paths/instance/update/UpdatePage.tsx:143 +#, c-format +msgid "Street" +msgstr "Calle" + +#: src/components/form/InputStock.tsx:164 +#: src/paths/admin/create/CreatePage.tsx:108 +#: src/paths/admin/create/CreatePage.tsx:125 +#: src/paths/instance/orders/create/CreatePage.tsx:317 +#: src/paths/instance/update/UpdatePage.tsx:127 +#: src/paths/instance/update/UpdatePage.tsx:144 +#, c-format +msgid "Post code" +msgstr "Código postal" + +#: src/components/form/InputStock.tsx:165 +#: src/paths/admin/create/CreatePage.tsx:109 +#: src/paths/admin/create/CreatePage.tsx:126 +#: src/paths/instance/orders/create/CreatePage.tsx:318 +#: src/paths/instance/update/UpdatePage.tsx:128 +#: src/paths/instance/update/UpdatePage.tsx:145 +#, fuzzy, c-format +msgid "Town location" +msgstr "Ubicación de ciudad" + +#: src/components/form/InputStock.tsx:166 +#: src/paths/admin/create/CreatePage.tsx:110 +#: src/paths/admin/create/CreatePage.tsx:127 +#: src/paths/instance/orders/create/CreatePage.tsx:319 +#: src/paths/instance/update/UpdatePage.tsx:129 +#: src/paths/instance/update/UpdatePage.tsx:146 +#, c-format +msgid "Town" +msgstr "Ciudad" + +#: src/components/form/InputStock.tsx:167 +#: src/paths/admin/create/CreatePage.tsx:111 +#: src/paths/admin/create/CreatePage.tsx:128 +#: src/paths/instance/orders/create/CreatePage.tsx:320 +#: src/paths/instance/update/UpdatePage.tsx:130 +#: src/paths/instance/update/UpdatePage.tsx:147 +#, c-format +msgid "District" +msgstr "Distrito" + +#: src/components/form/InputStock.tsx:168 +#: src/paths/admin/create/CreatePage.tsx:112 +#: src/paths/admin/create/CreatePage.tsx:129 +#: src/paths/instance/orders/create/CreatePage.tsx:321 +#: src/paths/instance/update/UpdatePage.tsx:131 +#: src/paths/instance/update/UpdatePage.tsx:148 +#, c-format +msgid "Country subdivision" +msgstr "Provincia" + +#: src/components/form/InputTaxes.tsx:73 +#, c-format +msgid "this product has no taxes" +msgstr "este producto no tiene impuestos" + +#: src/components/form/InputTaxes.tsx:77 +#: src/paths/instance/orders/details/DetailPage.tsx:145 +#: src/paths/instance/orders/details/DetailPage.tsx:296 +#: src/paths/instance/orders/list/Table.tsx:116 +#, c-format +msgid "Amount" +msgstr "Monto" + +#: src/components/form/InputTaxes.tsx:78 +#, c-format +msgid "currency and value separated with colon" +msgstr "Moneda y valor separado por dos puntos" + +#: src/components/form/InputTaxes.tsx:84 +#: src/paths/instance/orders/create/InventoryProductForm.tsx:78 +#, c-format +msgid "Add" +msgstr "Agregar" + +#: src/components/menu/SideBar.tsx:53 +#, c-format +msgid "Instance" +msgstr "Instancia" + +#: src/components/menu/SideBar.tsx:59 +#, c-format +msgid "Settings" +msgstr "Configuración" + +#: src/components/menu/SideBar.tsx:65 +#: src/paths/instance/orders/list/Table.tsx:60 +#, fuzzy, c-format +msgid "Orders" +msgstr "Ordenes" + +#: src/components/menu/SideBar.tsx:71 +#: src/paths/instance/orders/create/CreatePage.tsx:257 +#: src/paths/instance/products/list/Table.tsx:48 +#, c-format +msgid "Products" +msgstr "Productos" + +#: src/components/menu/SideBar.tsx:77 +#: src/paths/instance/transfers/list/Table.tsx:59 +#, c-format +msgid "Transfers" +msgstr "Transferencias" + +#: src/components/menu/SideBar.tsx:87 +#, fuzzy, c-format +msgid "Connection" +msgstr "Conexión" + +#: src/components/menu/SideBar.tsx:112 src/paths/admin/list/Table.tsx:57 +#, c-format +msgid "Instances" +msgstr "Instancias" + +#: src/components/menu/SideBar.tsx:116 +#, fuzzy, c-format +msgid "New" +msgstr "Nuevo" + +#: src/components/menu/SideBar.tsx:122 +#, c-format +msgid "List" +msgstr "Lista" + +#: src/components/menu/SideBar.tsx:129 +#, c-format +msgid "Log out" +msgstr "Salir" + +#: src/components/modal/index.tsx:74 +#, c-format +msgid "Clear" +msgstr "Limpiar" + +#: src/components/modal/index.tsx:110 src/components/modal/index.tsx:111 +#, c-format +msgid "should be the same" +msgstr "deberÃan ser iguales" + +#: src/components/modal/index.tsx:111 +#, c-format +msgid "cannot be the same as before" +msgstr "no puede ser igual al anterior" + +#: src/components/modal/index.tsx:114 +#, c-format +msgid "" +"You are updating the authorization token from instance %1$s with id %2$s" +msgstr "" +"Está actualizando el token de autorización para la instancia %1$s con id %2$s" + +#: src/components/modal/index.tsx:124 +#, c-format +msgid "Old token" +msgstr "Viejo token" + +#: src/components/modal/index.tsx:125 +#, c-format +msgid "New token" +msgstr "Nuevo token" + +#: src/components/modal/index.tsx:127 +#, c-format +msgid "Clearing the auth token will mean public access to the instance" +msgstr "" +"Limpiar el token de autorización significa acceso publico a la instancia" + +#: src/components/product/ProductForm.tsx:96 +#: src/paths/admin/create/CreatePage.tsx:84 src/paths/admin/list/Table.tsx:109 +#: src/paths/instance/transfers/list/Table.tsx:111 +#, c-format +msgid "ID" +msgstr "ID" + +#: src/components/product/ProductForm.tsx:98 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:121 +#: src/paths/instance/products/list/Table.tsx:85 +#, c-format +msgid "Image" +msgstr "Imagen" + +#: src/components/product/ProductForm.tsx:100 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:123 +#, c-format +msgid "Unit" +msgstr "Unidad" + +#: src/components/product/ProductForm.tsx:101 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:124 +#: src/paths/instance/products/list/Table.tsx:162 +#: src/paths/instance/products/list/Table.tsx:214 +#, c-format +msgid "Price" +msgstr "Precio" + +#: src/components/product/ProductForm.tsx:103 +#: src/paths/instance/products/list/Table.tsx:90 +#, c-format +msgid "Stock" +msgstr "Stock" + +#: src/components/product/ProductForm.tsx:105 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:128 +#: src/paths/instance/products/list/Table.tsx:88 +#, c-format +msgid "Taxes" +msgstr "Impuesto" + +#: src/index.tsx:75 +#, c-format +msgid "Server not found" +msgstr "Servidor no encontrado" + +#: src/index.tsx:85 +#, c-format +msgid "Couldn't access the server" +msgstr "No se pudo aceder al servidor" + +#: src/index.tsx:87 src/index.tsx:99 +#, c-format +msgid "Got message %1$s from %2$s" +msgstr "Recivimos el mensaje %1$s desde %2$s" + +#: src/index.tsx:97 +#, c-format +msgid "Unexpected Error" +msgstr "Error inesperado" + +#: src/paths/admin/create/CreatePage.tsx:88 +#: src/paths/instance/update/UpdatePage.tsx:107 +#, c-format +msgid "Auth token" +msgstr "Token de autorización" + +#: src/paths/admin/create/CreatePage.tsx:90 +#: src/paths/instance/details/DetailPage.tsx:77 +#: src/paths/instance/update/UpdatePage.tsx:109 +#, c-format +msgid "Account address" +msgstr "Dirección de cuenta" + +#: src/paths/admin/create/CreatePage.tsx:92 +#: src/paths/instance/update/UpdatePage.tsx:111 +#, c-format +msgid "Default max deposit fee" +msgstr "Impuesto máximo de deposito por omisión" + +#: src/paths/admin/create/CreatePage.tsx:94 +#: src/paths/instance/update/UpdatePage.tsx:113 +#, c-format +msgid "Default max wire fee" +msgstr "Impuesto máximo de transferencia por omisión" + +#: src/paths/admin/create/CreatePage.tsx:96 +#: src/paths/instance/update/UpdatePage.tsx:115 +#, c-format +msgid "Default wire fee amortization" +msgstr "Amortización de impuesto de transferencia por omisión" + +#: src/paths/admin/create/CreatePage.tsx:115 +#: src/paths/instance/update/UpdatePage.tsx:134 +#, c-format +msgid "Jurisdiction" +msgstr "Jurisdicción" + +#: src/paths/admin/create/CreatePage.tsx:132 +#: src/paths/instance/update/UpdatePage.tsx:151 +#, c-format +msgid "Default pay delay" +msgstr "Retrazo de pago por omisión" + +#: src/paths/admin/create/CreatePage.tsx:134 +#: src/paths/instance/update/UpdatePage.tsx:153 +#, c-format +msgid "Default wire transfer delay" +msgstr "Retrazo de transferencia por omisión" + +#: src/paths/admin/create/index.tsx:58 +#, c-format +msgid "could not create instance" +msgstr "no se pudo crear la instancia" + +#: src/paths/admin/list/Table.tsx:63 src/paths/admin/list/Table.tsx:131 +#, fuzzy, c-format +msgid "Delete" +msgstr "Borrando" + +#: src/paths/admin/list/Table.tsx:128 +#, c-format +msgid "Edit" +msgstr "" + +#: src/paths/admin/list/Table.tsx:149 +#: src/paths/instance/products/list/Table.tsx:245 +#, c-format +msgid "There is no instances yet, add more pressing the + sign" +msgstr "No hay instancias todavÃan, agregue mas presionando el signo +" + +#: src/paths/instance/orders/create/CreatePage.tsx:236 +#, c-format +msgid "Inventory products" +msgstr "Productos de inventario" + +#: src/paths/instance/orders/create/CreatePage.tsx:285 +#, c-format +msgid "Total price" +msgstr "Precio total" + +#: src/paths/instance/orders/create/CreatePage.tsx:286 +#, c-format +msgid "Total tax" +msgstr "Impuesto total" + +#: src/paths/instance/orders/create/CreatePage.tsx:288 +#: src/paths/instance/orders/create/CreatePage.tsx:296 +#, c-format +msgid "Order price" +msgstr "Precio de la orden" + +#: src/paths/instance/orders/create/CreatePage.tsx:294 +#, fuzzy, c-format +msgid "Net" +msgstr "Neto" + +#: src/paths/instance/orders/create/CreatePage.tsx:299 +#: src/paths/instance/orders/details/DetailPage.tsx:144 +#: src/paths/instance/orders/details/DetailPage.tsx:295 +#: src/paths/instance/orders/list/Table.tsx:117 +#, c-format +msgid "Summary" +msgstr "Resumen" + +#: src/paths/instance/orders/create/CreatePage.tsx:301 +#, c-format +msgid "Payments options" +msgstr "Opciones de pago" + +#: src/paths/instance/orders/create/CreatePage.tsx:302 +#, c-format +msgid "Auto refund deadline" +msgstr "Plazo de reembolso automático" + +#: src/paths/instance/orders/create/CreatePage.tsx:303 +#, c-format +msgid "Refund deadline" +msgstr "Plazo de reembolso" + +#: src/paths/instance/orders/create/CreatePage.tsx:304 +#, c-format +msgid "Pay deadline" +msgstr "Plazo de pago" + +#: src/paths/instance/orders/create/CreatePage.tsx:306 +#, c-format +msgid "Delivery date" +msgstr "Fecha de entrega" + +#: src/paths/instance/orders/create/CreatePage.tsx:307 +#, fuzzy, c-format +msgid "Location" +msgstr "Ubicación" + +#: src/paths/instance/orders/create/CreatePage.tsx:324 +#, c-format +msgid "Max fee" +msgstr "Impuesto máximo" + +#: src/paths/instance/orders/create/CreatePage.tsx:325 +#, c-format +msgid "Max wire fee" +msgstr "Impuesto de transferencia máximo" + +#: src/paths/instance/orders/create/CreatePage.tsx:326 +#, c-format +msgid "Wire fee amortization" +msgstr "Amortización de impuesto de transferencia" + +#: src/paths/instance/orders/create/CreatePage.tsx:327 +#, c-format +msgid "Fullfilment url" +msgstr "URL de completitud" + +#: src/paths/instance/orders/create/CreatePage.tsx:330 +#, c-format +msgid "Extra information" +msgstr "Información extra" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:44 +#, c-format +msgid "select a product first" +msgstr "seleccione un producto primero" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:51 +#, fuzzy, c-format +msgid "should be greater than 0" +msgstr "La imagen debe ser mas chica que 1 MB" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:58 +#, c-format +msgid "" +"cannot be greater than current stock and quantity previously added. max: %1$s" +msgstr "" +"no puede ser mayor al stock actual y la cantidad previamente agregada. " +"máximo: %1$s" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:64 +#, c-format +msgid "cannot be greater than current stock %1$s" +msgstr "no puede ser mayor al stock actual %1$s" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:76 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:126 +#, c-format +msgid "Quantity" +msgstr "Cantidad" + +#: src/paths/instance/orders/details/DetailPage.tsx:92 +#: src/paths/instance/orders/details/DetailPage.tsx:235 +#: src/paths/instance/orders/details/DetailPage.tsx:333 +#, c-format +msgid "Order" +msgstr "Orden" + +#: src/paths/instance/orders/details/DetailPage.tsx:93 +#, c-format +msgid "claimed" +msgstr "reclamado" + +#: src/paths/instance/orders/details/DetailPage.tsx:110 +#: src/paths/instance/orders/details/DetailPage.tsx:261 +#: src/paths/instance/orders/list/Table.tsx:136 +#, c-format +msgid "copy url" +msgstr "copiar url" + +#: src/paths/instance/orders/details/DetailPage.tsx:126 +#: src/paths/instance/orders/details/DetailPage.tsx:349 +#, c-format +msgid "pay at" +msgstr "pagar en" + +#: src/paths/instance/orders/details/DetailPage.tsx:127 +#: src/paths/instance/orders/details/DetailPage.tsx:350 +#, c-format +msgid "created at" +msgstr "creado" + +#: src/paths/instance/orders/details/DetailPage.tsx:138 +#: src/paths/instance/orders/details/DetailPage.tsx:289 +#, c-format +msgid "Timeline" +msgstr "CronologÃa" + +#: src/paths/instance/orders/details/DetailPage.tsx:142 +#: src/paths/instance/orders/details/DetailPage.tsx:293 +#, c-format +msgid "Payment details" +msgstr "Detalles de pago" + +#: src/paths/instance/orders/details/DetailPage.tsx:146 +#: src/paths/instance/orders/details/DetailPage.tsx:299 +#: src/paths/instance/orders/details/DetailPage.tsx:363 +#, fuzzy, c-format +msgid "Order status" +msgstr "Estado de orden" + +#: src/paths/instance/orders/details/DetailPage.tsx:156 +#: src/paths/instance/orders/details/DetailPage.tsx:308 +#, fuzzy, c-format +msgid "Product list" +msgstr "Lista de producto" + +#: src/paths/instance/orders/details/DetailPage.tsx:236 +#, c-format +msgid "paid" +msgstr "pagados" + +#: src/paths/instance/orders/details/DetailPage.tsx:238 +#, c-format +msgid "wired" +msgstr "transferido" + +#: src/paths/instance/orders/details/DetailPage.tsx:241 +#, c-format +msgid "refunded" +msgstr "reembolzado" + +#: src/paths/instance/orders/details/DetailPage.tsx:258 +#, c-format +msgid "refund" +msgstr "reembolzar" + +#: src/paths/instance/orders/details/DetailPage.tsx:297 +#, c-format +msgid "Refunded amount" +msgstr "Monto reembolzado" + +#: src/paths/instance/orders/details/DetailPage.tsx:298 +#, c-format +msgid "Deposit total" +msgstr "Total depositado" + +#: src/paths/instance/orders/details/DetailPage.tsx:336 +#, c-format +msgid "unpaid" +msgstr "impago" + +#: src/paths/instance/orders/details/DetailPage.tsx:364 +#, c-format +msgid "Order status URL" +msgstr "URL de estado de orden" + +#: src/paths/instance/orders/details/DetailPage.tsx:365 +#, c-format +msgid "Pay URI" +msgstr "URI de pago" + +#: src/paths/instance/orders/details/DetailPage.tsx:383 +#, c-format +msgid "" +"Unknown order status. This is an error, please contact the administrator." +msgstr "" +"Estado de orden desconocido. Esto es un error, por favor contacte a su " +"administrador" + +#: src/paths/instance/orders/details/index.tsx:56 +#: src/paths/instance/orders/list/index.tsx:147 +#, c-format +msgid "refund created successfully" +msgstr "reembolzo creado satisfactoriamente" + +#: src/paths/instance/orders/details/index.tsx:59 +#: src/paths/instance/orders/list/index.tsx:150 +#, fuzzy, c-format +msgid "could not create the refund" +msgstr "No se pudo aceder al servidor" + +#: src/paths/instance/orders/list/Table.tsx:111 +#, c-format +msgid "load newer orders" +msgstr "cargar nuevas ordenes" + +#: src/paths/instance/orders/list/Table.tsx:115 +#, c-format +msgid "Date" +msgstr "Fecha" + +#: src/paths/instance/orders/list/Table.tsx:131 +#: src/paths/instance/orders/list/Table.tsx:223 +#, c-format +msgid "Refund" +msgstr "Reembolzar" + +#: src/paths/instance/orders/list/Table.tsx:145 +#, c-format +msgid "load older orders" +msgstr "cargar viejas ordenes" + +#: src/paths/instance/orders/list/Table.tsx:154 +#, c-format +msgid "No orders has been found" +msgstr "No se enconraron ordenes" + +#: src/paths/instance/orders/list/Table.tsx:202 +#, c-format +msgid "date" +msgstr "fecha" + +#: src/paths/instance/orders/list/Table.tsx:203 +#, c-format +msgid "amount" +msgstr "monto" + +#: src/paths/instance/orders/list/Table.tsx:204 +#, c-format +msgid "reason" +msgstr "razón" + +#: src/paths/instance/orders/list/Table.tsx:224 +#, c-format +msgid "Max refundable:" +msgstr "Máximo reembolzable:" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "Reason" +msgstr "Razón" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "duplicated" +msgstr "duplicado" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "requested by the customer" +msgstr "pedido por el consumidor" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "other" +msgstr "otro" + +#: src/paths/instance/orders/list/index.tsx:91 +#, c-format +msgid "go to order id" +msgstr "ir a id de orden" + +#: src/paths/instance/orders/list/index.tsx:107 +#, c-format +msgid "Paid" +msgstr "Pagado" + +#: src/paths/instance/orders/list/index.tsx:108 +#, fuzzy, c-format +msgid "Refunded" +msgstr "Reembolzado" + +#: src/paths/instance/orders/list/index.tsx:109 +#, fuzzy, c-format +msgid "Not wired" +msgstr "No transferido" + +#: src/paths/instance/orders/list/index.tsx:110 +#, c-format +msgid "All" +msgstr "Todo" + +#: src/paths/instance/products/create/index.tsx:48 +#: src/paths/instance/products/update/index.tsx:64 +#, c-format +msgid "could not create product" +msgstr "no se pudo crear el producto" + +#: src/paths/instance/products/list/Table.tsx:87 +#, c-format +msgid "Sell" +msgstr "Venta" + +#: src/paths/instance/products/list/Table.tsx:89 +#, c-format +msgid "Profit" +msgstr "Ganancia" + +#: src/paths/instance/products/list/Table.tsx:91 +#, c-format +msgid "Sold" +msgstr "Vendido" + +#: src/paths/instance/products/list/index.tsx:59 +#, c-format +msgid "product updated successfully" +msgstr "producto actualizado correctamente" + +#: src/paths/instance/products/list/index.tsx:62 +#, c-format +msgid "could not update the product" +msgstr "no se pudo actualizar el producto" + +#: src/paths/instance/products/list/index.tsx:70 +#, c-format +msgid "product delete successfully" +msgstr "producto fue eliminado correctamente" + +#: src/paths/instance/products/list/index.tsx:73 +#, c-format +msgid "could not delete the product" +msgstr "no se pudo eliminar el producto" + +#: src/paths/instance/tips/list/Table.tsx:59 +#, c-format +msgid "Tips" +msgstr "Propinas" + +#: src/paths/instance/tips/list/Table.tsx:111 +#, c-format +msgid "Committed amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:112 +#, c-format +msgid "Exchange initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:113 +#, c-format +msgid "Merchant initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:148 +#, c-format +msgid "There is no tips yet, add more pressing the + sign" +msgstr "No hay propinas todavÃa, agregar mas presionando el signo +" + +#: src/paths/instance/transfers/list/Table.tsx:147 +#, c-format +msgid "There is no transfer yet, add more pressing the + sign" +msgstr "No hay transferencias todavÃa, agregar mas presionando el signo +" diff --git a/packages/frontend/src/i18n/fr.po b/packages/frontend/src/i18n/fr.po @@ -0,0 +1,1010 @@ +# This file is part of TALER +# (C) 2016 GNUnet e.V. +# +# 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. +# +# 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 +# TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Taler Wallet\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-11-23 00:00+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: src/ApplicationReadyRoutes.tsx:50 src/InstanceRoutes.tsx:117 +#: src/InstanceRoutes.tsx:293 +#, c-format +msgid "Access denied" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:51 src/InstanceRoutes.tsx:117 +#: src/InstanceRoutes.tsx:294 +#, c-format +msgid "Check your token is valid" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:72 +#, c-format +msgid "Couldn't access the server." +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:73 +#, c-format +msgid "Could not infer instance id from url %1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:108 +#, c-format +msgid "HTTP status #%1$s: Server reported a problem" +msgstr "" + +#: src/InstanceRoutes.tsx:109 +#, c-format +msgid "Got message: \"%1$s\" from: %2$s" +msgstr "" + +#: src/InstanceRoutes.tsx:126 +#, c-format +msgid "No default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:127 +#, c-format +msgid "" +"in order to use merchant backoffice, you should create the default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:282 +#, c-format +msgid "Server reported a problem: HTTP status #%1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:283 +#, c-format +msgid "Got message: %1$s from: %2$s" +msgstr "" + +#: src/components/exception/login.tsx:46 +#, c-format +msgid "Login required" +msgstr "" + +#: src/components/exception/login.tsx:49 +#, c-format +msgid "" +"Please enter your auth token. Token should have \"secret-token:\" and start " +"with Bearer or ApiKey" +msgstr "" + +#: src/components/exception/login.tsx:86 src/components/modal/index.tsx:53 +#: src/components/modal/index.tsx:75 src/paths/admin/create/CreatePage.tsx:140 +#: src/paths/instance/orders/create/CreatePage.tsx:337 +#: src/paths/instance/products/create/CreatePage.tsx:51 +#: src/paths/instance/products/list/Table.tsx:174 +#: src/paths/instance/products/list/Table.tsx:228 +#: src/paths/instance/products/update/UpdatePage.tsx:55 +#: src/paths/instance/update/UpdatePage.tsx:159 +#, c-format +msgid "Confirm" +msgstr "" + +#: src/components/form/InputArray.tsx:72 +#, c-format +msgid "The value %1$s is invalid for a payment url" +msgstr "" + +#: src/components/form/InputDate.tsx:67 +#: src/paths/instance/orders/list/index.tsx:123 +#, c-format +msgid "pick a date" +msgstr "" + +#: src/components/form/InputDate.tsx:81 +#, c-format +msgid "clear" +msgstr "" + +#: src/components/form/InputDate.tsx:83 +#, c-format +msgid "never" +msgstr "" + +#: src/components/form/InputImage.tsx:80 +#, c-format +msgid "Image should be smaller than 1 MB" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:59 +#, c-format +msgid "Product id" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:60 +#: src/components/product/ProductForm.tsx:99 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:122 +#: src/paths/instance/orders/list/Table.tsx:227 +#: src/paths/instance/products/list/Table.tsx:86 +#, c-format +msgid "Description" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:73 +#: src/components/form/InputTaxes.tsx:81 +#: src/paths/admin/create/CreatePage.tsx:86 src/paths/admin/list/Table.tsx:110 +#: src/paths/instance/details/DetailPage.tsx:76 +#: src/paths/instance/transfers/list/Table.tsx:112 +#: src/paths/instance/update/UpdatePage.tsx:105 +#, c-format +msgid "Name" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:102 +#, c-format +msgid "loading..." +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:108 +#, c-format +msgid "no products found" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:116 +#, c-format +msgid "no results" +msgstr "" + +#: src/components/form/InputSecured.tsx:33 +#, c-format +msgid "Deleting" +msgstr "" + +#: src/components/form/InputSecured.tsx:34 +#, c-format +msgid "Changing" +msgstr "" + +#: src/components/form/InputSecured.tsx:60 +#, c-format +msgid "Manage token" +msgstr "" + +#: src/components/form/InputSecured.tsx:83 +#, c-format +msgid "Update" +msgstr "" + +#: src/components/form/InputSecured.tsx:100 +#: src/paths/instance/orders/create/CreatePage.tsx:251 +#: src/paths/instance/orders/create/CreatePage.tsx:272 +#, c-format +msgid "Remove" +msgstr "" + +#: src/components/form/InputSecured.tsx:106 src/components/modal/index.tsx:52 +#: src/components/modal/index.tsx:73 src/paths/admin/create/CreatePage.tsx:139 +#: src/paths/instance/orders/create/CreatePage.tsx:336 +#: src/paths/instance/products/create/CreatePage.tsx:50 +#: src/paths/instance/products/list/Table.tsx:166 +#: src/paths/instance/products/list/Table.tsx:218 +#: src/paths/instance/products/update/UpdatePage.tsx:54 +#: src/paths/instance/update/UpdatePage.tsx:158 +#, c-format +msgid "Cancel" +msgstr "" + +#: src/components/form/InputStock.tsx:90 +#, c-format +msgid "Manage stock" +msgstr "" + +#: src/components/form/InputStock.tsx:92 +#, c-format +msgid "Infinite" +msgstr "" + +#: src/components/form/InputStock.tsx:104 +#, c-format +msgid "lost cannot be greater that current + incoming (max %1$s)" +msgstr "" + +#: src/components/form/InputStock.tsx:110 +#, c-format +msgid "current stock will change from %1$s to %2$s" +msgstr "" + +#: src/components/form/InputStock.tsx:111 +#, c-format +msgid "current stock will stay at %1$s" +msgstr "" + +#: src/components/form/InputStock.tsx:128 +#: src/paths/instance/products/list/Table.tsx:204 +#, c-format +msgid "Incoming" +msgstr "" + +#: src/components/form/InputStock.tsx:129 +#: src/paths/instance/products/list/Table.tsx:205 +#, c-format +msgid "Lost" +msgstr "" + +#: src/components/form/InputStock.tsx:141 +#, c-format +msgid "Current" +msgstr "" + +#: src/components/form/InputStock.tsx:144 +#, c-format +msgid "without stock" +msgstr "" + +#: src/components/form/InputStock.tsx:149 +#, c-format +msgid "Next restock" +msgstr "" + +#: src/components/form/InputStock.tsx:151 +#, c-format +msgid "Delivery address" +msgstr "" + +#: src/components/form/InputStock.tsx:153 +#: src/paths/admin/create/CreatePage.tsx:99 +#: src/paths/admin/create/CreatePage.tsx:116 +#: src/paths/instance/orders/create/CreatePage.tsx:308 +#: src/paths/instance/update/UpdatePage.tsx:118 +#: src/paths/instance/update/UpdatePage.tsx:135 +#, c-format +msgid "Country" +msgstr "" + +#: src/components/form/InputStock.tsx:156 +#: src/paths/admin/create/CreatePage.tsx:98 +#: src/paths/admin/create/CreatePage.tsx:101 +#: src/paths/admin/create/CreatePage.tsx:118 +#: src/paths/instance/orders/create/CreatePage.tsx:310 +#: src/paths/instance/update/UpdatePage.tsx:117 +#: src/paths/instance/update/UpdatePage.tsx:120 +#: src/paths/instance/update/UpdatePage.tsx:137 +#, c-format +msgid "Address" +msgstr "" + +#: src/components/form/InputStock.tsx:161 +#: src/paths/admin/create/CreatePage.tsx:105 +#: src/paths/admin/create/CreatePage.tsx:122 +#: src/paths/instance/orders/create/CreatePage.tsx:314 +#: src/paths/instance/update/UpdatePage.tsx:124 +#: src/paths/instance/update/UpdatePage.tsx:141 +#, c-format +msgid "Building number" +msgstr "" + +#: src/components/form/InputStock.tsx:162 +#: src/paths/admin/create/CreatePage.tsx:106 +#: src/paths/admin/create/CreatePage.tsx:123 +#: src/paths/instance/orders/create/CreatePage.tsx:315 +#: src/paths/instance/update/UpdatePage.tsx:125 +#: src/paths/instance/update/UpdatePage.tsx:142 +#, c-format +msgid "Building name" +msgstr "" + +#: src/components/form/InputStock.tsx:163 +#: src/paths/admin/create/CreatePage.tsx:107 +#: src/paths/admin/create/CreatePage.tsx:124 +#: src/paths/instance/orders/create/CreatePage.tsx:316 +#: src/paths/instance/update/UpdatePage.tsx:126 +#: src/paths/instance/update/UpdatePage.tsx:143 +#, c-format +msgid "Street" +msgstr "" + +#: src/components/form/InputStock.tsx:164 +#: src/paths/admin/create/CreatePage.tsx:108 +#: src/paths/admin/create/CreatePage.tsx:125 +#: src/paths/instance/orders/create/CreatePage.tsx:317 +#: src/paths/instance/update/UpdatePage.tsx:127 +#: src/paths/instance/update/UpdatePage.tsx:144 +#, c-format +msgid "Post code" +msgstr "" + +#: src/components/form/InputStock.tsx:165 +#: src/paths/admin/create/CreatePage.tsx:109 +#: src/paths/admin/create/CreatePage.tsx:126 +#: src/paths/instance/orders/create/CreatePage.tsx:318 +#: src/paths/instance/update/UpdatePage.tsx:128 +#: src/paths/instance/update/UpdatePage.tsx:145 +#, c-format +msgid "Town location" +msgstr "" + +#: src/components/form/InputStock.tsx:166 +#: src/paths/admin/create/CreatePage.tsx:110 +#: src/paths/admin/create/CreatePage.tsx:127 +#: src/paths/instance/orders/create/CreatePage.tsx:319 +#: src/paths/instance/update/UpdatePage.tsx:129 +#: src/paths/instance/update/UpdatePage.tsx:146 +#, c-format +msgid "Town" +msgstr "" + +#: src/components/form/InputStock.tsx:167 +#: src/paths/admin/create/CreatePage.tsx:111 +#: src/paths/admin/create/CreatePage.tsx:128 +#: src/paths/instance/orders/create/CreatePage.tsx:320 +#: src/paths/instance/update/UpdatePage.tsx:130 +#: src/paths/instance/update/UpdatePage.tsx:147 +#, c-format +msgid "District" +msgstr "" + +#: src/components/form/InputStock.tsx:168 +#: src/paths/admin/create/CreatePage.tsx:112 +#: src/paths/admin/create/CreatePage.tsx:129 +#: src/paths/instance/orders/create/CreatePage.tsx:321 +#: src/paths/instance/update/UpdatePage.tsx:131 +#: src/paths/instance/update/UpdatePage.tsx:148 +#, c-format +msgid "Country subdivision" +msgstr "" + +#: src/components/form/InputTaxes.tsx:73 +#, c-format +msgid "this product has no taxes" +msgstr "" + +#: src/components/form/InputTaxes.tsx:77 +#: src/paths/instance/orders/details/DetailPage.tsx:145 +#: src/paths/instance/orders/details/DetailPage.tsx:296 +#: src/paths/instance/orders/list/Table.tsx:116 +#, c-format +msgid "Amount" +msgstr "" + +#: src/components/form/InputTaxes.tsx:78 +#, c-format +msgid "currency and value separated with colon" +msgstr "" + +#: src/components/form/InputTaxes.tsx:84 +#: src/paths/instance/orders/create/InventoryProductForm.tsx:78 +#, c-format +msgid "Add" +msgstr "" + +#: src/components/menu/SideBar.tsx:53 +#, c-format +msgid "Instance" +msgstr "" + +#: src/components/menu/SideBar.tsx:59 +#, c-format +msgid "Settings" +msgstr "" + +#: src/components/menu/SideBar.tsx:65 +#: src/paths/instance/orders/list/Table.tsx:60 +#, c-format +msgid "Orders" +msgstr "" + +#: src/components/menu/SideBar.tsx:71 +#: src/paths/instance/orders/create/CreatePage.tsx:257 +#: src/paths/instance/products/list/Table.tsx:48 +#, c-format +msgid "Products" +msgstr "" + +#: src/components/menu/SideBar.tsx:77 +#: src/paths/instance/transfers/list/Table.tsx:59 +#, c-format +msgid "Transfers" +msgstr "" + +#: src/components/menu/SideBar.tsx:87 +#, c-format +msgid "Connection" +msgstr "" + +#: src/components/menu/SideBar.tsx:112 src/paths/admin/list/Table.tsx:57 +#, c-format +msgid "Instances" +msgstr "" + +#: src/components/menu/SideBar.tsx:116 +#, c-format +msgid "New" +msgstr "" + +#: src/components/menu/SideBar.tsx:122 +#, c-format +msgid "List" +msgstr "" + +#: src/components/menu/SideBar.tsx:129 +#, c-format +msgid "Log out" +msgstr "" + +#: src/components/modal/index.tsx:74 +#, c-format +msgid "Clear" +msgstr "" + +#: src/components/modal/index.tsx:110 src/components/modal/index.tsx:111 +#, c-format +msgid "should be the same" +msgstr "" + +#: src/components/modal/index.tsx:111 +#, c-format +msgid "cannot be the same as before" +msgstr "" + +#: src/components/modal/index.tsx:114 +#, c-format +msgid "" +"You are updating the authorization token from instance %1$s with id %2$s" +msgstr "" + +#: src/components/modal/index.tsx:124 +#, c-format +msgid "Old token" +msgstr "" + +#: src/components/modal/index.tsx:125 +#, c-format +msgid "New token" +msgstr "" + +#: src/components/modal/index.tsx:127 +#, c-format +msgid "Clearing the auth token will mean public access to the instance" +msgstr "" + +#: src/components/product/ProductForm.tsx:96 +#: src/paths/admin/create/CreatePage.tsx:84 src/paths/admin/list/Table.tsx:109 +#: src/paths/instance/transfers/list/Table.tsx:111 +#, c-format +msgid "ID" +msgstr "" + +#: src/components/product/ProductForm.tsx:98 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:121 +#: src/paths/instance/products/list/Table.tsx:85 +#, c-format +msgid "Image" +msgstr "" + +#: src/components/product/ProductForm.tsx:100 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:123 +#, c-format +msgid "Unit" +msgstr "" + +#: src/components/product/ProductForm.tsx:101 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:124 +#: src/paths/instance/products/list/Table.tsx:162 +#: src/paths/instance/products/list/Table.tsx:214 +#, c-format +msgid "Price" +msgstr "" + +#: src/components/product/ProductForm.tsx:103 +#: src/paths/instance/products/list/Table.tsx:90 +#, c-format +msgid "Stock" +msgstr "" + +#: src/components/product/ProductForm.tsx:105 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:128 +#: src/paths/instance/products/list/Table.tsx:88 +#, c-format +msgid "Taxes" +msgstr "" + +#: src/index.tsx:75 +#, c-format +msgid "Server not found" +msgstr "" + +#: src/index.tsx:85 +#, c-format +msgid "Couldn't access the server" +msgstr "" + +#: src/index.tsx:87 src/index.tsx:99 +#, c-format +msgid "Got message %1$s from %2$s" +msgstr "" + +#: src/index.tsx:97 +#, c-format +msgid "Unexpected Error" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:88 +#: src/paths/instance/update/UpdatePage.tsx:107 +#, c-format +msgid "Auth token" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:90 +#: src/paths/instance/details/DetailPage.tsx:77 +#: src/paths/instance/update/UpdatePage.tsx:109 +#, c-format +msgid "Account address" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:92 +#: src/paths/instance/update/UpdatePage.tsx:111 +#, c-format +msgid "Default max deposit fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:94 +#: src/paths/instance/update/UpdatePage.tsx:113 +#, c-format +msgid "Default max wire fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:96 +#: src/paths/instance/update/UpdatePage.tsx:115 +#, c-format +msgid "Default wire fee amortization" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:115 +#: src/paths/instance/update/UpdatePage.tsx:134 +#, c-format +msgid "Jurisdiction" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:132 +#: src/paths/instance/update/UpdatePage.tsx:151 +#, c-format +msgid "Default pay delay" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:134 +#: src/paths/instance/update/UpdatePage.tsx:153 +#, c-format +msgid "Default wire transfer delay" +msgstr "" + +#: src/paths/admin/create/index.tsx:58 +#, c-format +msgid "could not create instance" +msgstr "" + +#: src/paths/admin/list/Table.tsx:63 src/paths/admin/list/Table.tsx:131 +#, c-format +msgid "Delete" +msgstr "" + +#: src/paths/admin/list/Table.tsx:128 +#, c-format +msgid "Edit" +msgstr "" + +#: src/paths/admin/list/Table.tsx:149 +#: src/paths/instance/products/list/Table.tsx:245 +#, c-format +msgid "There is no instances yet, add more pressing the + sign" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:236 +#, c-format +msgid "Inventory products" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:285 +#, c-format +msgid "Total price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:286 +#, c-format +msgid "Total tax" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:288 +#: src/paths/instance/orders/create/CreatePage.tsx:296 +#, c-format +msgid "Order price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:294 +#, c-format +msgid "Net" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:299 +#: src/paths/instance/orders/details/DetailPage.tsx:144 +#: src/paths/instance/orders/details/DetailPage.tsx:295 +#: src/paths/instance/orders/list/Table.tsx:117 +#, c-format +msgid "Summary" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:301 +#, c-format +msgid "Payments options" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:302 +#, c-format +msgid "Auto refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:303 +#, c-format +msgid "Refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:304 +#, c-format +msgid "Pay deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:306 +#, c-format +msgid "Delivery date" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:307 +#, c-format +msgid "Location" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:324 +#, c-format +msgid "Max fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:325 +#, c-format +msgid "Max wire fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:326 +#, c-format +msgid "Wire fee amortization" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:327 +#, c-format +msgid "Fullfilment url" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:330 +#, c-format +msgid "Extra information" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:44 +#, c-format +msgid "select a product first" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:51 +#, c-format +msgid "should be greater than 0" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:58 +#, c-format +msgid "" +"cannot be greater than current stock and quantity previously added. max: %1$s" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:64 +#, c-format +msgid "cannot be greater than current stock %1$s" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:76 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:126 +#, c-format +msgid "Quantity" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:92 +#: src/paths/instance/orders/details/DetailPage.tsx:235 +#: src/paths/instance/orders/details/DetailPage.tsx:333 +#, c-format +msgid "Order" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:93 +#, c-format +msgid "claimed" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:110 +#: src/paths/instance/orders/details/DetailPage.tsx:261 +#: src/paths/instance/orders/list/Table.tsx:136 +#, c-format +msgid "copy url" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:126 +#: src/paths/instance/orders/details/DetailPage.tsx:349 +#, c-format +msgid "pay at" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:127 +#: src/paths/instance/orders/details/DetailPage.tsx:350 +#, c-format +msgid "created at" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:138 +#: src/paths/instance/orders/details/DetailPage.tsx:289 +#, c-format +msgid "Timeline" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:142 +#: src/paths/instance/orders/details/DetailPage.tsx:293 +#, c-format +msgid "Payment details" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:146 +#: src/paths/instance/orders/details/DetailPage.tsx:299 +#: src/paths/instance/orders/details/DetailPage.tsx:363 +#, c-format +msgid "Order status" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:156 +#: src/paths/instance/orders/details/DetailPage.tsx:308 +#, c-format +msgid "Product list" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:236 +#, c-format +msgid "paid" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:238 +#, c-format +msgid "wired" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:241 +#, c-format +msgid "refunded" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:258 +#, c-format +msgid "refund" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:297 +#, c-format +msgid "Refunded amount" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:298 +#, c-format +msgid "Deposit total" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:336 +#, c-format +msgid "unpaid" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:364 +#, c-format +msgid "Order status URL" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:365 +#, c-format +msgid "Pay URI" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:383 +#, c-format +msgid "" +"Unknown order status. This is an error, please contact the administrator." +msgstr "" + +#: src/paths/instance/orders/details/index.tsx:56 +#: src/paths/instance/orders/list/index.tsx:147 +#, c-format +msgid "refund created successfully" +msgstr "" + +#: src/paths/instance/orders/details/index.tsx:59 +#: src/paths/instance/orders/list/index.tsx:150 +#, c-format +msgid "could not create the refund" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:111 +#, c-format +msgid "load newer orders" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:115 +#, c-format +msgid "Date" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:131 +#: src/paths/instance/orders/list/Table.tsx:223 +#, c-format +msgid "Refund" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:145 +#, c-format +msgid "load older orders" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:154 +#, c-format +msgid "No orders has been found" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:202 +#, c-format +msgid "date" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:203 +#, c-format +msgid "amount" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:204 +#, c-format +msgid "reason" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:224 +#, c-format +msgid "Max refundable:" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "Reason" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "duplicated" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "requested by the customer" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "other" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:91 +#, c-format +msgid "go to order id" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:107 +#, c-format +msgid "Paid" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:108 +#, c-format +msgid "Refunded" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:109 +#, c-format +msgid "Not wired" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:110 +#, c-format +msgid "All" +msgstr "" + +#: src/paths/instance/products/create/index.tsx:48 +#: src/paths/instance/products/update/index.tsx:64 +#, c-format +msgid "could not create product" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:87 +#, c-format +msgid "Sell" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:89 +#, c-format +msgid "Profit" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:91 +#, c-format +msgid "Sold" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:59 +#, c-format +msgid "product updated successfully" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:62 +#, c-format +msgid "could not update the product" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:70 +#, c-format +msgid "product delete successfully" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:73 +#, c-format +msgid "could not delete the product" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:59 +#, c-format +msgid "Tips" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:111 +#, c-format +msgid "Committed amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:112 +#, c-format +msgid "Exchange initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:113 +#, c-format +msgid "Merchant initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:148 +#, c-format +msgid "There is no tips yet, add more pressing the + sign" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:147 +#, c-format +msgid "There is no transfer yet, add more pressing the + sign" +msgstr "" diff --git a/packages/frontend/src/i18n/index.tsx b/packages/frontend/src/i18n/index.tsx @@ -0,0 +1,204 @@ +/* + 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/> + */ + +/** + * Translation helpers for React components and template literals. + */ + +/** + * Imports + */ +import { Component, ComponentChild, ComponentChildren, h, Fragment, VNode } from "preact"; + +import { useTranslationContext } from "../context/translation"; + +export function useTranslator() { + const ctx = useTranslationContext(); + const jed = ctx.handler + return function str(stringSeq: TemplateStringsArray, ...values: any[]): string { + const s = toI18nString(stringSeq); + const tr = jed + .translate(s) + .ifPlural(1, s) + .fetch(...values); + return tr; + } +} + + + +/** + * Convert template strings to a msgid + */ +function toI18nString(stringSeq: ReadonlyArray<string>): string { + let s = ""; + for (let i = 0; i < stringSeq.length; i++) { + s += stringSeq[i]; + if (i < stringSeq.length - 1) { + s += `%${i + 1}$s`; + } + } + return s; +} + + +interface TranslateSwitchProps { + target: number; + children: ComponentChildren; +} + +function stringifyChildren(children: ComponentChildren): string { + let n = 1; + const ss = (children instanceof Array ? children : [children]).map((c) => { + if (typeof c === "string") { + return c; + } + return `%${n++}$s`; + }); + const s = ss.join("").replace(/ +/g, " ").trim(); + // console.log("translation lookup", JSON.stringify(s)); + return s; +} + +interface TranslateProps { + children: ComponentChildren; + /** + * Component that the translated element should be wrapped in. + * Defaults to "div". + */ + wrap?: any; + + /** + * Props to give to the wrapped component. + */ + wrapProps?: any; +} + +function getTranslatedChildren( + translation: string, + children: ComponentChildren, +): ComponentChild[] { + const tr = translation.split(/%(\d+)\$s/); + const childArray = children instanceof Array ? children : [children]; + // Merge consecutive string children. + const placeholderChildren = Array<ComponentChild>(); + for (let i = 0; i < childArray.length; i++) { + const x = childArray[i]; + if (x === undefined) { + continue; + } else if (typeof x === "string") { + continue; + } else { + placeholderChildren.push(x); + } + } + const result = Array<ComponentChild>(); + for (let i = 0; i < tr.length; i++) { + if (i % 2 == 0) { + // Text + result.push(tr[i]); + } else { + const childIdx = Number.parseInt(tr[i],10) - 1; + result.push(placeholderChildren[childIdx]); + } + } + return result; +} + +/** + * Translate text node children of this component. + * If a child component might produce a text node, it must be wrapped + * in a another non-text element. + * + * Example: + * ``` + * <Translate> + * Hello. Your score is <span><PlayerScore player={player} /></span> + * </Translate> + * ``` + */ +export function Translate({ children }: TranslateProps): VNode { + const s = stringifyChildren(children); + const ctx = useTranslationContext() + const translation: string = ctx.handler.ngettext(s, s, 1); + const result = getTranslatedChildren(translation, children) + return <>{result}</>; +} + +/** + * Switch translation based on singular or plural based on the target prop. + * Should only contain TranslateSingular and TransplatePlural as children. + * + * Example: + * ``` + * <TranslateSwitch target={n}> + * <TranslateSingular>I have {n} apple.</TranslateSingular> + * <TranslatePlural>I have {n} apples.</TranslatePlural> + * </TranslateSwitch> + * ``` + */ +export function TranslateSwitch({ children, target }: TranslateSwitchProps) { + let singular: VNode<TranslationPluralProps> | undefined; + let plural: VNode<TranslationPluralProps> | undefined; + // const children = this.props.children; + if (children) { + (children instanceof Array ? children : [children]).forEach((child: any) => { + if (child.type === TranslatePlural) { + plural = child; + } + if (child.type === TranslateSingular) { + singular = child; + } + }); + } + if (!singular || !plural) { + console.error("translation not found"); + return h("span", {}, ["translation not found"]); + } + singular.props.target = target; + plural.props.target = target; + // We're looking up the translation based on the + // singular, even if we must use the plural form. + return singular; +} + +interface TranslationPluralProps { + children: ComponentChildren; + target: number; +} + +/** + * See [[TranslateSwitch]]. + */ +export function TranslatePlural({ children, target }: TranslationPluralProps): VNode { + const s = stringifyChildren(children); + const ctx = useTranslationContext() + const translation = ctx.handler.ngettext(s, s, 1); + const result = getTranslatedChildren(translation, children); + return <>{result}</>; +} + +/** + * See [[TranslateSwitch]]. + */ +export function TranslateSingular({ children, target }: TranslationPluralProps): VNode { + const s = stringifyChildren(children); + const ctx = useTranslationContext() + const translation = ctx.handler.ngettext(s, s, target); + const result = getTranslatedChildren(translation, children); + return <>{result}</>; + +} diff --git a/packages/frontend/src/i18n/it.po b/packages/frontend/src/i18n/it.po @@ -0,0 +1,1010 @@ +# This file is part of TALER +# (C) 2016 GNUnet e.V. +# +# 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. +# +# 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 +# TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Taler Wallet\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-11-23 00:00+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: src/ApplicationReadyRoutes.tsx:50 src/InstanceRoutes.tsx:117 +#: src/InstanceRoutes.tsx:293 +#, c-format +msgid "Access denied" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:51 src/InstanceRoutes.tsx:117 +#: src/InstanceRoutes.tsx:294 +#, c-format +msgid "Check your token is valid" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:72 +#, c-format +msgid "Couldn't access the server." +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:73 +#, c-format +msgid "Could not infer instance id from url %1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:108 +#, c-format +msgid "HTTP status #%1$s: Server reported a problem" +msgstr "" + +#: src/InstanceRoutes.tsx:109 +#, c-format +msgid "Got message: \"%1$s\" from: %2$s" +msgstr "" + +#: src/InstanceRoutes.tsx:126 +#, c-format +msgid "No default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:127 +#, c-format +msgid "" +"in order to use merchant backoffice, you should create the default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:282 +#, c-format +msgid "Server reported a problem: HTTP status #%1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:283 +#, c-format +msgid "Got message: %1$s from: %2$s" +msgstr "" + +#: src/components/exception/login.tsx:46 +#, c-format +msgid "Login required" +msgstr "" + +#: src/components/exception/login.tsx:49 +#, c-format +msgid "" +"Please enter your auth token. Token should have \"secret-token:\" and start " +"with Bearer or ApiKey" +msgstr "" + +#: src/components/exception/login.tsx:86 src/components/modal/index.tsx:53 +#: src/components/modal/index.tsx:75 src/paths/admin/create/CreatePage.tsx:140 +#: src/paths/instance/orders/create/CreatePage.tsx:337 +#: src/paths/instance/products/create/CreatePage.tsx:51 +#: src/paths/instance/products/list/Table.tsx:174 +#: src/paths/instance/products/list/Table.tsx:228 +#: src/paths/instance/products/update/UpdatePage.tsx:55 +#: src/paths/instance/update/UpdatePage.tsx:159 +#, c-format +msgid "Confirm" +msgstr "" + +#: src/components/form/InputArray.tsx:72 +#, c-format +msgid "The value %1$s is invalid for a payment url" +msgstr "" + +#: src/components/form/InputDate.tsx:67 +#: src/paths/instance/orders/list/index.tsx:123 +#, c-format +msgid "pick a date" +msgstr "" + +#: src/components/form/InputDate.tsx:81 +#, c-format +msgid "clear" +msgstr "" + +#: src/components/form/InputDate.tsx:83 +#, c-format +msgid "never" +msgstr "" + +#: src/components/form/InputImage.tsx:80 +#, c-format +msgid "Image should be smaller than 1 MB" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:59 +#, c-format +msgid "Product id" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:60 +#: src/components/product/ProductForm.tsx:99 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:122 +#: src/paths/instance/orders/list/Table.tsx:227 +#: src/paths/instance/products/list/Table.tsx:86 +#, c-format +msgid "Description" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:73 +#: src/components/form/InputTaxes.tsx:81 +#: src/paths/admin/create/CreatePage.tsx:86 src/paths/admin/list/Table.tsx:110 +#: src/paths/instance/details/DetailPage.tsx:76 +#: src/paths/instance/transfers/list/Table.tsx:112 +#: src/paths/instance/update/UpdatePage.tsx:105 +#, c-format +msgid "Name" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:102 +#, c-format +msgid "loading..." +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:108 +#, c-format +msgid "no products found" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:116 +#, c-format +msgid "no results" +msgstr "" + +#: src/components/form/InputSecured.tsx:33 +#, c-format +msgid "Deleting" +msgstr "" + +#: src/components/form/InputSecured.tsx:34 +#, c-format +msgid "Changing" +msgstr "" + +#: src/components/form/InputSecured.tsx:60 +#, c-format +msgid "Manage token" +msgstr "" + +#: src/components/form/InputSecured.tsx:83 +#, c-format +msgid "Update" +msgstr "" + +#: src/components/form/InputSecured.tsx:100 +#: src/paths/instance/orders/create/CreatePage.tsx:251 +#: src/paths/instance/orders/create/CreatePage.tsx:272 +#, c-format +msgid "Remove" +msgstr "" + +#: src/components/form/InputSecured.tsx:106 src/components/modal/index.tsx:52 +#: src/components/modal/index.tsx:73 src/paths/admin/create/CreatePage.tsx:139 +#: src/paths/instance/orders/create/CreatePage.tsx:336 +#: src/paths/instance/products/create/CreatePage.tsx:50 +#: src/paths/instance/products/list/Table.tsx:166 +#: src/paths/instance/products/list/Table.tsx:218 +#: src/paths/instance/products/update/UpdatePage.tsx:54 +#: src/paths/instance/update/UpdatePage.tsx:158 +#, c-format +msgid "Cancel" +msgstr "" + +#: src/components/form/InputStock.tsx:90 +#, c-format +msgid "Manage stock" +msgstr "" + +#: src/components/form/InputStock.tsx:92 +#, c-format +msgid "Infinite" +msgstr "" + +#: src/components/form/InputStock.tsx:104 +#, c-format +msgid "lost cannot be greater that current + incoming (max %1$s)" +msgstr "" + +#: src/components/form/InputStock.tsx:110 +#, c-format +msgid "current stock will change from %1$s to %2$s" +msgstr "" + +#: src/components/form/InputStock.tsx:111 +#, c-format +msgid "current stock will stay at %1$s" +msgstr "" + +#: src/components/form/InputStock.tsx:128 +#: src/paths/instance/products/list/Table.tsx:204 +#, c-format +msgid "Incoming" +msgstr "" + +#: src/components/form/InputStock.tsx:129 +#: src/paths/instance/products/list/Table.tsx:205 +#, c-format +msgid "Lost" +msgstr "" + +#: src/components/form/InputStock.tsx:141 +#, c-format +msgid "Current" +msgstr "" + +#: src/components/form/InputStock.tsx:144 +#, c-format +msgid "without stock" +msgstr "" + +#: src/components/form/InputStock.tsx:149 +#, c-format +msgid "Next restock" +msgstr "" + +#: src/components/form/InputStock.tsx:151 +#, c-format +msgid "Delivery address" +msgstr "" + +#: src/components/form/InputStock.tsx:153 +#: src/paths/admin/create/CreatePage.tsx:99 +#: src/paths/admin/create/CreatePage.tsx:116 +#: src/paths/instance/orders/create/CreatePage.tsx:308 +#: src/paths/instance/update/UpdatePage.tsx:118 +#: src/paths/instance/update/UpdatePage.tsx:135 +#, c-format +msgid "Country" +msgstr "" + +#: src/components/form/InputStock.tsx:156 +#: src/paths/admin/create/CreatePage.tsx:98 +#: src/paths/admin/create/CreatePage.tsx:101 +#: src/paths/admin/create/CreatePage.tsx:118 +#: src/paths/instance/orders/create/CreatePage.tsx:310 +#: src/paths/instance/update/UpdatePage.tsx:117 +#: src/paths/instance/update/UpdatePage.tsx:120 +#: src/paths/instance/update/UpdatePage.tsx:137 +#, c-format +msgid "Address" +msgstr "" + +#: src/components/form/InputStock.tsx:161 +#: src/paths/admin/create/CreatePage.tsx:105 +#: src/paths/admin/create/CreatePage.tsx:122 +#: src/paths/instance/orders/create/CreatePage.tsx:314 +#: src/paths/instance/update/UpdatePage.tsx:124 +#: src/paths/instance/update/UpdatePage.tsx:141 +#, c-format +msgid "Building number" +msgstr "" + +#: src/components/form/InputStock.tsx:162 +#: src/paths/admin/create/CreatePage.tsx:106 +#: src/paths/admin/create/CreatePage.tsx:123 +#: src/paths/instance/orders/create/CreatePage.tsx:315 +#: src/paths/instance/update/UpdatePage.tsx:125 +#: src/paths/instance/update/UpdatePage.tsx:142 +#, c-format +msgid "Building name" +msgstr "" + +#: src/components/form/InputStock.tsx:163 +#: src/paths/admin/create/CreatePage.tsx:107 +#: src/paths/admin/create/CreatePage.tsx:124 +#: src/paths/instance/orders/create/CreatePage.tsx:316 +#: src/paths/instance/update/UpdatePage.tsx:126 +#: src/paths/instance/update/UpdatePage.tsx:143 +#, c-format +msgid "Street" +msgstr "" + +#: src/components/form/InputStock.tsx:164 +#: src/paths/admin/create/CreatePage.tsx:108 +#: src/paths/admin/create/CreatePage.tsx:125 +#: src/paths/instance/orders/create/CreatePage.tsx:317 +#: src/paths/instance/update/UpdatePage.tsx:127 +#: src/paths/instance/update/UpdatePage.tsx:144 +#, c-format +msgid "Post code" +msgstr "" + +#: src/components/form/InputStock.tsx:165 +#: src/paths/admin/create/CreatePage.tsx:109 +#: src/paths/admin/create/CreatePage.tsx:126 +#: src/paths/instance/orders/create/CreatePage.tsx:318 +#: src/paths/instance/update/UpdatePage.tsx:128 +#: src/paths/instance/update/UpdatePage.tsx:145 +#, c-format +msgid "Town location" +msgstr "" + +#: src/components/form/InputStock.tsx:166 +#: src/paths/admin/create/CreatePage.tsx:110 +#: src/paths/admin/create/CreatePage.tsx:127 +#: src/paths/instance/orders/create/CreatePage.tsx:319 +#: src/paths/instance/update/UpdatePage.tsx:129 +#: src/paths/instance/update/UpdatePage.tsx:146 +#, c-format +msgid "Town" +msgstr "" + +#: src/components/form/InputStock.tsx:167 +#: src/paths/admin/create/CreatePage.tsx:111 +#: src/paths/admin/create/CreatePage.tsx:128 +#: src/paths/instance/orders/create/CreatePage.tsx:320 +#: src/paths/instance/update/UpdatePage.tsx:130 +#: src/paths/instance/update/UpdatePage.tsx:147 +#, c-format +msgid "District" +msgstr "" + +#: src/components/form/InputStock.tsx:168 +#: src/paths/admin/create/CreatePage.tsx:112 +#: src/paths/admin/create/CreatePage.tsx:129 +#: src/paths/instance/orders/create/CreatePage.tsx:321 +#: src/paths/instance/update/UpdatePage.tsx:131 +#: src/paths/instance/update/UpdatePage.tsx:148 +#, c-format +msgid "Country subdivision" +msgstr "" + +#: src/components/form/InputTaxes.tsx:73 +#, c-format +msgid "this product has no taxes" +msgstr "" + +#: src/components/form/InputTaxes.tsx:77 +#: src/paths/instance/orders/details/DetailPage.tsx:145 +#: src/paths/instance/orders/details/DetailPage.tsx:296 +#: src/paths/instance/orders/list/Table.tsx:116 +#, c-format +msgid "Amount" +msgstr "" + +#: src/components/form/InputTaxes.tsx:78 +#, c-format +msgid "currency and value separated with colon" +msgstr "" + +#: src/components/form/InputTaxes.tsx:84 +#: src/paths/instance/orders/create/InventoryProductForm.tsx:78 +#, c-format +msgid "Add" +msgstr "" + +#: src/components/menu/SideBar.tsx:53 +#, c-format +msgid "Instance" +msgstr "" + +#: src/components/menu/SideBar.tsx:59 +#, c-format +msgid "Settings" +msgstr "" + +#: src/components/menu/SideBar.tsx:65 +#: src/paths/instance/orders/list/Table.tsx:60 +#, c-format +msgid "Orders" +msgstr "" + +#: src/components/menu/SideBar.tsx:71 +#: src/paths/instance/orders/create/CreatePage.tsx:257 +#: src/paths/instance/products/list/Table.tsx:48 +#, c-format +msgid "Products" +msgstr "" + +#: src/components/menu/SideBar.tsx:77 +#: src/paths/instance/transfers/list/Table.tsx:59 +#, c-format +msgid "Transfers" +msgstr "" + +#: src/components/menu/SideBar.tsx:87 +#, c-format +msgid "Connection" +msgstr "" + +#: src/components/menu/SideBar.tsx:112 src/paths/admin/list/Table.tsx:57 +#, c-format +msgid "Instances" +msgstr "" + +#: src/components/menu/SideBar.tsx:116 +#, c-format +msgid "New" +msgstr "" + +#: src/components/menu/SideBar.tsx:122 +#, c-format +msgid "List" +msgstr "" + +#: src/components/menu/SideBar.tsx:129 +#, c-format +msgid "Log out" +msgstr "" + +#: src/components/modal/index.tsx:74 +#, c-format +msgid "Clear" +msgstr "" + +#: src/components/modal/index.tsx:110 src/components/modal/index.tsx:111 +#, c-format +msgid "should be the same" +msgstr "" + +#: src/components/modal/index.tsx:111 +#, c-format +msgid "cannot be the same as before" +msgstr "" + +#: src/components/modal/index.tsx:114 +#, c-format +msgid "" +"You are updating the authorization token from instance %1$s with id %2$s" +msgstr "" + +#: src/components/modal/index.tsx:124 +#, c-format +msgid "Old token" +msgstr "" + +#: src/components/modal/index.tsx:125 +#, c-format +msgid "New token" +msgstr "" + +#: src/components/modal/index.tsx:127 +#, c-format +msgid "Clearing the auth token will mean public access to the instance" +msgstr "" + +#: src/components/product/ProductForm.tsx:96 +#: src/paths/admin/create/CreatePage.tsx:84 src/paths/admin/list/Table.tsx:109 +#: src/paths/instance/transfers/list/Table.tsx:111 +#, c-format +msgid "ID" +msgstr "" + +#: src/components/product/ProductForm.tsx:98 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:121 +#: src/paths/instance/products/list/Table.tsx:85 +#, c-format +msgid "Image" +msgstr "" + +#: src/components/product/ProductForm.tsx:100 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:123 +#, c-format +msgid "Unit" +msgstr "" + +#: src/components/product/ProductForm.tsx:101 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:124 +#: src/paths/instance/products/list/Table.tsx:162 +#: src/paths/instance/products/list/Table.tsx:214 +#, c-format +msgid "Price" +msgstr "" + +#: src/components/product/ProductForm.tsx:103 +#: src/paths/instance/products/list/Table.tsx:90 +#, c-format +msgid "Stock" +msgstr "" + +#: src/components/product/ProductForm.tsx:105 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:128 +#: src/paths/instance/products/list/Table.tsx:88 +#, c-format +msgid "Taxes" +msgstr "" + +#: src/index.tsx:75 +#, c-format +msgid "Server not found" +msgstr "" + +#: src/index.tsx:85 +#, c-format +msgid "Couldn't access the server" +msgstr "" + +#: src/index.tsx:87 src/index.tsx:99 +#, c-format +msgid "Got message %1$s from %2$s" +msgstr "" + +#: src/index.tsx:97 +#, c-format +msgid "Unexpected Error" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:88 +#: src/paths/instance/update/UpdatePage.tsx:107 +#, c-format +msgid "Auth token" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:90 +#: src/paths/instance/details/DetailPage.tsx:77 +#: src/paths/instance/update/UpdatePage.tsx:109 +#, c-format +msgid "Account address" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:92 +#: src/paths/instance/update/UpdatePage.tsx:111 +#, c-format +msgid "Default max deposit fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:94 +#: src/paths/instance/update/UpdatePage.tsx:113 +#, c-format +msgid "Default max wire fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:96 +#: src/paths/instance/update/UpdatePage.tsx:115 +#, c-format +msgid "Default wire fee amortization" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:115 +#: src/paths/instance/update/UpdatePage.tsx:134 +#, c-format +msgid "Jurisdiction" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:132 +#: src/paths/instance/update/UpdatePage.tsx:151 +#, c-format +msgid "Default pay delay" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:134 +#: src/paths/instance/update/UpdatePage.tsx:153 +#, c-format +msgid "Default wire transfer delay" +msgstr "" + +#: src/paths/admin/create/index.tsx:58 +#, c-format +msgid "could not create instance" +msgstr "" + +#: src/paths/admin/list/Table.tsx:63 src/paths/admin/list/Table.tsx:131 +#, c-format +msgid "Delete" +msgstr "" + +#: src/paths/admin/list/Table.tsx:128 +#, c-format +msgid "Edit" +msgstr "" + +#: src/paths/admin/list/Table.tsx:149 +#: src/paths/instance/products/list/Table.tsx:245 +#, c-format +msgid "There is no instances yet, add more pressing the + sign" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:236 +#, c-format +msgid "Inventory products" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:285 +#, c-format +msgid "Total price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:286 +#, c-format +msgid "Total tax" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:288 +#: src/paths/instance/orders/create/CreatePage.tsx:296 +#, c-format +msgid "Order price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:294 +#, c-format +msgid "Net" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:299 +#: src/paths/instance/orders/details/DetailPage.tsx:144 +#: src/paths/instance/orders/details/DetailPage.tsx:295 +#: src/paths/instance/orders/list/Table.tsx:117 +#, c-format +msgid "Summary" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:301 +#, c-format +msgid "Payments options" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:302 +#, c-format +msgid "Auto refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:303 +#, c-format +msgid "Refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:304 +#, c-format +msgid "Pay deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:306 +#, c-format +msgid "Delivery date" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:307 +#, c-format +msgid "Location" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:324 +#, c-format +msgid "Max fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:325 +#, c-format +msgid "Max wire fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:326 +#, c-format +msgid "Wire fee amortization" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:327 +#, c-format +msgid "Fullfilment url" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:330 +#, c-format +msgid "Extra information" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:44 +#, c-format +msgid "select a product first" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:51 +#, c-format +msgid "should be greater than 0" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:58 +#, c-format +msgid "" +"cannot be greater than current stock and quantity previously added. max: %1$s" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:64 +#, c-format +msgid "cannot be greater than current stock %1$s" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:76 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:126 +#, c-format +msgid "Quantity" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:92 +#: src/paths/instance/orders/details/DetailPage.tsx:235 +#: src/paths/instance/orders/details/DetailPage.tsx:333 +#, c-format +msgid "Order" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:93 +#, c-format +msgid "claimed" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:110 +#: src/paths/instance/orders/details/DetailPage.tsx:261 +#: src/paths/instance/orders/list/Table.tsx:136 +#, c-format +msgid "copy url" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:126 +#: src/paths/instance/orders/details/DetailPage.tsx:349 +#, c-format +msgid "pay at" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:127 +#: src/paths/instance/orders/details/DetailPage.tsx:350 +#, c-format +msgid "created at" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:138 +#: src/paths/instance/orders/details/DetailPage.tsx:289 +#, c-format +msgid "Timeline" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:142 +#: src/paths/instance/orders/details/DetailPage.tsx:293 +#, c-format +msgid "Payment details" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:146 +#: src/paths/instance/orders/details/DetailPage.tsx:299 +#: src/paths/instance/orders/details/DetailPage.tsx:363 +#, c-format +msgid "Order status" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:156 +#: src/paths/instance/orders/details/DetailPage.tsx:308 +#, c-format +msgid "Product list" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:236 +#, c-format +msgid "paid" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:238 +#, c-format +msgid "wired" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:241 +#, c-format +msgid "refunded" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:258 +#, c-format +msgid "refund" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:297 +#, c-format +msgid "Refunded amount" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:298 +#, c-format +msgid "Deposit total" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:336 +#, c-format +msgid "unpaid" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:364 +#, c-format +msgid "Order status URL" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:365 +#, c-format +msgid "Pay URI" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:383 +#, c-format +msgid "" +"Unknown order status. This is an error, please contact the administrator." +msgstr "" + +#: src/paths/instance/orders/details/index.tsx:56 +#: src/paths/instance/orders/list/index.tsx:147 +#, c-format +msgid "refund created successfully" +msgstr "" + +#: src/paths/instance/orders/details/index.tsx:59 +#: src/paths/instance/orders/list/index.tsx:150 +#, c-format +msgid "could not create the refund" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:111 +#, c-format +msgid "load newer orders" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:115 +#, c-format +msgid "Date" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:131 +#: src/paths/instance/orders/list/Table.tsx:223 +#, c-format +msgid "Refund" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:145 +#, c-format +msgid "load older orders" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:154 +#, c-format +msgid "No orders has been found" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:202 +#, c-format +msgid "date" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:203 +#, c-format +msgid "amount" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:204 +#, c-format +msgid "reason" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:224 +#, c-format +msgid "Max refundable:" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "Reason" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "duplicated" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "requested by the customer" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "other" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:91 +#, c-format +msgid "go to order id" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:107 +#, c-format +msgid "Paid" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:108 +#, c-format +msgid "Refunded" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:109 +#, c-format +msgid "Not wired" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:110 +#, c-format +msgid "All" +msgstr "" + +#: src/paths/instance/products/create/index.tsx:48 +#: src/paths/instance/products/update/index.tsx:64 +#, c-format +msgid "could not create product" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:87 +#, c-format +msgid "Sell" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:89 +#, c-format +msgid "Profit" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:91 +#, c-format +msgid "Sold" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:59 +#, c-format +msgid "product updated successfully" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:62 +#, c-format +msgid "could not update the product" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:70 +#, c-format +msgid "product delete successfully" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:73 +#, c-format +msgid "could not delete the product" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:59 +#, c-format +msgid "Tips" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:111 +#, c-format +msgid "Committed amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:112 +#, c-format +msgid "Exchange initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:113 +#, c-format +msgid "Merchant initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:148 +#, c-format +msgid "There is no tips yet, add more pressing the + sign" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:147 +#, c-format +msgid "There is no transfer yet, add more pressing the + sign" +msgstr "" diff --git a/packages/frontend/src/i18n/poheader b/packages/frontend/src/i18n/poheader @@ -0,0 +1,27 @@ +# 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/> + +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Taler Wallet\n" +"Report-Msgid-Bugs-To: taler@gnu.org\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" diff --git a/packages/frontend/src/i18n/strings-prelude b/packages/frontend/src/i18n/strings-prelude @@ -0,0 +1,19 @@ +/* + 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/> + */ + +/*eslint quote-props: ["error", "consistent"]*/ +export const strings: {[s: string]: any} = {}; + diff --git a/packages/frontend/src/i18n/strings.ts b/packages/frontend/src/i18n/strings.ts @@ -0,0 +1,3139 @@ +/* + 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/> + */ + +/*eslint quote-props: ["error", "consistent"]*/ +export const strings: {[s: string]: any} = {}; + +strings['de'] = { + "domain": "messages", + "locale_data": { + "messages": { + "": { + "domain": "messages", + "plural_forms": "nplurals=2; plural=(n != 1);", + "lang": "" + }, + "Access denied": [ + "" + ], + "Check your token is valid": [ + "" + ], + "Couldn't access the server.": [ + "" + ], + "Could not infer instance id from url %1$s": [ + "" + ], + "HTTP status #%1$s: Server reported a problem": [ + "" + ], + "Got message: \"%1$s\" from: %2$s": [ + "" + ], + "No default instance": [ + "" + ], + "in order to use merchant backoffice, you should create the default instance": [ + "" + ], + "Server reported a problem: HTTP status #%1$s": [ + "" + ], + "Got message: %1$s from: %2$s": [ + "" + ], + "Login required": [ + "" + ], + "Please enter your auth token. Token should have \"secret-token:\" and start with Bearer or ApiKey": [ + "" + ], + "Confirm": [ + "" + ], + "The value %1$s is invalid for a payment url": [ + "" + ], + "pick a date": [ + "" + ], + "clear": [ + "" + ], + "never": [ + "" + ], + "Image should be smaller than 1 MB": [ + "" + ], + "Product id": [ + "" + ], + "Description": [ + "" + ], + "Name": [ + "" + ], + "loading...": [ + "" + ], + "no products found": [ + "" + ], + "no results": [ + "" + ], + "Deleting": [ + "" + ], + "Changing": [ + "" + ], + "Manage token": [ + "" + ], + "Update": [ + "" + ], + "Remove": [ + "" + ], + "Cancel": [ + "" + ], + "Manage stock": [ + "" + ], + "Infinite": [ + "" + ], + "lost cannot be greater that current + incoming (max %1$s)": [ + "" + ], + "current stock will change from %1$s to %2$s": [ + "" + ], + "current stock will stay at %1$s": [ + "" + ], + "Incoming": [ + "" + ], + "Lost": [ + "" + ], + "Current": [ + "" + ], + "without stock": [ + "" + ], + "Next restock": [ + "" + ], + "Delivery address": [ + "" + ], + "Country": [ + "" + ], + "Address": [ + "" + ], + "Building number": [ + "" + ], + "Building name": [ + "" + ], + "Street": [ + "" + ], + "Post code": [ + "" + ], + "Town location": [ + "" + ], + "Town": [ + "" + ], + "District": [ + "" + ], + "Country subdivision": [ + "" + ], + "this product has no taxes": [ + "" + ], + "Amount": [ + "" + ], + "currency and value separated with colon": [ + "" + ], + "Add": [ + "" + ], + "Instance": [ + "" + ], + "Settings": [ + "" + ], + "Orders": [ + "" + ], + "Products": [ + "" + ], + "Transfers": [ + "" + ], + "Connection": [ + "" + ], + "Instances": [ + "" + ], + "New": [ + "" + ], + "List": [ + "" + ], + "Log out": [ + "" + ], + "Clear": [ + "" + ], + "should be the same": [ + "" + ], + "cannot be the same as before": [ + "" + ], + "You are updating the authorization token from instance %1$s with id %2$s": [ + "" + ], + "Old token": [ + "" + ], + "New token": [ + "" + ], + "Clearing the auth token will mean public access to the instance": [ + "" + ], + "ID": [ + "" + ], + "Image": [ + "" + ], + "Unit": [ + "" + ], + "Price": [ + "" + ], + "Stock": [ + "" + ], + "Taxes": [ + "" + ], + "Server not found": [ + "" + ], + "Couldn't access the server": [ + "" + ], + "Got message %1$s from %2$s": [ + "" + ], + "Unexpected Error": [ + "" + ], + "Auth token": [ + "" + ], + "Account address": [ + "" + ], + "Default max deposit fee": [ + "" + ], + "Default max wire fee": [ + "" + ], + "Default wire fee amortization": [ + "" + ], + "Jurisdiction": [ + "" + ], + "Default pay delay": [ + "" + ], + "Default wire transfer delay": [ + "" + ], + "could not create instance": [ + "" + ], + "Delete": [ + "" + ], + "Edit": [ + "" + ], + "There is no instances yet, add more pressing the + sign": [ + "" + ], + "Inventory products": [ + "" + ], + "Total price": [ + "" + ], + "Total tax": [ + "" + ], + "Order price": [ + "" + ], + "Net": [ + "" + ], + "Summary": [ + "" + ], + "Payments options": [ + "" + ], + "Auto refund deadline": [ + "" + ], + "Refund deadline": [ + "" + ], + "Pay deadline": [ + "" + ], + "Delivery date": [ + "" + ], + "Location": [ + "" + ], + "Max fee": [ + "" + ], + "Max wire fee": [ + "" + ], + "Wire fee amortization": [ + "" + ], + "Fullfilment url": [ + "" + ], + "Extra information": [ + "" + ], + "select a product first": [ + "" + ], + "should be greater than 0": [ + "" + ], + "cannot be greater than current stock and quantity previously added. max: %1$s": [ + "" + ], + "cannot be greater than current stock %1$s": [ + "" + ], + "Quantity": [ + "" + ], + "Order": [ + "" + ], + "claimed": [ + "" + ], + "copy url": [ + "" + ], + "pay at": [ + "" + ], + "created at": [ + "" + ], + "Timeline": [ + "" + ], + "Payment details": [ + "" + ], + "Order status": [ + "" + ], + "Product list": [ + "" + ], + "paid": [ + "" + ], + "wired": [ + "" + ], + "refunded": [ + "" + ], + "refund": [ + "" + ], + "Refunded amount": [ + "" + ], + "Deposit total": [ + "" + ], + "unpaid": [ + "" + ], + "Order status URL": [ + "" + ], + "Pay URI": [ + "" + ], + "Unknown order status. This is an error, please contact the administrator.": [ + "" + ], + "refund created successfully": [ + "" + ], + "could not create the refund": [ + "" + ], + "load newer orders": [ + "" + ], + "Date": [ + "" + ], + "Refund": [ + "" + ], + "load older orders": [ + "" + ], + "No orders has been found": [ + "" + ], + "date": [ + "" + ], + "amount": [ + "" + ], + "reason": [ + "" + ], + "Max refundable:": [ + "" + ], + "Reason": [ + "" + ], + "duplicated": [ + "" + ], + "requested by the customer": [ + "" + ], + "other": [ + "" + ], + "go to order id": [ + "" + ], + "Paid": [ + "" + ], + "Refunded": [ + "" + ], + "Not wired": [ + "" + ], + "All": [ + "" + ], + "could not create product": [ + "" + ], + "Sell": [ + "" + ], + "Profit": [ + "" + ], + "Sold": [ + "" + ], + "product updated successfully": [ + "" + ], + "could not update the product": [ + "" + ], + "product delete successfully": [ + "" + ], + "could not delete the product": [ + "" + ], + "Tips": [ + "" + ], + "Committed amount": [ + "" + ], + "Exchange initial amount": [ + "" + ], + "Merchant initial amount": [ + "" + ], + "There is no tips yet, add more pressing the + sign": [ + "" + ], + "There is no transfer yet, add more pressing the + sign": [ + "" + ] + } + } +}; + +strings['en'] = { + "domain": "messages", + "locale_data": { + "messages": { + "": { + "domain": "messages", + "plural_forms": "nplurals=2; plural=(n != 1);", + "lang": "" + }, + "Access denied": [ + "" + ], + "Check your token is valid": [ + "" + ], + "Couldn't access the server.": [ + "" + ], + "Could not infer instance id from url %1$s": [ + "" + ], + "HTTP status #%1$s: Server reported a problem": [ + "" + ], + "Got message: \"%1$s\" from: %2$s": [ + "" + ], + "No default instance": [ + "" + ], + "in order to use merchant backoffice, you should create the default instance": [ + "" + ], + "Server reported a problem: HTTP status #%1$s": [ + "" + ], + "Got message: %1$s from: %2$s": [ + "" + ], + "Login required": [ + "" + ], + "Please enter your auth token. Token should have \"secret-token:\" and start with Bearer or ApiKey": [ + "" + ], + "Confirm": [ + "" + ], + "The value %1$s is invalid for a payment url": [ + "" + ], + "pick a date": [ + "" + ], + "clear": [ + "" + ], + "never": [ + "" + ], + "Image should be smaller than 1 MB": [ + "" + ], + "Product id": [ + "" + ], + "Description": [ + "" + ], + "Name": [ + "" + ], + "loading...": [ + "" + ], + "no products found": [ + "" + ], + "no results": [ + "" + ], + "Deleting": [ + "" + ], + "Changing": [ + "" + ], + "Manage token": [ + "" + ], + "Update": [ + "" + ], + "Remove": [ + "" + ], + "Cancel": [ + "" + ], + "Manage stock": [ + "" + ], + "Infinite": [ + "" + ], + "lost cannot be greater that current + incoming (max %1$s)": [ + "" + ], + "current stock will change from %1$s to %2$s": [ + "" + ], + "current stock will stay at %1$s": [ + "" + ], + "Incoming": [ + "" + ], + "Lost": [ + "" + ], + "Current": [ + "" + ], + "without stock": [ + "" + ], + "Next restock": [ + "" + ], + "Delivery address": [ + "" + ], + "Country": [ + "" + ], + "Address": [ + "" + ], + "Building number": [ + "" + ], + "Building name": [ + "" + ], + "Street": [ + "" + ], + "Post code": [ + "" + ], + "Town location": [ + "" + ], + "Town": [ + "" + ], + "District": [ + "" + ], + "Country subdivision": [ + "" + ], + "this product has no taxes": [ + "" + ], + "Amount": [ + "" + ], + "currency and value separated with colon": [ + "" + ], + "Add": [ + "" + ], + "Instance": [ + "" + ], + "Settings": [ + "" + ], + "Orders": [ + "" + ], + "Products": [ + "" + ], + "Transfers": [ + "" + ], + "Connection": [ + "" + ], + "Instances": [ + "" + ], + "New": [ + "" + ], + "List": [ + "" + ], + "Log out": [ + "" + ], + "Clear": [ + "" + ], + "should be the same": [ + "" + ], + "cannot be the same as before": [ + "" + ], + "You are updating the authorization token from instance %1$s with id %2$s": [ + "" + ], + "Old token": [ + "" + ], + "New token": [ + "" + ], + "Clearing the auth token will mean public access to the instance": [ + "" + ], + "ID": [ + "" + ], + "Image": [ + "" + ], + "Unit": [ + "" + ], + "Price": [ + "" + ], + "Stock": [ + "" + ], + "Taxes": [ + "" + ], + "Server not found": [ + "" + ], + "Couldn't access the server": [ + "" + ], + "Got message %1$s from %2$s": [ + "" + ], + "Unexpected Error": [ + "" + ], + "Auth token": [ + "" + ], + "Account address": [ + "" + ], + "Default max deposit fee": [ + "" + ], + "Default max wire fee": [ + "" + ], + "Default wire fee amortization": [ + "" + ], + "Jurisdiction": [ + "" + ], + "Default pay delay": [ + "" + ], + "Default wire transfer delay": [ + "" + ], + "could not create instance": [ + "" + ], + "Delete": [ + "" + ], + "Edit": [ + "" + ], + "There is no instances yet, add more pressing the + sign": [ + "" + ], + "Inventory products": [ + "" + ], + "Total price": [ + "" + ], + "Total tax": [ + "" + ], + "Order price": [ + "" + ], + "Net": [ + "" + ], + "Summary": [ + "" + ], + "Payments options": [ + "" + ], + "Auto refund deadline": [ + "" + ], + "Refund deadline": [ + "" + ], + "Pay deadline": [ + "" + ], + "Delivery date": [ + "" + ], + "Location": [ + "" + ], + "Max fee": [ + "" + ], + "Max wire fee": [ + "" + ], + "Wire fee amortization": [ + "" + ], + "Fullfilment url": [ + "" + ], + "Extra information": [ + "" + ], + "select a product first": [ + "" + ], + "should be greater than 0": [ + "" + ], + "cannot be greater than current stock and quantity previously added. max: %1$s": [ + "" + ], + "cannot be greater than current stock %1$s": [ + "" + ], + "Quantity": [ + "" + ], + "Order": [ + "" + ], + "claimed": [ + "" + ], + "copy url": [ + "" + ], + "pay at": [ + "" + ], + "created at": [ + "" + ], + "Timeline": [ + "" + ], + "Payment details": [ + "" + ], + "Order status": [ + "" + ], + "Product list": [ + "" + ], + "paid": [ + "" + ], + "wired": [ + "" + ], + "refunded": [ + "" + ], + "refund": [ + "" + ], + "Refunded amount": [ + "" + ], + "Deposit total": [ + "" + ], + "unpaid": [ + "" + ], + "Order status URL": [ + "" + ], + "Pay URI": [ + "" + ], + "Unknown order status. This is an error, please contact the administrator.": [ + "" + ], + "refund created successfully": [ + "" + ], + "could not create the refund": [ + "" + ], + "load newer orders": [ + "" + ], + "Date": [ + "" + ], + "Refund": [ + "" + ], + "load older orders": [ + "" + ], + "No orders has been found": [ + "" + ], + "date": [ + "" + ], + "amount": [ + "" + ], + "reason": [ + "" + ], + "Max refundable:": [ + "" + ], + "Reason": [ + "" + ], + "duplicated": [ + "" + ], + "requested by the customer": [ + "" + ], + "other": [ + "" + ], + "go to order id": [ + "" + ], + "Paid": [ + "" + ], + "Refunded": [ + "" + ], + "Not wired": [ + "" + ], + "All": [ + "" + ], + "could not create product": [ + "" + ], + "Sell": [ + "" + ], + "Profit": [ + "" + ], + "Sold": [ + "" + ], + "product updated successfully": [ + "" + ], + "could not update the product": [ + "" + ], + "product delete successfully": [ + "" + ], + "could not delete the product": [ + "" + ], + "Tips": [ + "" + ], + "Committed amount": [ + "" + ], + "Exchange initial amount": [ + "" + ], + "Merchant initial amount": [ + "" + ], + "There is no tips yet, add more pressing the + sign": [ + "" + ], + "There is no transfer yet, add more pressing the + sign": [ + "" + ] + } + } +}; + +strings['es'] = { + "domain": "messages", + "locale_data": { + "messages": { + "": { + "domain": "messages", + "plural_forms": "nplurals=2; plural=(n != 1);", + "lang": "" + }, + "Access denied": [ + "Acceso denegado" + ], + "Check your token is valid": [ + "Verifica que el token sea valido" + ], + "Couldn't access the server.": [ + "No se pudo acceder al servidor" + ], + "Could not infer instance id from url %1$s": [ + "No se pudo inferir el id de la instancia con la url %1$s" + ], + "HTTP status #%1$s: Server reported a problem": [ + "HTTP status #%1$s: Servidor reporto un problema" + ], + "Got message: \"%1$s\" from: %2$s": [ + "Recivimos el mensaje %1$s desde %2$s" + ], + "No default instance": [ + "Sin instancia default" + ], + "in order to use merchant backoffice, you should create the default instance": [ + "para usar el merchant backoffice, deberÃa crear la instancia default" + ], + "Server reported a problem: HTTP status #%1$s": [ + "Servidir reporto un problema: HTTP status #%1$s" + ], + "Got message: %1$s from: %2$s": [ + "Recivimos el mensaje %1$s desde %2$s" + ], + "Login required": [ + "Login necesario" + ], + "Please enter your auth token. Token should have \"secret-token:\" and start with Bearer or ApiKey": [ + "Por favor ingrese su token de autorización. El token debe tener \"secret-token\" y comenzar con Bearer o ApiKey" + ], + "Confirm": [ + "Confirmar" + ], + "The value %1$s is invalid for a payment url": [ + "El valor %1$s es invalido para una URL de pago" + ], + "pick a date": [ + "elegir una fecha" + ], + "clear": [ + "Limpiar" + ], + "never": [ + "nunca" + ], + "Image should be smaller than 1 MB": [ + "La imagen debe ser mas chica que 1 MB" + ], + "Product id": [ + "Id de producto" + ], + "Description": [ + "Descripcion" + ], + "Name": [ + "Nombre" + ], + "loading...": [ + "Cargando..." + ], + "no products found": [ + "No se encontraron productos" + ], + "no results": [ + "Sin resultados" + ], + "Deleting": [ + "Borrando" + ], + "Changing": [ + "Cambiando" + ], + "Manage token": [ + "Administrar token" + ], + "Update": [ + "Actualizar" + ], + "Remove": [ + "Eliminar" + ], + "Cancel": [ + "Cancelar" + ], + "Manage stock": [ + "Administrar stock" + ], + "Infinite": [ + "Inifinito" + ], + "lost cannot be greater that current + incoming (max %1$s)": [ + "no puede ser mayor al stock actual %1$s" + ], + "current stock will change from %1$s to %2$s": [ + "stock actual cambiará desde %1$s a %2$s" + ], + "current stock will stay at %1$s": [ + "stock actual seguirá en %1$s" + ], + "Incoming": [ + "Ingresando" + ], + "Lost": [ + "Perdido" + ], + "Current": [ + "Actual" + ], + "without stock": [ + "sin stock" + ], + "Next restock": [ + "Próximo reabastecimiento" + ], + "Delivery address": [ + "Dirección de entrega" + ], + "Country": [ + "PaÃs" + ], + "Address": [ + "Dirección" + ], + "Building number": [ + "Número de edificio" + ], + "Building name": [ + "Nombre de edificio" + ], + "Street": [ + "Calle" + ], + "Post code": [ + "Código postal" + ], + "Town location": [ + "Ubicación de ciudad" + ], + "Town": [ + "Ciudad" + ], + "District": [ + "Distrito" + ], + "Country subdivision": [ + "Provincia" + ], + "this product has no taxes": [ + "este producto no tiene impuestos" + ], + "Amount": [ + "Monto" + ], + "currency and value separated with colon": [ + "Moneda y valor separado por dos puntos" + ], + "Add": [ + "Agregar" + ], + "Instance": [ + "Instancia" + ], + "Settings": [ + "Configuración" + ], + "Orders": [ + "Ordenes" + ], + "Products": [ + "Productos" + ], + "Transfers": [ + "Transferencias" + ], + "Connection": [ + "Conexión" + ], + "Instances": [ + "Instancias" + ], + "New": [ + "Nuevo" + ], + "List": [ + "Lista" + ], + "Log out": [ + "Salir" + ], + "Clear": [ + "Limpiar" + ], + "should be the same": [ + "deberÃan ser iguales" + ], + "cannot be the same as before": [ + "no puede ser igual al anterior" + ], + "You are updating the authorization token from instance %1$s with id %2$s": [ + "Está actualizando el token de autorización para la instancia %1$s con id %2$s" + ], + "Old token": [ + "Viejo token" + ], + "New token": [ + "Nuevo token" + ], + "Clearing the auth token will mean public access to the instance": [ + "Limpiar el token de autorización significa acceso publico a la instancia" + ], + "ID": [ + "ID" + ], + "Image": [ + "Imagen" + ], + "Unit": [ + "Unidad" + ], + "Price": [ + "Precio" + ], + "Stock": [ + "Stock" + ], + "Taxes": [ + "Impuesto" + ], + "Server not found": [ + "Servidor no encontrado" + ], + "Couldn't access the server": [ + "No se pudo aceder al servidor" + ], + "Got message %1$s from %2$s": [ + "Recivimos el mensaje %1$s desde %2$s" + ], + "Unexpected Error": [ + "Error inesperado" + ], + "Auth token": [ + "Token de autorización" + ], + "Account address": [ + "Dirección de cuenta" + ], + "Default max deposit fee": [ + "Impuesto máximo de deposito por omisión" + ], + "Default max wire fee": [ + "Impuesto máximo de transferencia por omisión" + ], + "Default wire fee amortization": [ + "Amortización de impuesto de transferencia por omisión" + ], + "Jurisdiction": [ + "Jurisdicción" + ], + "Default pay delay": [ + "Retrazo de pago por omisión" + ], + "Default wire transfer delay": [ + "Retrazo de transferencia por omisión" + ], + "could not create instance": [ + "no se pudo crear la instancia" + ], + "Delete": [ + "Borrando" + ], + "Edit": [ + "" + ], + "There is no instances yet, add more pressing the + sign": [ + "No hay instancias todavÃan, agregue mas presionando el signo +" + ], + "Inventory products": [ + "Productos de inventario" + ], + "Total price": [ + "Precio total" + ], + "Total tax": [ + "Impuesto total" + ], + "Order price": [ + "Precio de la orden" + ], + "Net": [ + "Neto" + ], + "Summary": [ + "Resumen" + ], + "Payments options": [ + "Opciones de pago" + ], + "Auto refund deadline": [ + "Plazo de reembolso automático" + ], + "Refund deadline": [ + "Plazo de reembolso" + ], + "Pay deadline": [ + "Plazo de pago" + ], + "Delivery date": [ + "Fecha de entrega" + ], + "Location": [ + "Ubicación" + ], + "Max fee": [ + "Impuesto máximo" + ], + "Max wire fee": [ + "Impuesto de transferencia máximo" + ], + "Wire fee amortization": [ + "Amortización de impuesto de transferencia" + ], + "Fullfilment url": [ + "URL de completitud" + ], + "Extra information": [ + "Información extra" + ], + "select a product first": [ + "seleccione un producto primero" + ], + "should be greater than 0": [ + "La imagen debe ser mas chica que 1 MB" + ], + "cannot be greater than current stock and quantity previously added. max: %1$s": [ + "no puede ser mayor al stock actual y la cantidad previamente agregada. máximo: %1$s" + ], + "cannot be greater than current stock %1$s": [ + "no puede ser mayor al stock actual %1$s" + ], + "Quantity": [ + "Cantidad" + ], + "Order": [ + "Orden" + ], + "claimed": [ + "reclamado" + ], + "copy url": [ + "copiar url" + ], + "pay at": [ + "pagar en" + ], + "created at": [ + "creado" + ], + "Timeline": [ + "CronologÃa" + ], + "Payment details": [ + "Detalles de pago" + ], + "Order status": [ + "Estado de orden" + ], + "Product list": [ + "Lista de producto" + ], + "paid": [ + "pagados" + ], + "wired": [ + "transferido" + ], + "refunded": [ + "reembolzado" + ], + "refund": [ + "reembolzar" + ], + "Refunded amount": [ + "Monto reembolzado" + ], + "Deposit total": [ + "Total depositado" + ], + "unpaid": [ + "impago" + ], + "Order status URL": [ + "URL de estado de orden" + ], + "Pay URI": [ + "URI de pago" + ], + "Unknown order status. This is an error, please contact the administrator.": [ + "Estado de orden desconocido. Esto es un error, por favor contacte a su administrador" + ], + "refund created successfully": [ + "reembolzo creado satisfactoriamente" + ], + "could not create the refund": [ + "No se pudo aceder al servidor" + ], + "load newer orders": [ + "cargar nuevas ordenes" + ], + "Date": [ + "Fecha" + ], + "Refund": [ + "Reembolzar" + ], + "load older orders": [ + "cargar viejas ordenes" + ], + "No orders has been found": [ + "No se enconraron ordenes" + ], + "date": [ + "fecha" + ], + "amount": [ + "monto" + ], + "reason": [ + "razón" + ], + "Max refundable:": [ + "Máximo reembolzable:" + ], + "Reason": [ + "Razón" + ], + "duplicated": [ + "duplicado" + ], + "requested by the customer": [ + "pedido por el consumidor" + ], + "other": [ + "otro" + ], + "go to order id": [ + "ir a id de orden" + ], + "Paid": [ + "Pagado" + ], + "Refunded": [ + "Reembolzado" + ], + "Not wired": [ + "No transferido" + ], + "All": [ + "Todo" + ], + "could not create product": [ + "no se pudo crear el producto" + ], + "Sell": [ + "Venta" + ], + "Profit": [ + "Ganancia" + ], + "Sold": [ + "Vendido" + ], + "product updated successfully": [ + "producto actualizado correctamente" + ], + "could not update the product": [ + "no se pudo actualizar el producto" + ], + "product delete successfully": [ + "producto fue eliminado correctamente" + ], + "could not delete the product": [ + "no se pudo eliminar el producto" + ], + "Tips": [ + "Propinas" + ], + "Committed amount": [ + "" + ], + "Exchange initial amount": [ + "" + ], + "Merchant initial amount": [ + "" + ], + "There is no tips yet, add more pressing the + sign": [ + "No hay propinas todavÃa, agregar mas presionando el signo +" + ], + "There is no transfer yet, add more pressing the + sign": [ + "No hay transferencias todavÃa, agregar mas presionando el signo +" + ] + } + } +}; + +strings['fr'] = { + "domain": "messages", + "locale_data": { + "messages": { + "": { + "domain": "messages", + "plural_forms": "nplurals=2; plural=(n != 1);", + "lang": "" + }, + "Access denied": [ + "" + ], + "Check your token is valid": [ + "" + ], + "Couldn't access the server.": [ + "" + ], + "Could not infer instance id from url %1$s": [ + "" + ], + "HTTP status #%1$s: Server reported a problem": [ + "" + ], + "Got message: \"%1$s\" from: %2$s": [ + "" + ], + "No default instance": [ + "" + ], + "in order to use merchant backoffice, you should create the default instance": [ + "" + ], + "Server reported a problem: HTTP status #%1$s": [ + "" + ], + "Got message: %1$s from: %2$s": [ + "" + ], + "Login required": [ + "" + ], + "Please enter your auth token. Token should have \"secret-token:\" and start with Bearer or ApiKey": [ + "" + ], + "Confirm": [ + "" + ], + "The value %1$s is invalid for a payment url": [ + "" + ], + "pick a date": [ + "" + ], + "clear": [ + "" + ], + "never": [ + "" + ], + "Image should be smaller than 1 MB": [ + "" + ], + "Product id": [ + "" + ], + "Description": [ + "" + ], + "Name": [ + "" + ], + "loading...": [ + "" + ], + "no products found": [ + "" + ], + "no results": [ + "" + ], + "Deleting": [ + "" + ], + "Changing": [ + "" + ], + "Manage token": [ + "" + ], + "Update": [ + "" + ], + "Remove": [ + "" + ], + "Cancel": [ + "" + ], + "Manage stock": [ + "" + ], + "Infinite": [ + "" + ], + "lost cannot be greater that current + incoming (max %1$s)": [ + "" + ], + "current stock will change from %1$s to %2$s": [ + "" + ], + "current stock will stay at %1$s": [ + "" + ], + "Incoming": [ + "" + ], + "Lost": [ + "" + ], + "Current": [ + "" + ], + "without stock": [ + "" + ], + "Next restock": [ + "" + ], + "Delivery address": [ + "" + ], + "Country": [ + "" + ], + "Address": [ + "" + ], + "Building number": [ + "" + ], + "Building name": [ + "" + ], + "Street": [ + "" + ], + "Post code": [ + "" + ], + "Town location": [ + "" + ], + "Town": [ + "" + ], + "District": [ + "" + ], + "Country subdivision": [ + "" + ], + "this product has no taxes": [ + "" + ], + "Amount": [ + "" + ], + "currency and value separated with colon": [ + "" + ], + "Add": [ + "" + ], + "Instance": [ + "" + ], + "Settings": [ + "" + ], + "Orders": [ + "" + ], + "Products": [ + "" + ], + "Transfers": [ + "" + ], + "Connection": [ + "" + ], + "Instances": [ + "" + ], + "New": [ + "" + ], + "List": [ + "" + ], + "Log out": [ + "" + ], + "Clear": [ + "" + ], + "should be the same": [ + "" + ], + "cannot be the same as before": [ + "" + ], + "You are updating the authorization token from instance %1$s with id %2$s": [ + "" + ], + "Old token": [ + "" + ], + "New token": [ + "" + ], + "Clearing the auth token will mean public access to the instance": [ + "" + ], + "ID": [ + "" + ], + "Image": [ + "" + ], + "Unit": [ + "" + ], + "Price": [ + "" + ], + "Stock": [ + "" + ], + "Taxes": [ + "" + ], + "Server not found": [ + "" + ], + "Couldn't access the server": [ + "" + ], + "Got message %1$s from %2$s": [ + "" + ], + "Unexpected Error": [ + "" + ], + "Auth token": [ + "" + ], + "Account address": [ + "" + ], + "Default max deposit fee": [ + "" + ], + "Default max wire fee": [ + "" + ], + "Default wire fee amortization": [ + "" + ], + "Jurisdiction": [ + "" + ], + "Default pay delay": [ + "" + ], + "Default wire transfer delay": [ + "" + ], + "could not create instance": [ + "" + ], + "Delete": [ + "" + ], + "Edit": [ + "" + ], + "There is no instances yet, add more pressing the + sign": [ + "" + ], + "Inventory products": [ + "" + ], + "Total price": [ + "" + ], + "Total tax": [ + "" + ], + "Order price": [ + "" + ], + "Net": [ + "" + ], + "Summary": [ + "" + ], + "Payments options": [ + "" + ], + "Auto refund deadline": [ + "" + ], + "Refund deadline": [ + "" + ], + "Pay deadline": [ + "" + ], + "Delivery date": [ + "" + ], + "Location": [ + "" + ], + "Max fee": [ + "" + ], + "Max wire fee": [ + "" + ], + "Wire fee amortization": [ + "" + ], + "Fullfilment url": [ + "" + ], + "Extra information": [ + "" + ], + "select a product first": [ + "" + ], + "should be greater than 0": [ + "" + ], + "cannot be greater than current stock and quantity previously added. max: %1$s": [ + "" + ], + "cannot be greater than current stock %1$s": [ + "" + ], + "Quantity": [ + "" + ], + "Order": [ + "" + ], + "claimed": [ + "" + ], + "copy url": [ + "" + ], + "pay at": [ + "" + ], + "created at": [ + "" + ], + "Timeline": [ + "" + ], + "Payment details": [ + "" + ], + "Order status": [ + "" + ], + "Product list": [ + "" + ], + "paid": [ + "" + ], + "wired": [ + "" + ], + "refunded": [ + "" + ], + "refund": [ + "" + ], + "Refunded amount": [ + "" + ], + "Deposit total": [ + "" + ], + "unpaid": [ + "" + ], + "Order status URL": [ + "" + ], + "Pay URI": [ + "" + ], + "Unknown order status. This is an error, please contact the administrator.": [ + "" + ], + "refund created successfully": [ + "" + ], + "could not create the refund": [ + "" + ], + "load newer orders": [ + "" + ], + "Date": [ + "" + ], + "Refund": [ + "" + ], + "load older orders": [ + "" + ], + "No orders has been found": [ + "" + ], + "date": [ + "" + ], + "amount": [ + "" + ], + "reason": [ + "" + ], + "Max refundable:": [ + "" + ], + "Reason": [ + "" + ], + "duplicated": [ + "" + ], + "requested by the customer": [ + "" + ], + "other": [ + "" + ], + "go to order id": [ + "" + ], + "Paid": [ + "" + ], + "Refunded": [ + "" + ], + "Not wired": [ + "" + ], + "All": [ + "" + ], + "could not create product": [ + "" + ], + "Sell": [ + "" + ], + "Profit": [ + "" + ], + "Sold": [ + "" + ], + "product updated successfully": [ + "" + ], + "could not update the product": [ + "" + ], + "product delete successfully": [ + "" + ], + "could not delete the product": [ + "" + ], + "Tips": [ + "" + ], + "Committed amount": [ + "" + ], + "Exchange initial amount": [ + "" + ], + "Merchant initial amount": [ + "" + ], + "There is no tips yet, add more pressing the + sign": [ + "" + ], + "There is no transfer yet, add more pressing the + sign": [ + "" + ] + } + } +}; + +strings['it'] = { + "domain": "messages", + "locale_data": { + "messages": { + "": { + "domain": "messages", + "plural_forms": "nplurals=2; plural=(n != 1);", + "lang": "" + }, + "Access denied": [ + "" + ], + "Check your token is valid": [ + "" + ], + "Couldn't access the server.": [ + "" + ], + "Could not infer instance id from url %1$s": [ + "" + ], + "HTTP status #%1$s: Server reported a problem": [ + "" + ], + "Got message: \"%1$s\" from: %2$s": [ + "" + ], + "No default instance": [ + "" + ], + "in order to use merchant backoffice, you should create the default instance": [ + "" + ], + "Server reported a problem: HTTP status #%1$s": [ + "" + ], + "Got message: %1$s from: %2$s": [ + "" + ], + "Login required": [ + "" + ], + "Please enter your auth token. Token should have \"secret-token:\" and start with Bearer or ApiKey": [ + "" + ], + "Confirm": [ + "" + ], + "The value %1$s is invalid for a payment url": [ + "" + ], + "pick a date": [ + "" + ], + "clear": [ + "" + ], + "never": [ + "" + ], + "Image should be smaller than 1 MB": [ + "" + ], + "Product id": [ + "" + ], + "Description": [ + "" + ], + "Name": [ + "" + ], + "loading...": [ + "" + ], + "no products found": [ + "" + ], + "no results": [ + "" + ], + "Deleting": [ + "" + ], + "Changing": [ + "" + ], + "Manage token": [ + "" + ], + "Update": [ + "" + ], + "Remove": [ + "" + ], + "Cancel": [ + "" + ], + "Manage stock": [ + "" + ], + "Infinite": [ + "" + ], + "lost cannot be greater that current + incoming (max %1$s)": [ + "" + ], + "current stock will change from %1$s to %2$s": [ + "" + ], + "current stock will stay at %1$s": [ + "" + ], + "Incoming": [ + "" + ], + "Lost": [ + "" + ], + "Current": [ + "" + ], + "without stock": [ + "" + ], + "Next restock": [ + "" + ], + "Delivery address": [ + "" + ], + "Country": [ + "" + ], + "Address": [ + "" + ], + "Building number": [ + "" + ], + "Building name": [ + "" + ], + "Street": [ + "" + ], + "Post code": [ + "" + ], + "Town location": [ + "" + ], + "Town": [ + "" + ], + "District": [ + "" + ], + "Country subdivision": [ + "" + ], + "this product has no taxes": [ + "" + ], + "Amount": [ + "" + ], + "currency and value separated with colon": [ + "" + ], + "Add": [ + "" + ], + "Instance": [ + "" + ], + "Settings": [ + "" + ], + "Orders": [ + "" + ], + "Products": [ + "" + ], + "Transfers": [ + "" + ], + "Connection": [ + "" + ], + "Instances": [ + "" + ], + "New": [ + "" + ], + "List": [ + "" + ], + "Log out": [ + "" + ], + "Clear": [ + "" + ], + "should be the same": [ + "" + ], + "cannot be the same as before": [ + "" + ], + "You are updating the authorization token from instance %1$s with id %2$s": [ + "" + ], + "Old token": [ + "" + ], + "New token": [ + "" + ], + "Clearing the auth token will mean public access to the instance": [ + "" + ], + "ID": [ + "" + ], + "Image": [ + "" + ], + "Unit": [ + "" + ], + "Price": [ + "" + ], + "Stock": [ + "" + ], + "Taxes": [ + "" + ], + "Server not found": [ + "" + ], + "Couldn't access the server": [ + "" + ], + "Got message %1$s from %2$s": [ + "" + ], + "Unexpected Error": [ + "" + ], + "Auth token": [ + "" + ], + "Account address": [ + "" + ], + "Default max deposit fee": [ + "" + ], + "Default max wire fee": [ + "" + ], + "Default wire fee amortization": [ + "" + ], + "Jurisdiction": [ + "" + ], + "Default pay delay": [ + "" + ], + "Default wire transfer delay": [ + "" + ], + "could not create instance": [ + "" + ], + "Delete": [ + "" + ], + "Edit": [ + "" + ], + "There is no instances yet, add more pressing the + sign": [ + "" + ], + "Inventory products": [ + "" + ], + "Total price": [ + "" + ], + "Total tax": [ + "" + ], + "Order price": [ + "" + ], + "Net": [ + "" + ], + "Summary": [ + "" + ], + "Payments options": [ + "" + ], + "Auto refund deadline": [ + "" + ], + "Refund deadline": [ + "" + ], + "Pay deadline": [ + "" + ], + "Delivery date": [ + "" + ], + "Location": [ + "" + ], + "Max fee": [ + "" + ], + "Max wire fee": [ + "" + ], + "Wire fee amortization": [ + "" + ], + "Fullfilment url": [ + "" + ], + "Extra information": [ + "" + ], + "select a product first": [ + "" + ], + "should be greater than 0": [ + "" + ], + "cannot be greater than current stock and quantity previously added. max: %1$s": [ + "" + ], + "cannot be greater than current stock %1$s": [ + "" + ], + "Quantity": [ + "" + ], + "Order": [ + "" + ], + "claimed": [ + "" + ], + "copy url": [ + "" + ], + "pay at": [ + "" + ], + "created at": [ + "" + ], + "Timeline": [ + "" + ], + "Payment details": [ + "" + ], + "Order status": [ + "" + ], + "Product list": [ + "" + ], + "paid": [ + "" + ], + "wired": [ + "" + ], + "refunded": [ + "" + ], + "refund": [ + "" + ], + "Refunded amount": [ + "" + ], + "Deposit total": [ + "" + ], + "unpaid": [ + "" + ], + "Order status URL": [ + "" + ], + "Pay URI": [ + "" + ], + "Unknown order status. This is an error, please contact the administrator.": [ + "" + ], + "refund created successfully": [ + "" + ], + "could not create the refund": [ + "" + ], + "load newer orders": [ + "" + ], + "Date": [ + "" + ], + "Refund": [ + "" + ], + "load older orders": [ + "" + ], + "No orders has been found": [ + "" + ], + "date": [ + "" + ], + "amount": [ + "" + ], + "reason": [ + "" + ], + "Max refundable:": [ + "" + ], + "Reason": [ + "" + ], + "duplicated": [ + "" + ], + "requested by the customer": [ + "" + ], + "other": [ + "" + ], + "go to order id": [ + "" + ], + "Paid": [ + "" + ], + "Refunded": [ + "" + ], + "Not wired": [ + "" + ], + "All": [ + "" + ], + "could not create product": [ + "" + ], + "Sell": [ + "" + ], + "Profit": [ + "" + ], + "Sold": [ + "" + ], + "product updated successfully": [ + "" + ], + "could not update the product": [ + "" + ], + "product delete successfully": [ + "" + ], + "could not delete the product": [ + "" + ], + "Tips": [ + "" + ], + "Committed amount": [ + "" + ], + "Exchange initial amount": [ + "" + ], + "Merchant initial amount": [ + "" + ], + "There is no tips yet, add more pressing the + sign": [ + "" + ], + "There is no transfer yet, add more pressing the + sign": [ + "" + ] + } + } +}; + +strings['sv'] = { + "domain": "messages", + "locale_data": { + "messages": { + "": { + "domain": "messages", + "plural_forms": "nplurals=2; plural=(n != 1);", + "lang": "" + }, + "Access denied": [ + "" + ], + "Check your token is valid": [ + "" + ], + "Couldn't access the server.": [ + "" + ], + "Could not infer instance id from url %1$s": [ + "" + ], + "HTTP status #%1$s: Server reported a problem": [ + "" + ], + "Got message: \"%1$s\" from: %2$s": [ + "" + ], + "No default instance": [ + "" + ], + "in order to use merchant backoffice, you should create the default instance": [ + "" + ], + "Server reported a problem: HTTP status #%1$s": [ + "" + ], + "Got message: %1$s from: %2$s": [ + "" + ], + "Login required": [ + "" + ], + "Please enter your auth token. Token should have \"secret-token:\" and start with Bearer or ApiKey": [ + "" + ], + "Confirm": [ + "" + ], + "The value %1$s is invalid for a payment url": [ + "" + ], + "pick a date": [ + "" + ], + "clear": [ + "" + ], + "never": [ + "" + ], + "Image should be smaller than 1 MB": [ + "" + ], + "Product id": [ + "" + ], + "Description": [ + "" + ], + "Name": [ + "" + ], + "loading...": [ + "" + ], + "no products found": [ + "" + ], + "no results": [ + "" + ], + "Deleting": [ + "" + ], + "Changing": [ + "" + ], + "Manage token": [ + "" + ], + "Update": [ + "" + ], + "Remove": [ + "" + ], + "Cancel": [ + "" + ], + "Manage stock": [ + "" + ], + "Infinite": [ + "" + ], + "lost cannot be greater that current + incoming (max %1$s)": [ + "" + ], + "current stock will change from %1$s to %2$s": [ + "" + ], + "current stock will stay at %1$s": [ + "" + ], + "Incoming": [ + "" + ], + "Lost": [ + "" + ], + "Current": [ + "" + ], + "without stock": [ + "" + ], + "Next restock": [ + "" + ], + "Delivery address": [ + "" + ], + "Country": [ + "" + ], + "Address": [ + "" + ], + "Building number": [ + "" + ], + "Building name": [ + "" + ], + "Street": [ + "" + ], + "Post code": [ + "" + ], + "Town location": [ + "" + ], + "Town": [ + "" + ], + "District": [ + "" + ], + "Country subdivision": [ + "" + ], + "this product has no taxes": [ + "" + ], + "Amount": [ + "" + ], + "currency and value separated with colon": [ + "" + ], + "Add": [ + "" + ], + "Instance": [ + "" + ], + "Settings": [ + "" + ], + "Orders": [ + "" + ], + "Products": [ + "" + ], + "Transfers": [ + "" + ], + "Connection": [ + "" + ], + "Instances": [ + "" + ], + "New": [ + "" + ], + "List": [ + "" + ], + "Log out": [ + "" + ], + "Clear": [ + "" + ], + "should be the same": [ + "" + ], + "cannot be the same as before": [ + "" + ], + "You are updating the authorization token from instance %1$s with id %2$s": [ + "" + ], + "Old token": [ + "" + ], + "New token": [ + "" + ], + "Clearing the auth token will mean public access to the instance": [ + "" + ], + "ID": [ + "" + ], + "Image": [ + "" + ], + "Unit": [ + "" + ], + "Price": [ + "" + ], + "Stock": [ + "" + ], + "Taxes": [ + "" + ], + "Server not found": [ + "" + ], + "Couldn't access the server": [ + "" + ], + "Got message %1$s from %2$s": [ + "" + ], + "Unexpected Error": [ + "" + ], + "Auth token": [ + "" + ], + "Account address": [ + "" + ], + "Default max deposit fee": [ + "" + ], + "Default max wire fee": [ + "" + ], + "Default wire fee amortization": [ + "" + ], + "Jurisdiction": [ + "" + ], + "Default pay delay": [ + "" + ], + "Default wire transfer delay": [ + "" + ], + "could not create instance": [ + "" + ], + "Delete": [ + "" + ], + "Edit": [ + "" + ], + "There is no instances yet, add more pressing the + sign": [ + "" + ], + "Inventory products": [ + "" + ], + "Total price": [ + "" + ], + "Total tax": [ + "" + ], + "Order price": [ + "" + ], + "Net": [ + "" + ], + "Summary": [ + "" + ], + "Payments options": [ + "" + ], + "Auto refund deadline": [ + "" + ], + "Refund deadline": [ + "" + ], + "Pay deadline": [ + "" + ], + "Delivery date": [ + "" + ], + "Location": [ + "" + ], + "Max fee": [ + "" + ], + "Max wire fee": [ + "" + ], + "Wire fee amortization": [ + "" + ], + "Fullfilment url": [ + "" + ], + "Extra information": [ + "" + ], + "select a product first": [ + "" + ], + "should be greater than 0": [ + "" + ], + "cannot be greater than current stock and quantity previously added. max: %1$s": [ + "" + ], + "cannot be greater than current stock %1$s": [ + "" + ], + "Quantity": [ + "" + ], + "Order": [ + "" + ], + "claimed": [ + "" + ], + "copy url": [ + "" + ], + "pay at": [ + "" + ], + "created at": [ + "" + ], + "Timeline": [ + "" + ], + "Payment details": [ + "" + ], + "Order status": [ + "" + ], + "Product list": [ + "" + ], + "paid": [ + "" + ], + "wired": [ + "" + ], + "refunded": [ + "" + ], + "refund": [ + "" + ], + "Refunded amount": [ + "" + ], + "Deposit total": [ + "" + ], + "unpaid": [ + "" + ], + "Order status URL": [ + "" + ], + "Pay URI": [ + "" + ], + "Unknown order status. This is an error, please contact the administrator.": [ + "" + ], + "refund created successfully": [ + "" + ], + "could not create the refund": [ + "" + ], + "load newer orders": [ + "" + ], + "Date": [ + "" + ], + "Refund": [ + "" + ], + "load older orders": [ + "" + ], + "No orders has been found": [ + "" + ], + "date": [ + "" + ], + "amount": [ + "" + ], + "reason": [ + "" + ], + "Max refundable:": [ + "" + ], + "Reason": [ + "" + ], + "duplicated": [ + "" + ], + "requested by the customer": [ + "" + ], + "other": [ + "" + ], + "go to order id": [ + "" + ], + "Paid": [ + "" + ], + "Refunded": [ + "" + ], + "Not wired": [ + "" + ], + "All": [ + "" + ], + "could not create product": [ + "" + ], + "Sell": [ + "" + ], + "Profit": [ + "" + ], + "Sold": [ + "" + ], + "product updated successfully": [ + "" + ], + "could not update the product": [ + "" + ], + "product delete successfully": [ + "" + ], + "could not delete the product": [ + "" + ], + "Tips": [ + "" + ], + "Committed amount": [ + "" + ], + "Exchange initial amount": [ + "" + ], + "Merchant initial amount": [ + "" + ], + "There is no tips yet, add more pressing the + sign": [ + "" + ], + "There is no transfer yet, add more pressing the + sign": [ + "" + ] + } + } +}; + diff --git a/packages/frontend/src/i18n/sv.po b/packages/frontend/src/i18n/sv.po @@ -0,0 +1,1010 @@ +# This file is part of TALER +# (C) 2016 GNUnet e.V. +# +# 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. +# +# 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 +# TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Taler Wallet\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-11-23 00:00+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: src/ApplicationReadyRoutes.tsx:50 src/InstanceRoutes.tsx:117 +#: src/InstanceRoutes.tsx:293 +#, c-format +msgid "Access denied" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:51 src/InstanceRoutes.tsx:117 +#: src/InstanceRoutes.tsx:294 +#, c-format +msgid "Check your token is valid" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:72 +#, c-format +msgid "Couldn't access the server." +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:73 +#, c-format +msgid "Could not infer instance id from url %1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:108 +#, c-format +msgid "HTTP status #%1$s: Server reported a problem" +msgstr "" + +#: src/InstanceRoutes.tsx:109 +#, c-format +msgid "Got message: \"%1$s\" from: %2$s" +msgstr "" + +#: src/InstanceRoutes.tsx:126 +#, c-format +msgid "No default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:127 +#, c-format +msgid "" +"in order to use merchant backoffice, you should create the default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:282 +#, c-format +msgid "Server reported a problem: HTTP status #%1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:283 +#, c-format +msgid "Got message: %1$s from: %2$s" +msgstr "" + +#: src/components/exception/login.tsx:46 +#, c-format +msgid "Login required" +msgstr "" + +#: src/components/exception/login.tsx:49 +#, c-format +msgid "" +"Please enter your auth token. Token should have \"secret-token:\" and start " +"with Bearer or ApiKey" +msgstr "" + +#: src/components/exception/login.tsx:86 src/components/modal/index.tsx:53 +#: src/components/modal/index.tsx:75 src/paths/admin/create/CreatePage.tsx:140 +#: src/paths/instance/orders/create/CreatePage.tsx:337 +#: src/paths/instance/products/create/CreatePage.tsx:51 +#: src/paths/instance/products/list/Table.tsx:174 +#: src/paths/instance/products/list/Table.tsx:228 +#: src/paths/instance/products/update/UpdatePage.tsx:55 +#: src/paths/instance/update/UpdatePage.tsx:159 +#, c-format +msgid "Confirm" +msgstr "" + +#: src/components/form/InputArray.tsx:72 +#, c-format +msgid "The value %1$s is invalid for a payment url" +msgstr "" + +#: src/components/form/InputDate.tsx:67 +#: src/paths/instance/orders/list/index.tsx:123 +#, c-format +msgid "pick a date" +msgstr "" + +#: src/components/form/InputDate.tsx:81 +#, c-format +msgid "clear" +msgstr "" + +#: src/components/form/InputDate.tsx:83 +#, c-format +msgid "never" +msgstr "" + +#: src/components/form/InputImage.tsx:80 +#, c-format +msgid "Image should be smaller than 1 MB" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:59 +#, c-format +msgid "Product id" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:60 +#: src/components/product/ProductForm.tsx:99 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:122 +#: src/paths/instance/orders/list/Table.tsx:227 +#: src/paths/instance/products/list/Table.tsx:86 +#, c-format +msgid "Description" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:73 +#: src/components/form/InputTaxes.tsx:81 +#: src/paths/admin/create/CreatePage.tsx:86 src/paths/admin/list/Table.tsx:110 +#: src/paths/instance/details/DetailPage.tsx:76 +#: src/paths/instance/transfers/list/Table.tsx:112 +#: src/paths/instance/update/UpdatePage.tsx:105 +#, c-format +msgid "Name" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:102 +#, c-format +msgid "loading..." +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:108 +#, c-format +msgid "no products found" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:116 +#, c-format +msgid "no results" +msgstr "" + +#: src/components/form/InputSecured.tsx:33 +#, c-format +msgid "Deleting" +msgstr "" + +#: src/components/form/InputSecured.tsx:34 +#, c-format +msgid "Changing" +msgstr "" + +#: src/components/form/InputSecured.tsx:60 +#, c-format +msgid "Manage token" +msgstr "" + +#: src/components/form/InputSecured.tsx:83 +#, c-format +msgid "Update" +msgstr "" + +#: src/components/form/InputSecured.tsx:100 +#: src/paths/instance/orders/create/CreatePage.tsx:251 +#: src/paths/instance/orders/create/CreatePage.tsx:272 +#, c-format +msgid "Remove" +msgstr "" + +#: src/components/form/InputSecured.tsx:106 src/components/modal/index.tsx:52 +#: src/components/modal/index.tsx:73 src/paths/admin/create/CreatePage.tsx:139 +#: src/paths/instance/orders/create/CreatePage.tsx:336 +#: src/paths/instance/products/create/CreatePage.tsx:50 +#: src/paths/instance/products/list/Table.tsx:166 +#: src/paths/instance/products/list/Table.tsx:218 +#: src/paths/instance/products/update/UpdatePage.tsx:54 +#: src/paths/instance/update/UpdatePage.tsx:158 +#, c-format +msgid "Cancel" +msgstr "" + +#: src/components/form/InputStock.tsx:90 +#, c-format +msgid "Manage stock" +msgstr "" + +#: src/components/form/InputStock.tsx:92 +#, c-format +msgid "Infinite" +msgstr "" + +#: src/components/form/InputStock.tsx:104 +#, c-format +msgid "lost cannot be greater that current + incoming (max %1$s)" +msgstr "" + +#: src/components/form/InputStock.tsx:110 +#, c-format +msgid "current stock will change from %1$s to %2$s" +msgstr "" + +#: src/components/form/InputStock.tsx:111 +#, c-format +msgid "current stock will stay at %1$s" +msgstr "" + +#: src/components/form/InputStock.tsx:128 +#: src/paths/instance/products/list/Table.tsx:204 +#, c-format +msgid "Incoming" +msgstr "" + +#: src/components/form/InputStock.tsx:129 +#: src/paths/instance/products/list/Table.tsx:205 +#, c-format +msgid "Lost" +msgstr "" + +#: src/components/form/InputStock.tsx:141 +#, c-format +msgid "Current" +msgstr "" + +#: src/components/form/InputStock.tsx:144 +#, c-format +msgid "without stock" +msgstr "" + +#: src/components/form/InputStock.tsx:149 +#, c-format +msgid "Next restock" +msgstr "" + +#: src/components/form/InputStock.tsx:151 +#, c-format +msgid "Delivery address" +msgstr "" + +#: src/components/form/InputStock.tsx:153 +#: src/paths/admin/create/CreatePage.tsx:99 +#: src/paths/admin/create/CreatePage.tsx:116 +#: src/paths/instance/orders/create/CreatePage.tsx:308 +#: src/paths/instance/update/UpdatePage.tsx:118 +#: src/paths/instance/update/UpdatePage.tsx:135 +#, c-format +msgid "Country" +msgstr "" + +#: src/components/form/InputStock.tsx:156 +#: src/paths/admin/create/CreatePage.tsx:98 +#: src/paths/admin/create/CreatePage.tsx:101 +#: src/paths/admin/create/CreatePage.tsx:118 +#: src/paths/instance/orders/create/CreatePage.tsx:310 +#: src/paths/instance/update/UpdatePage.tsx:117 +#: src/paths/instance/update/UpdatePage.tsx:120 +#: src/paths/instance/update/UpdatePage.tsx:137 +#, c-format +msgid "Address" +msgstr "" + +#: src/components/form/InputStock.tsx:161 +#: src/paths/admin/create/CreatePage.tsx:105 +#: src/paths/admin/create/CreatePage.tsx:122 +#: src/paths/instance/orders/create/CreatePage.tsx:314 +#: src/paths/instance/update/UpdatePage.tsx:124 +#: src/paths/instance/update/UpdatePage.tsx:141 +#, c-format +msgid "Building number" +msgstr "" + +#: src/components/form/InputStock.tsx:162 +#: src/paths/admin/create/CreatePage.tsx:106 +#: src/paths/admin/create/CreatePage.tsx:123 +#: src/paths/instance/orders/create/CreatePage.tsx:315 +#: src/paths/instance/update/UpdatePage.tsx:125 +#: src/paths/instance/update/UpdatePage.tsx:142 +#, c-format +msgid "Building name" +msgstr "" + +#: src/components/form/InputStock.tsx:163 +#: src/paths/admin/create/CreatePage.tsx:107 +#: src/paths/admin/create/CreatePage.tsx:124 +#: src/paths/instance/orders/create/CreatePage.tsx:316 +#: src/paths/instance/update/UpdatePage.tsx:126 +#: src/paths/instance/update/UpdatePage.tsx:143 +#, c-format +msgid "Street" +msgstr "" + +#: src/components/form/InputStock.tsx:164 +#: src/paths/admin/create/CreatePage.tsx:108 +#: src/paths/admin/create/CreatePage.tsx:125 +#: src/paths/instance/orders/create/CreatePage.tsx:317 +#: src/paths/instance/update/UpdatePage.tsx:127 +#: src/paths/instance/update/UpdatePage.tsx:144 +#, c-format +msgid "Post code" +msgstr "" + +#: src/components/form/InputStock.tsx:165 +#: src/paths/admin/create/CreatePage.tsx:109 +#: src/paths/admin/create/CreatePage.tsx:126 +#: src/paths/instance/orders/create/CreatePage.tsx:318 +#: src/paths/instance/update/UpdatePage.tsx:128 +#: src/paths/instance/update/UpdatePage.tsx:145 +#, c-format +msgid "Town location" +msgstr "" + +#: src/components/form/InputStock.tsx:166 +#: src/paths/admin/create/CreatePage.tsx:110 +#: src/paths/admin/create/CreatePage.tsx:127 +#: src/paths/instance/orders/create/CreatePage.tsx:319 +#: src/paths/instance/update/UpdatePage.tsx:129 +#: src/paths/instance/update/UpdatePage.tsx:146 +#, c-format +msgid "Town" +msgstr "" + +#: src/components/form/InputStock.tsx:167 +#: src/paths/admin/create/CreatePage.tsx:111 +#: src/paths/admin/create/CreatePage.tsx:128 +#: src/paths/instance/orders/create/CreatePage.tsx:320 +#: src/paths/instance/update/UpdatePage.tsx:130 +#: src/paths/instance/update/UpdatePage.tsx:147 +#, c-format +msgid "District" +msgstr "" + +#: src/components/form/InputStock.tsx:168 +#: src/paths/admin/create/CreatePage.tsx:112 +#: src/paths/admin/create/CreatePage.tsx:129 +#: src/paths/instance/orders/create/CreatePage.tsx:321 +#: src/paths/instance/update/UpdatePage.tsx:131 +#: src/paths/instance/update/UpdatePage.tsx:148 +#, c-format +msgid "Country subdivision" +msgstr "" + +#: src/components/form/InputTaxes.tsx:73 +#, c-format +msgid "this product has no taxes" +msgstr "" + +#: src/components/form/InputTaxes.tsx:77 +#: src/paths/instance/orders/details/DetailPage.tsx:145 +#: src/paths/instance/orders/details/DetailPage.tsx:296 +#: src/paths/instance/orders/list/Table.tsx:116 +#, c-format +msgid "Amount" +msgstr "" + +#: src/components/form/InputTaxes.tsx:78 +#, c-format +msgid "currency and value separated with colon" +msgstr "" + +#: src/components/form/InputTaxes.tsx:84 +#: src/paths/instance/orders/create/InventoryProductForm.tsx:78 +#, c-format +msgid "Add" +msgstr "" + +#: src/components/menu/SideBar.tsx:53 +#, c-format +msgid "Instance" +msgstr "" + +#: src/components/menu/SideBar.tsx:59 +#, c-format +msgid "Settings" +msgstr "" + +#: src/components/menu/SideBar.tsx:65 +#: src/paths/instance/orders/list/Table.tsx:60 +#, c-format +msgid "Orders" +msgstr "" + +#: src/components/menu/SideBar.tsx:71 +#: src/paths/instance/orders/create/CreatePage.tsx:257 +#: src/paths/instance/products/list/Table.tsx:48 +#, c-format +msgid "Products" +msgstr "" + +#: src/components/menu/SideBar.tsx:77 +#: src/paths/instance/transfers/list/Table.tsx:59 +#, c-format +msgid "Transfers" +msgstr "" + +#: src/components/menu/SideBar.tsx:87 +#, c-format +msgid "Connection" +msgstr "" + +#: src/components/menu/SideBar.tsx:112 src/paths/admin/list/Table.tsx:57 +#, c-format +msgid "Instances" +msgstr "" + +#: src/components/menu/SideBar.tsx:116 +#, c-format +msgid "New" +msgstr "" + +#: src/components/menu/SideBar.tsx:122 +#, c-format +msgid "List" +msgstr "" + +#: src/components/menu/SideBar.tsx:129 +#, c-format +msgid "Log out" +msgstr "" + +#: src/components/modal/index.tsx:74 +#, c-format +msgid "Clear" +msgstr "" + +#: src/components/modal/index.tsx:110 src/components/modal/index.tsx:111 +#, c-format +msgid "should be the same" +msgstr "" + +#: src/components/modal/index.tsx:111 +#, c-format +msgid "cannot be the same as before" +msgstr "" + +#: src/components/modal/index.tsx:114 +#, c-format +msgid "" +"You are updating the authorization token from instance %1$s with id %2$s" +msgstr "" + +#: src/components/modal/index.tsx:124 +#, c-format +msgid "Old token" +msgstr "" + +#: src/components/modal/index.tsx:125 +#, c-format +msgid "New token" +msgstr "" + +#: src/components/modal/index.tsx:127 +#, c-format +msgid "Clearing the auth token will mean public access to the instance" +msgstr "" + +#: src/components/product/ProductForm.tsx:96 +#: src/paths/admin/create/CreatePage.tsx:84 src/paths/admin/list/Table.tsx:109 +#: src/paths/instance/transfers/list/Table.tsx:111 +#, c-format +msgid "ID" +msgstr "" + +#: src/components/product/ProductForm.tsx:98 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:121 +#: src/paths/instance/products/list/Table.tsx:85 +#, c-format +msgid "Image" +msgstr "" + +#: src/components/product/ProductForm.tsx:100 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:123 +#, c-format +msgid "Unit" +msgstr "" + +#: src/components/product/ProductForm.tsx:101 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:124 +#: src/paths/instance/products/list/Table.tsx:162 +#: src/paths/instance/products/list/Table.tsx:214 +#, c-format +msgid "Price" +msgstr "" + +#: src/components/product/ProductForm.tsx:103 +#: src/paths/instance/products/list/Table.tsx:90 +#, c-format +msgid "Stock" +msgstr "" + +#: src/components/product/ProductForm.tsx:105 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:128 +#: src/paths/instance/products/list/Table.tsx:88 +#, c-format +msgid "Taxes" +msgstr "" + +#: src/index.tsx:75 +#, c-format +msgid "Server not found" +msgstr "" + +#: src/index.tsx:85 +#, c-format +msgid "Couldn't access the server" +msgstr "" + +#: src/index.tsx:87 src/index.tsx:99 +#, c-format +msgid "Got message %1$s from %2$s" +msgstr "" + +#: src/index.tsx:97 +#, c-format +msgid "Unexpected Error" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:88 +#: src/paths/instance/update/UpdatePage.tsx:107 +#, c-format +msgid "Auth token" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:90 +#: src/paths/instance/details/DetailPage.tsx:77 +#: src/paths/instance/update/UpdatePage.tsx:109 +#, c-format +msgid "Account address" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:92 +#: src/paths/instance/update/UpdatePage.tsx:111 +#, c-format +msgid "Default max deposit fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:94 +#: src/paths/instance/update/UpdatePage.tsx:113 +#, c-format +msgid "Default max wire fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:96 +#: src/paths/instance/update/UpdatePage.tsx:115 +#, c-format +msgid "Default wire fee amortization" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:115 +#: src/paths/instance/update/UpdatePage.tsx:134 +#, c-format +msgid "Jurisdiction" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:132 +#: src/paths/instance/update/UpdatePage.tsx:151 +#, c-format +msgid "Default pay delay" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:134 +#: src/paths/instance/update/UpdatePage.tsx:153 +#, c-format +msgid "Default wire transfer delay" +msgstr "" + +#: src/paths/admin/create/index.tsx:58 +#, c-format +msgid "could not create instance" +msgstr "" + +#: src/paths/admin/list/Table.tsx:63 src/paths/admin/list/Table.tsx:131 +#, c-format +msgid "Delete" +msgstr "" + +#: src/paths/admin/list/Table.tsx:128 +#, c-format +msgid "Edit" +msgstr "" + +#: src/paths/admin/list/Table.tsx:149 +#: src/paths/instance/products/list/Table.tsx:245 +#, c-format +msgid "There is no instances yet, add more pressing the + sign" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:236 +#, c-format +msgid "Inventory products" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:285 +#, c-format +msgid "Total price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:286 +#, c-format +msgid "Total tax" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:288 +#: src/paths/instance/orders/create/CreatePage.tsx:296 +#, c-format +msgid "Order price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:294 +#, c-format +msgid "Net" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:299 +#: src/paths/instance/orders/details/DetailPage.tsx:144 +#: src/paths/instance/orders/details/DetailPage.tsx:295 +#: src/paths/instance/orders/list/Table.tsx:117 +#, c-format +msgid "Summary" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:301 +#, c-format +msgid "Payments options" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:302 +#, c-format +msgid "Auto refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:303 +#, c-format +msgid "Refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:304 +#, c-format +msgid "Pay deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:306 +#, c-format +msgid "Delivery date" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:307 +#, c-format +msgid "Location" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:324 +#, c-format +msgid "Max fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:325 +#, c-format +msgid "Max wire fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:326 +#, c-format +msgid "Wire fee amortization" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:327 +#, c-format +msgid "Fullfilment url" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:330 +#, c-format +msgid "Extra information" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:44 +#, c-format +msgid "select a product first" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:51 +#, c-format +msgid "should be greater than 0" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:58 +#, c-format +msgid "" +"cannot be greater than current stock and quantity previously added. max: %1$s" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:64 +#, c-format +msgid "cannot be greater than current stock %1$s" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:76 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:126 +#, c-format +msgid "Quantity" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:92 +#: src/paths/instance/orders/details/DetailPage.tsx:235 +#: src/paths/instance/orders/details/DetailPage.tsx:333 +#, c-format +msgid "Order" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:93 +#, c-format +msgid "claimed" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:110 +#: src/paths/instance/orders/details/DetailPage.tsx:261 +#: src/paths/instance/orders/list/Table.tsx:136 +#, c-format +msgid "copy url" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:126 +#: src/paths/instance/orders/details/DetailPage.tsx:349 +#, c-format +msgid "pay at" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:127 +#: src/paths/instance/orders/details/DetailPage.tsx:350 +#, c-format +msgid "created at" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:138 +#: src/paths/instance/orders/details/DetailPage.tsx:289 +#, c-format +msgid "Timeline" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:142 +#: src/paths/instance/orders/details/DetailPage.tsx:293 +#, c-format +msgid "Payment details" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:146 +#: src/paths/instance/orders/details/DetailPage.tsx:299 +#: src/paths/instance/orders/details/DetailPage.tsx:363 +#, c-format +msgid "Order status" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:156 +#: src/paths/instance/orders/details/DetailPage.tsx:308 +#, c-format +msgid "Product list" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:236 +#, c-format +msgid "paid" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:238 +#, c-format +msgid "wired" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:241 +#, c-format +msgid "refunded" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:258 +#, c-format +msgid "refund" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:297 +#, c-format +msgid "Refunded amount" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:298 +#, c-format +msgid "Deposit total" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:336 +#, c-format +msgid "unpaid" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:364 +#, c-format +msgid "Order status URL" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:365 +#, c-format +msgid "Pay URI" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:383 +#, c-format +msgid "" +"Unknown order status. This is an error, please contact the administrator." +msgstr "" + +#: src/paths/instance/orders/details/index.tsx:56 +#: src/paths/instance/orders/list/index.tsx:147 +#, c-format +msgid "refund created successfully" +msgstr "" + +#: src/paths/instance/orders/details/index.tsx:59 +#: src/paths/instance/orders/list/index.tsx:150 +#, c-format +msgid "could not create the refund" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:111 +#, c-format +msgid "load newer orders" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:115 +#, c-format +msgid "Date" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:131 +#: src/paths/instance/orders/list/Table.tsx:223 +#, c-format +msgid "Refund" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:145 +#, c-format +msgid "load older orders" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:154 +#, c-format +msgid "No orders has been found" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:202 +#, c-format +msgid "date" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:203 +#, c-format +msgid "amount" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:204 +#, c-format +msgid "reason" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:224 +#, c-format +msgid "Max refundable:" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "Reason" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "duplicated" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "requested by the customer" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "other" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:91 +#, c-format +msgid "go to order id" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:107 +#, c-format +msgid "Paid" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:108 +#, c-format +msgid "Refunded" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:109 +#, c-format +msgid "Not wired" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:110 +#, c-format +msgid "All" +msgstr "" + +#: src/paths/instance/products/create/index.tsx:48 +#: src/paths/instance/products/update/index.tsx:64 +#, c-format +msgid "could not create product" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:87 +#, c-format +msgid "Sell" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:89 +#, c-format +msgid "Profit" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:91 +#, c-format +msgid "Sold" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:59 +#, c-format +msgid "product updated successfully" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:62 +#, c-format +msgid "could not update the product" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:70 +#, c-format +msgid "product delete successfully" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:73 +#, c-format +msgid "could not delete the product" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:59 +#, c-format +msgid "Tips" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:111 +#, c-format +msgid "Committed amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:112 +#, c-format +msgid "Exchange initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:113 +#, c-format +msgid "Merchant initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:148 +#, c-format +msgid "There is no tips yet, add more pressing the + sign" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:147 +#, c-format +msgid "There is no transfer yet, add more pressing the + sign" +msgstr "" diff --git a/packages/frontend/src/i18n/taler-merchant-backoffice.pot b/packages/frontend/src/i18n/taler-merchant-backoffice.pot @@ -0,0 +1,1007 @@ +# 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/> +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Taler Wallet\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-11-23 00:00+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: src/ApplicationReadyRoutes.tsx:50 src/InstanceRoutes.tsx:117 +#: src/InstanceRoutes.tsx:293 +#, c-format +msgid "Access denied" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:51 src/InstanceRoutes.tsx:117 +#: src/InstanceRoutes.tsx:294 +#, c-format +msgid "Check your token is valid" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:72 +#, c-format +msgid "Couldn't access the server." +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:73 +#, c-format +msgid "Could not infer instance id from url %1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:108 +#, c-format +msgid "HTTP status #%1$s: Server reported a problem" +msgstr "" + +#: src/InstanceRoutes.tsx:109 +#, c-format +msgid "Got message: \"%1$s\" from: %2$s" +msgstr "" + +#: src/InstanceRoutes.tsx:126 +#, c-format +msgid "No default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:127 +#, c-format +msgid "" +"in order to use merchant backoffice, you should create the default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:282 +#, c-format +msgid "Server reported a problem: HTTP status #%1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:283 +#, c-format +msgid "Got message: %1$s from: %2$s" +msgstr "" + +#: src/components/exception/login.tsx:46 +#, c-format +msgid "Login required" +msgstr "" + +#: src/components/exception/login.tsx:49 +#, c-format +msgid "" +"Please enter your auth token. Token should have \"secret-token:\" and start " +"with Bearer or ApiKey" +msgstr "" + +#: src/components/exception/login.tsx:86 src/components/modal/index.tsx:53 +#: src/components/modal/index.tsx:75 src/paths/admin/create/CreatePage.tsx:140 +#: src/paths/instance/orders/create/CreatePage.tsx:337 +#: src/paths/instance/products/create/CreatePage.tsx:51 +#: src/paths/instance/products/list/Table.tsx:174 +#: src/paths/instance/products/list/Table.tsx:228 +#: src/paths/instance/products/update/UpdatePage.tsx:55 +#: src/paths/instance/update/UpdatePage.tsx:159 +#, c-format +msgid "Confirm" +msgstr "" + +#: src/components/form/InputArray.tsx:72 +#, c-format +msgid "The value %1$s is invalid for a payment url" +msgstr "" + +#: src/components/form/InputDate.tsx:67 +#: src/paths/instance/orders/list/index.tsx:123 +#, c-format +msgid "pick a date" +msgstr "" + +#: src/components/form/InputDate.tsx:81 +#, c-format +msgid "clear" +msgstr "" + +#: src/components/form/InputDate.tsx:83 +#, c-format +msgid "never" +msgstr "" + +#: src/components/form/InputImage.tsx:80 +#, c-format +msgid "Image should be smaller than 1 MB" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:59 +#, c-format +msgid "Product id" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:60 +#: src/components/product/ProductForm.tsx:99 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:122 +#: src/paths/instance/orders/list/Table.tsx:227 +#: src/paths/instance/products/list/Table.tsx:86 +#, c-format +msgid "Description" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:73 +#: src/components/form/InputTaxes.tsx:81 +#: src/paths/admin/create/CreatePage.tsx:86 src/paths/admin/list/Table.tsx:110 +#: src/paths/instance/details/DetailPage.tsx:76 +#: src/paths/instance/transfers/list/Table.tsx:112 +#: src/paths/instance/update/UpdatePage.tsx:105 +#, c-format +msgid "Name" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:102 +#, c-format +msgid "loading..." +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:108 +#, c-format +msgid "no products found" +msgstr "" + +#: src/components/form/InputSearchProduct.tsx:116 +#, c-format +msgid "no results" +msgstr "" + +#: src/components/form/InputSecured.tsx:33 +#, c-format +msgid "Deleting" +msgstr "" + +#: src/components/form/InputSecured.tsx:34 +#, c-format +msgid "Changing" +msgstr "" + +#: src/components/form/InputSecured.tsx:60 +#, c-format +msgid "Manage token" +msgstr "" + +#: src/components/form/InputSecured.tsx:83 +#, c-format +msgid "Update" +msgstr "" + +#: src/components/form/InputSecured.tsx:100 +#: src/paths/instance/orders/create/CreatePage.tsx:251 +#: src/paths/instance/orders/create/CreatePage.tsx:272 +#, c-format +msgid "Remove" +msgstr "" + +#: src/components/form/InputSecured.tsx:106 src/components/modal/index.tsx:52 +#: src/components/modal/index.tsx:73 src/paths/admin/create/CreatePage.tsx:139 +#: src/paths/instance/orders/create/CreatePage.tsx:336 +#: src/paths/instance/products/create/CreatePage.tsx:50 +#: src/paths/instance/products/list/Table.tsx:166 +#: src/paths/instance/products/list/Table.tsx:218 +#: src/paths/instance/products/update/UpdatePage.tsx:54 +#: src/paths/instance/update/UpdatePage.tsx:158 +#, c-format +msgid "Cancel" +msgstr "" + +#: src/components/form/InputStock.tsx:90 +#, c-format +msgid "Manage stock" +msgstr "" + +#: src/components/form/InputStock.tsx:92 +#, c-format +msgid "Infinite" +msgstr "" + +#: src/components/form/InputStock.tsx:104 +#, c-format +msgid "lost cannot be greater that current + incoming (max %1$s)" +msgstr "" + +#: src/components/form/InputStock.tsx:110 +#, c-format +msgid "current stock will change from %1$s to %2$s" +msgstr "" + +#: src/components/form/InputStock.tsx:111 +#, c-format +msgid "current stock will stay at %1$s" +msgstr "" + +#: src/components/form/InputStock.tsx:128 +#: src/paths/instance/products/list/Table.tsx:204 +#, c-format +msgid "Incoming" +msgstr "" + +#: src/components/form/InputStock.tsx:129 +#: src/paths/instance/products/list/Table.tsx:205 +#, c-format +msgid "Lost" +msgstr "" + +#: src/components/form/InputStock.tsx:141 +#, c-format +msgid "Current" +msgstr "" + +#: src/components/form/InputStock.tsx:144 +#, c-format +msgid "without stock" +msgstr "" + +#: src/components/form/InputStock.tsx:149 +#, c-format +msgid "Next restock" +msgstr "" + +#: src/components/form/InputStock.tsx:151 +#, c-format +msgid "Delivery address" +msgstr "" + +#: src/components/form/InputStock.tsx:153 +#: src/paths/admin/create/CreatePage.tsx:99 +#: src/paths/admin/create/CreatePage.tsx:116 +#: src/paths/instance/orders/create/CreatePage.tsx:308 +#: src/paths/instance/update/UpdatePage.tsx:118 +#: src/paths/instance/update/UpdatePage.tsx:135 +#, c-format +msgid "Country" +msgstr "" + +#: src/components/form/InputStock.tsx:156 +#: src/paths/admin/create/CreatePage.tsx:98 +#: src/paths/admin/create/CreatePage.tsx:101 +#: src/paths/admin/create/CreatePage.tsx:118 +#: src/paths/instance/orders/create/CreatePage.tsx:310 +#: src/paths/instance/update/UpdatePage.tsx:117 +#: src/paths/instance/update/UpdatePage.tsx:120 +#: src/paths/instance/update/UpdatePage.tsx:137 +#, c-format +msgid "Address" +msgstr "" + +#: src/components/form/InputStock.tsx:161 +#: src/paths/admin/create/CreatePage.tsx:105 +#: src/paths/admin/create/CreatePage.tsx:122 +#: src/paths/instance/orders/create/CreatePage.tsx:314 +#: src/paths/instance/update/UpdatePage.tsx:124 +#: src/paths/instance/update/UpdatePage.tsx:141 +#, c-format +msgid "Building number" +msgstr "" + +#: src/components/form/InputStock.tsx:162 +#: src/paths/admin/create/CreatePage.tsx:106 +#: src/paths/admin/create/CreatePage.tsx:123 +#: src/paths/instance/orders/create/CreatePage.tsx:315 +#: src/paths/instance/update/UpdatePage.tsx:125 +#: src/paths/instance/update/UpdatePage.tsx:142 +#, c-format +msgid "Building name" +msgstr "" + +#: src/components/form/InputStock.tsx:163 +#: src/paths/admin/create/CreatePage.tsx:107 +#: src/paths/admin/create/CreatePage.tsx:124 +#: src/paths/instance/orders/create/CreatePage.tsx:316 +#: src/paths/instance/update/UpdatePage.tsx:126 +#: src/paths/instance/update/UpdatePage.tsx:143 +#, c-format +msgid "Street" +msgstr "" + +#: src/components/form/InputStock.tsx:164 +#: src/paths/admin/create/CreatePage.tsx:108 +#: src/paths/admin/create/CreatePage.tsx:125 +#: src/paths/instance/orders/create/CreatePage.tsx:317 +#: src/paths/instance/update/UpdatePage.tsx:127 +#: src/paths/instance/update/UpdatePage.tsx:144 +#, c-format +msgid "Post code" +msgstr "" + +#: src/components/form/InputStock.tsx:165 +#: src/paths/admin/create/CreatePage.tsx:109 +#: src/paths/admin/create/CreatePage.tsx:126 +#: src/paths/instance/orders/create/CreatePage.tsx:318 +#: src/paths/instance/update/UpdatePage.tsx:128 +#: src/paths/instance/update/UpdatePage.tsx:145 +#, c-format +msgid "Town location" +msgstr "" + +#: src/components/form/InputStock.tsx:166 +#: src/paths/admin/create/CreatePage.tsx:110 +#: src/paths/admin/create/CreatePage.tsx:127 +#: src/paths/instance/orders/create/CreatePage.tsx:319 +#: src/paths/instance/update/UpdatePage.tsx:129 +#: src/paths/instance/update/UpdatePage.tsx:146 +#, c-format +msgid "Town" +msgstr "" + +#: src/components/form/InputStock.tsx:167 +#: src/paths/admin/create/CreatePage.tsx:111 +#: src/paths/admin/create/CreatePage.tsx:128 +#: src/paths/instance/orders/create/CreatePage.tsx:320 +#: src/paths/instance/update/UpdatePage.tsx:130 +#: src/paths/instance/update/UpdatePage.tsx:147 +#, c-format +msgid "District" +msgstr "" + +#: src/components/form/InputStock.tsx:168 +#: src/paths/admin/create/CreatePage.tsx:112 +#: src/paths/admin/create/CreatePage.tsx:129 +#: src/paths/instance/orders/create/CreatePage.tsx:321 +#: src/paths/instance/update/UpdatePage.tsx:131 +#: src/paths/instance/update/UpdatePage.tsx:148 +#, c-format +msgid "Country subdivision" +msgstr "" + +#: src/components/form/InputTaxes.tsx:73 +#, c-format +msgid "this product has no taxes" +msgstr "" + +#: src/components/form/InputTaxes.tsx:77 +#: src/paths/instance/orders/details/DetailPage.tsx:145 +#: src/paths/instance/orders/details/DetailPage.tsx:296 +#: src/paths/instance/orders/list/Table.tsx:116 +#, c-format +msgid "Amount" +msgstr "" + +#: src/components/form/InputTaxes.tsx:78 +#, c-format +msgid "currency and value separated with colon" +msgstr "" + +#: src/components/form/InputTaxes.tsx:84 +#: src/paths/instance/orders/create/InventoryProductForm.tsx:78 +#, c-format +msgid "Add" +msgstr "" + +#: src/components/menu/SideBar.tsx:53 +#, c-format +msgid "Instance" +msgstr "" + +#: src/components/menu/SideBar.tsx:59 +#, c-format +msgid "Settings" +msgstr "" + +#: src/components/menu/SideBar.tsx:65 +#: src/paths/instance/orders/list/Table.tsx:60 +#, c-format +msgid "Orders" +msgstr "" + +#: src/components/menu/SideBar.tsx:71 +#: src/paths/instance/orders/create/CreatePage.tsx:257 +#: src/paths/instance/products/list/Table.tsx:48 +#, c-format +msgid "Products" +msgstr "" + +#: src/components/menu/SideBar.tsx:77 +#: src/paths/instance/transfers/list/Table.tsx:59 +#, c-format +msgid "Transfers" +msgstr "" + +#: src/components/menu/SideBar.tsx:87 +#, c-format +msgid "Connection" +msgstr "" + +#: src/components/menu/SideBar.tsx:112 src/paths/admin/list/Table.tsx:57 +#, c-format +msgid "Instances" +msgstr "" + +#: src/components/menu/SideBar.tsx:116 +#, c-format +msgid "New" +msgstr "" + +#: src/components/menu/SideBar.tsx:122 +#, c-format +msgid "List" +msgstr "" + +#: src/components/menu/SideBar.tsx:129 +#, c-format +msgid "Log out" +msgstr "" + +#: src/components/modal/index.tsx:74 +#, c-format +msgid "Clear" +msgstr "" + +#: src/components/modal/index.tsx:110 src/components/modal/index.tsx:111 +#, c-format +msgid "should be the same" +msgstr "" + +#: src/components/modal/index.tsx:111 +#, c-format +msgid "cannot be the same as before" +msgstr "" + +#: src/components/modal/index.tsx:114 +#, c-format +msgid "" +"You are updating the authorization token from instance %1$s with id %2$s" +msgstr "" + +#: src/components/modal/index.tsx:124 +#, c-format +msgid "Old token" +msgstr "" + +#: src/components/modal/index.tsx:125 +#, c-format +msgid "New token" +msgstr "" + +#: src/components/modal/index.tsx:127 +#, c-format +msgid "Clearing the auth token will mean public access to the instance" +msgstr "" + +#: src/components/product/ProductForm.tsx:96 +#: src/paths/admin/create/CreatePage.tsx:84 src/paths/admin/list/Table.tsx:109 +#: src/paths/instance/transfers/list/Table.tsx:111 +#, c-format +msgid "ID" +msgstr "" + +#: src/components/product/ProductForm.tsx:98 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:121 +#: src/paths/instance/products/list/Table.tsx:85 +#, c-format +msgid "Image" +msgstr "" + +#: src/components/product/ProductForm.tsx:100 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:123 +#, c-format +msgid "Unit" +msgstr "" + +#: src/components/product/ProductForm.tsx:101 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:124 +#: src/paths/instance/products/list/Table.tsx:162 +#: src/paths/instance/products/list/Table.tsx:214 +#, c-format +msgid "Price" +msgstr "" + +#: src/components/product/ProductForm.tsx:103 +#: src/paths/instance/products/list/Table.tsx:90 +#, c-format +msgid "Stock" +msgstr "" + +#: src/components/product/ProductForm.tsx:105 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:128 +#: src/paths/instance/products/list/Table.tsx:88 +#, c-format +msgid "Taxes" +msgstr "" + +#: src/index.tsx:75 +#, c-format +msgid "Server not found" +msgstr "" + +#: src/index.tsx:85 +#, c-format +msgid "Couldn't access the server" +msgstr "" + +#: src/index.tsx:87 src/index.tsx:99 +#, c-format +msgid "Got message %1$s from %2$s" +msgstr "" + +#: src/index.tsx:97 +#, c-format +msgid "Unexpected Error" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:88 +#: src/paths/instance/update/UpdatePage.tsx:107 +#, c-format +msgid "Auth token" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:90 +#: src/paths/instance/details/DetailPage.tsx:77 +#: src/paths/instance/update/UpdatePage.tsx:109 +#, c-format +msgid "Account address" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:92 +#: src/paths/instance/update/UpdatePage.tsx:111 +#, c-format +msgid "Default max deposit fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:94 +#: src/paths/instance/update/UpdatePage.tsx:113 +#, c-format +msgid "Default max wire fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:96 +#: src/paths/instance/update/UpdatePage.tsx:115 +#, c-format +msgid "Default wire fee amortization" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:115 +#: src/paths/instance/update/UpdatePage.tsx:134 +#, c-format +msgid "Jurisdiction" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:132 +#: src/paths/instance/update/UpdatePage.tsx:151 +#, c-format +msgid "Default pay delay" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:134 +#: src/paths/instance/update/UpdatePage.tsx:153 +#, c-format +msgid "Default wire transfer delay" +msgstr "" + +#: src/paths/admin/create/index.tsx:58 +#, c-format +msgid "could not create instance" +msgstr "" + +#: src/paths/admin/list/Table.tsx:63 src/paths/admin/list/Table.tsx:131 +#, c-format +msgid "Delete" +msgstr "" + +#: src/paths/admin/list/Table.tsx:128 +#, c-format +msgid "Edit" +msgstr "" + +#: src/paths/admin/list/Table.tsx:149 +#: src/paths/instance/products/list/Table.tsx:245 +#, c-format +msgid "There is no instances yet, add more pressing the + sign" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:236 +#, c-format +msgid "Inventory products" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:285 +#, c-format +msgid "Total price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:286 +#, c-format +msgid "Total tax" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:288 +#: src/paths/instance/orders/create/CreatePage.tsx:296 +#, c-format +msgid "Order price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:294 +#, c-format +msgid "Net" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:299 +#: src/paths/instance/orders/details/DetailPage.tsx:144 +#: src/paths/instance/orders/details/DetailPage.tsx:295 +#: src/paths/instance/orders/list/Table.tsx:117 +#, c-format +msgid "Summary" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:301 +#, c-format +msgid "Payments options" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:302 +#, c-format +msgid "Auto refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:303 +#, c-format +msgid "Refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:304 +#, c-format +msgid "Pay deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:306 +#, c-format +msgid "Delivery date" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:307 +#, c-format +msgid "Location" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:324 +#, c-format +msgid "Max fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:325 +#, c-format +msgid "Max wire fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:326 +#, c-format +msgid "Wire fee amortization" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:327 +#, c-format +msgid "Fullfilment url" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:330 +#, c-format +msgid "Extra information" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:44 +#, c-format +msgid "select a product first" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:51 +#, c-format +msgid "should be greater than 0" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:58 +#, c-format +msgid "" +"cannot be greater than current stock and quantity previously added. max: %1$s" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:64 +#, c-format +msgid "cannot be greater than current stock %1$s" +msgstr "" + +#: src/paths/instance/orders/create/InventoryProductForm.tsx:76 +#: src/paths/instance/orders/create/NonInventoryProductForm.tsx:126 +#, c-format +msgid "Quantity" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:92 +#: src/paths/instance/orders/details/DetailPage.tsx:235 +#: src/paths/instance/orders/details/DetailPage.tsx:333 +#, c-format +msgid "Order" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:93 +#, c-format +msgid "claimed" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:110 +#: src/paths/instance/orders/details/DetailPage.tsx:261 +#: src/paths/instance/orders/list/Table.tsx:136 +#, c-format +msgid "copy url" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:126 +#: src/paths/instance/orders/details/DetailPage.tsx:349 +#, c-format +msgid "pay at" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:127 +#: src/paths/instance/orders/details/DetailPage.tsx:350 +#, c-format +msgid "created at" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:138 +#: src/paths/instance/orders/details/DetailPage.tsx:289 +#, c-format +msgid "Timeline" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:142 +#: src/paths/instance/orders/details/DetailPage.tsx:293 +#, c-format +msgid "Payment details" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:146 +#: src/paths/instance/orders/details/DetailPage.tsx:299 +#: src/paths/instance/orders/details/DetailPage.tsx:363 +#, c-format +msgid "Order status" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:156 +#: src/paths/instance/orders/details/DetailPage.tsx:308 +#, c-format +msgid "Product list" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:236 +#, c-format +msgid "paid" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:238 +#, c-format +msgid "wired" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:241 +#, c-format +msgid "refunded" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:258 +#, c-format +msgid "refund" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:297 +#, c-format +msgid "Refunded amount" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:298 +#, c-format +msgid "Deposit total" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:336 +#, c-format +msgid "unpaid" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:364 +#, c-format +msgid "Order status URL" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:365 +#, c-format +msgid "Pay URI" +msgstr "" + +#: src/paths/instance/orders/details/DetailPage.tsx:383 +#, c-format +msgid "" +"Unknown order status. This is an error, please contact the administrator." +msgstr "" + +#: src/paths/instance/orders/details/index.tsx:56 +#: src/paths/instance/orders/list/index.tsx:147 +#, c-format +msgid "refund created successfully" +msgstr "" + +#: src/paths/instance/orders/details/index.tsx:59 +#: src/paths/instance/orders/list/index.tsx:150 +#, c-format +msgid "could not create the refund" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:111 +#, c-format +msgid "load newer orders" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:115 +#, c-format +msgid "Date" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:131 +#: src/paths/instance/orders/list/Table.tsx:223 +#, c-format +msgid "Refund" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:145 +#, c-format +msgid "load older orders" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:154 +#, c-format +msgid "No orders has been found" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:202 +#, c-format +msgid "date" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:203 +#, c-format +msgid "amount" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:204 +#, c-format +msgid "reason" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:224 +#, c-format +msgid "Max refundable:" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "Reason" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "duplicated" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "requested by the customer" +msgstr "" + +#: src/paths/instance/orders/list/Table.tsx:226 +#, c-format +msgid "other" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:91 +#, c-format +msgid "go to order id" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:107 +#, c-format +msgid "Paid" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:108 +#, c-format +msgid "Refunded" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:109 +#, c-format +msgid "Not wired" +msgstr "" + +#: src/paths/instance/orders/list/index.tsx:110 +#, c-format +msgid "All" +msgstr "" + +#: src/paths/instance/products/create/index.tsx:48 +#: src/paths/instance/products/update/index.tsx:64 +#, c-format +msgid "could not create product" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:87 +#, c-format +msgid "Sell" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:89 +#, c-format +msgid "Profit" +msgstr "" + +#: src/paths/instance/products/list/Table.tsx:91 +#, c-format +msgid "Sold" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:59 +#, c-format +msgid "product updated successfully" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:62 +#, c-format +msgid "could not update the product" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:70 +#, c-format +msgid "product delete successfully" +msgstr "" + +#: src/paths/instance/products/list/index.tsx:73 +#, c-format +msgid "could not delete the product" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:59 +#, c-format +msgid "Tips" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:111 +#, c-format +msgid "Committed amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:112 +#, c-format +msgid "Exchange initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:113 +#, c-format +msgid "Merchant initial amount" +msgstr "" + +#: src/paths/instance/tips/list/Table.tsx:148 +#, c-format +msgid "There is no tips yet, add more pressing the + sign" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:147 +#, c-format +msgid "There is no transfer yet, add more pressing the + sign" +msgstr "" diff --git a/packages/frontend/src/index.tsx b/packages/frontend/src/index.tsx @@ -20,31 +20,25 @@ */ import { h, VNode } from 'preact'; -import { MessageProvider, useMessageTemplate } from 'preact-messages'; import { route } from 'preact-router'; import { useMemo } from "preact/hooks"; import { ApplicationReadyRoutes } from "./ApplicationReadyRoutes"; import { Loading } from "./components/exception/loading"; import { NotificationCard, NotYetReadyAppMenu } from "./components/menu"; -import { BackendContextProvider, ConfigContextProvider, useBackendContext } from './context/backend'; -import { useBackendContextState } from './hooks'; +import { BackendContextProvider, useBackendContext } from './context/backend'; +import { ConfigContextProvider } from './context/config'; +import { TranslationProvider } from './context/translation'; import { useBackendConfig } from "./hooks/backend"; -import * as messages from './messages'; +import { useTranslator } from './i18n'; import LoginPage from './paths/login'; import "./scss/main.scss"; -import { hasKey, onTranslationError } from "./utils/functions"; - - - export default function Application(): VNode { - const state = useBackendContextState() - return ( - <BackendContextProvider value={state}> - <MessageProvider locale={state.lang} onError={onTranslationError} messages={hasKey(messages, state.lang) ? messages[state.lang] : messages.en} pathSep={null as any} > + <BackendContextProvider> + <TranslationProvider> <ApplicationStatusRoutes /> - </MessageProvider > + </TranslationProvider> </BackendContextProvider> ); } @@ -52,7 +46,7 @@ export default function Application(): VNode { function ApplicationStatusRoutes(): VNode { const { changeBackend, triedToLog, updateToken } = useBackendContext() const result = useBackendConfig(); - const i18n = useMessageTemplate() + const i18n = useTranslator() const updateLoginInfoAndGoToRoot = (url: string, token?: string) => { changeBackend(url) diff --git a/packages/frontend/src/messages/en.po b/packages/frontend/src/messages/en.po @@ -1,627 +0,0 @@ -# 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/> - -# Examples from http://pology.nedohodnik.net/doc/user/en_US/ch-poformat.html -msgid "" -msgstr "" -"Content-Type: text/plain; charset=UTF-8\n" -"Language: en\n" -"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" - -msgid "Time: %1 second" -msgid_plural "Time: %1 seconds" -msgstr[0] "Czas: %1 sekunda" -msgstr[1] "Czas: %1 sekundy" -msgstr[2] "Czas: %1 sekund" - -msgid "Hi" -msgstr "Hello" - -msgid "List of configured instances" -msgstr "List of configured instances" - -msgid "There is no instances yet, add more pressing the + sign" -msgstr "There is no instances yet, add more pressing the + sign" - -msgid "Invalid payment address" -msgstr "Invalid payment address" - -msgid "Problem reaching the server" -msgstr "Problem reaching the server" - -msgid "The value %s is invalid for a payment url" -msgstr "The value \"%s\" is invalid for a payment url" - -# msgctxt "fields.instance.name" -# msgid "placeholder" -# msgstr "" - -# |msgctxt "fields" -# |msgctxt "instance" -# msgctxt "fields.instance.id.label" - -msgid "fields.instance.id.label" -msgstr "Id" - -msgid "fields.instance.name.label" -msgstr "Name" - -msgid "fields.instance.merchant.pub.label" -msgstr "Public key" - -msgid "fields.instance.payment.targets.label" -msgstr "Payment targets" - -msgid "fields.instance.auth_token.label" -msgstr "Auth token" - -msgid "fields.instance.auth_token.tooltip" -msgstr "Use this token to secure an instance with a password" - -msgid "fields.instance.payto_uris.label" -msgstr "Account address" - -msgid "fields.instance.payto_uris.help" -msgstr "x-taler-bank/bank.taler:5882/blogger" - -msgid "fields.instance.default_max_deposit_fee.label" -msgstr "Max deposit fee label" - -msgid "fields.instance.default_max_wire_fee.label" -msgstr "Max wire fee label" - -msgid "fields.instance.default_wire_fee_amortization.label" -msgstr "Wire fee Amortization" - -msgid "fields.instance.address.label" -msgstr "Address" - -msgid "Could not infer instance id from url %s" -msgstr "Could not infer instance id from url %s" - -msgid "fields.instance.address.country.label" -msgstr "Country" - -msgid "fields.instance.address.country_subdivision.label" -msgstr "Country Subdivision" - -msgid "fields.instance.address.district.label" -msgstr "District" - -msgid "fields.instance.address.town.label" -msgstr "Town" - -msgid "fields.instance.address.town_location.label" -msgstr "Town Location" - -msgid "fields.instance.address.post_code.label" -msgstr "Post code" - -msgid "fields.instance.address.street.label" -msgstr "Street" - -msgid "fields.instance.address.building_name.label" -msgstr "Building Name" - -msgid "fields.instance.address.building_number.label" -msgstr "Building Number" - -msgid "fields.instance.address.address_lines.label" -msgstr "Address" - -msgid "fields.instance.jurisdiction.label" -msgstr "Jurisdiction" - -msgid "fields.instance.jurisdiction.country.label" -msgstr "Country" - -msgid "fields.instance.jurisdiction.country_subdivision.label" -msgstr "Country Subdivision" - -msgid "fields.instance.jurisdiction.district.label" -msgstr "District" - -msgid "fields.instance.jurisdiction.town.label" -msgstr "Town" - -msgid "fields.instance.jurisdiction.town_location.label" -msgstr "Town Location" - -msgid "fields.instance.jurisdiction.post_code.label" -msgstr "Post code" - -msgid "fields.instance.jurisdiction.street.label" -msgstr "Street" - -msgid "fields.instance.jurisdiction.building_name.label" -msgstr "Building Name" - -msgid "fields.instance.jurisdiction.building_number.label" -msgstr "Building Number" - -msgid "fields.instance.jurisdiction.address_lines.label" -msgstr "Address" - -msgid "fields.instance.default_pay_delay.label" -msgstr "Pay delay" - -msgid "fields.instance.default_wire_transfer_delay.label" -msgstr "Wire transfer delay" - -msgid "Couldn't access the server" -msgstr "Couldn't access the server" - -msgid "Unexpected Error" -msgstr "Unexpected Error" - -msgid "Got message %s from %s" -msgstr "Got message \"%s\" from %s" - -msgid "Merchant" -msgstr "Merchant" - -msgid "Instances" -msgstr "Instances" - -msgid "Update this instance" -msgstr "Update this instance" - -msgid "Cancel" -msgstr "Cancel" - -msgid "Clear" -msgstr "Clear" - -msgid "Confirm" -msgstr "Confirm" - -msgid "en" -msgstr "English [en]" - -msgid "es" -msgstr "Español [es]" - - -msgid "fields.instance.old_token.label" -msgstr "Old token" - -msgid "fields.instance.new_token.label" -msgstr "New token" - -msgid "validations." -msgstr "New token" - -msgid "fields.instance.id.label" -msgstr "Id" - -msgid "fields.instance.name.label" -msgstr "Business Name" - -msgid "fields.instance.merchant_pub.label" -msgstr "Public Key" - -msgid "fields.instance.payment_targets.label" -msgstr "Payment targets" - -msgid "Access denied" -msgstr "Access denied" - -msgid "Check your token is valid" -msgstr "Check your token is valid" - -msgid "delete" -msgstr "Delete" - -msgid "update" -msgstr "Update" - -msgid "Instance details" -msgstr "Instance details" - -msgid "Login required" -msgstr "Login required" - -msgid "Please enter your auth token. Token should have \"secret-token:\" and start with Bearer or ApiKey" -msgstr "Please enter your auth token. Token should have \"secret-token:\" and start with Bearer or ApiKey" - -msgid "Orders" -msgstr "Orders" - -msgid "fields.order.amount.label" -msgstr "Amount" - -msgid "fields.order.summary.label" -msgstr "Summary" - -msgid "fields.order.date.label" -msgstr "Date" - -msgid "Products" -msgstr "Products" - -msgid "fields.product.id.label" -msgstr "Id" - -msgid "Transfers" -msgstr "Transfers" - -msgid "Tips" -msgstr "Tips" - -msgid "fields.tips.committed_amount.label" -msgstr "Commited Amount" - -msgid "fields.tips.exchange_initial_amount.label" -msgstr "Exchange Initial Amount" - -msgid "fields.tips.merchant_initial_amount.label" -msgstr "Merchant Initial Amount" - -msgid "fields.instance.paid.tooltip" -msgstr "three state boolean" - -msgid "fields.instance.paid.label" -msgstr "Paid" - -# msgid "fields.instance.refunded.tooltip" -# msgstr "" - -msgid "fields.instance.refunded.label" -msgstr "Refunded" - -# msgid "fields.instance.wired.tooltip" -# msgstr "" - -msgid "fields.instance.wired.label" -msgstr "Wired" - -msgid "create_success" -msgstr "Creation succeed" - -msgid "create_error" -msgstr "Creation failed" - -msgid "delete_instance" -msgstr "Delete instance" - -# msgid "fields.instance.refund.placeholder" -# msgstr "" - -# msgid "fields.instance.refund.tooltip" -# msgstr "" - -msgid "fields.instance.refund.label" -msgstr "Amount" - -msgid "fields.instance.mainReason.placeholder" -msgstr "select an option" - -# msgid "fields.instance.reason.tooltip" -# msgstr "" - -msgid "fields.instance.mainReason.label" -msgstr "Reason" - -msgid "fields.instance.description.label" -msgstr "Description" - -msgid "fields.instance.description.placeholder" -msgstr "add more information about the refund" - -msgid "fields.instance.order_status.label" -msgstr "Order status" - -msgid "fields.instance.order_status_url.label" -msgstr "Order status URL" - -msgid "fields.instance.taler_pay_uri.label" -msgstr "Taler Pay URI" - - -msgid "fields.instance.amount.label" -msgstr "Amount" - -msgid "fields.instance.summary.label" -msgstr "Summary" - - -msgid "fields.instance.contract_terms.amount.label" -msgstr "Amount" - -msgid "fields.instance.contract_terms.summary.label" -msgstr "Summary" - -msgid "fields.instance.refund_amount.label" -msgstr "Refunded" - -msgid "fields.instance.deposit_total.label" -msgstr "Deposit Total" - -msgid "fields.instance.contract_terms.max_fee.label" -msgstr "Max Fee" - -msgid "fields.instance.contract_terms.max_wire_fee.label" -msgstr "Max Wire Fee" - - -msgid "fields.instance.fee.label" -msgstr "Fee" - -msgid "fields.product.image.label" -msgstr "Image" - -msgid "fields.product.description.label" -msgstr "Description" - -msgid "fields.product.sell.label" -msgstr "Sell" - -msgid "fields.product.taxes.label" -msgstr "Taxes" - -msgid "fields.product.profit.label" -msgstr "Profit" - -msgid "fields.product.stock.label" -msgstr "Stock" - -msgid "fields.product.quantity.label" -msgstr "Quantity" - -msgid "fields.product.sold.label" -msgstr "Sold" - -msgid "fields.instance.inventory_products.label" -msgstr "Products from inventory" - -msgid "fields.instance.products.label" -msgstr "Products outside inventory" - -msgid "fields.instance.quantity.label" -msgstr "Quantity" - - -msgid "fields.instance.pricing.order_price.label" -msgstr "Order Price" - -msgid "fields.instance.pricing.summary.label" -msgstr "Summary" - -msgid "fields.instance.pricing.products_price.label" -msgstr "Products Price" - -msgid "fields.instance.pricing.products_taxes.label" -msgstr "Products Taxes" - -msgid "fields.instance.pricing.net.label" -msgstr "Net" - - -msgid "fields.instance.payments.label" -msgstr "Payments" - - - -msgid "fields.instance.payments.auto_refund_deadline.label" -msgstr "Auto Refund Deadline" - - - -msgid "fields.instance.payments.refund_deadline.label" -msgstr "Refund Deadline" - - - -msgid "fields.instance.payments.pay_deadline.label" -msgstr "Pay Deadline" - - - -msgid "fields.instance.payments.delivery_date.label" -msgstr "Delivery Date" - -msgid "fields.instance.payments.delivery_location.label" -msgstr "Delivery Location" - - - -msgid "fields.instance.payments.max_fee.label" -msgstr "Max Fee" - - - -msgid "fields.instance.payments.max_wire_fee.label" -msgstr "Max Wire Fee" - - - -msgid "fields.instance.payments.wire_fee_amortization.label" -msgstr "Wire Fee Amortization" - - - -msgid "fields.instance.payments.fullfilment_url.label" -msgstr "Fillfilment URL" - - - -msgid "fields.instance.payments.delivery_location.country.label" -msgstr "Country" - - - -msgid "fields.instance.payments.delivery_location.address_lines.label" -msgstr "Adress Lines" - - - -msgid "fields.instance.payments.delivery_location.building_number.label" -msgstr "Building Number" - - - -msgid "fields.instance.payments.delivery_location.building_name.label" -msgstr "Building Name" - - - -msgid "fields.instance.payments.delivery_location.street.label" -msgstr "Stree" - - - -msgid "fields.instance.payments.delivery_location.post_code.label" -msgstr "Post Code" - - - -msgid "fields.instance.payments.delivery_location.town_location.label" -msgstr "Town Location" - -msgid "fields.instance.payments.delivery_location.town.label" -msgstr "Town" - -msgid "fields.instance.payments.delivery_location.district.label" -msgstr "District" - -msgid "fields.instance.payments.delivery_location.country_subdivision.label" -msgstr "Country Subdivision" - -msgid "fields.instance.extra.label" -msgstr "Extra information" - -msgid "fields.instance.extra.tooltip" -msgstr "Must be a JSON formatted string" - - -msgid "fields.instance.product_id.label" -msgstr "ID" - - -msgid "fields.instance.image.label" -msgstr "Image" - - -msgid "fields.instance.unit.label" -msgstr "Unit" - - - -msgid "fields.instance.total_stock.label" -msgstr "Total Stock" - - -msgid "fields.product.description.label" -msgstr "Description" - -msgid "fields.product.unit.label" -msgstr "Unit" - -msgid "fields.product.total_stock.label" -msgstr "Total Stock" - -msgid "fields.product.product_id.label" -msgstr "ID" - -msgid "fields.product.price.label" -msgstr "Price" - -msgid "fields.tax.name.label" -msgstr "Name" - -msgid "fields.tax.tax.label" -msgstr "Amount" - -msgid "fields.groups.address.label" -msgstr "Storage address" - -msgid "fields.stock.current.label" -msgstr "Current stock" - -msgid "fields.stock.lost.label" -msgstr "Lost stock" - -msgid "fields.stock.nextRestock.label" -msgstr "Next Restock" - - -msgid "fields.stock.address.country.label" -msgstr "Country" - -msgid "fields.stock.address.country_subdivision.label" -msgstr "Country Subdivision" - -msgid "fields.stock.address.district.label" -msgstr "District" - -msgid "fields.stock.address.town.label" -msgstr "Town" - -msgid "fields.stock.address.town_location.label" -msgstr "Town Location" - -msgid "fields.stock.address.post_code.label" -msgstr "Post code" - -msgid "fields.stock.address.street.label" -msgstr "Street" - -msgid "fields.stock.address.building_name.label" -msgstr "Building Name" - -msgid "fields.stock.address.building_number.label" -msgstr "Building Number" - -msgid "fields.stock.address.address_lines.label" -msgstr "Address" - -msgid "fields.groups.jurisdiction.label" -msgstr "Jurisdiction" - -msgid "fields.groups.inventory_products.label" -msgstr "Inventory Products" - -msgid "fields.groups.products.label" -msgstr "Products" - -msgid "fields.groups.payments.label" -msgstr "Payments" - -msgid "fields.groups.extra.label" -msgstr "Extra" - - -msgid "fields.instance.stock.label" -msgstr "Stock" - -msgid "fields.instance.lost.label" -msgstr "Lost" - -msgid "fields.instance.price.label" -msgstr "Price" - -msgid "fields.groups.tax.label" -msgstr "Taxes" - -msgid "validation.imageSizeLimit" -msgstr "Image max size is 1 MB" - -msgid "fields.added.incoming.label" -msgstr "Incoming" - -msgid "fields.added.lost.label" -msgstr "Notify Lost" - -msgid "fields.added.price.label" -msgstr "New Price" diff --git a/packages/frontend/src/messages/es.po b/packages/frontend/src/messages/es.po @@ -1,202 +0,0 @@ -# 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/> - -# Examples from http://pology.nedohodnik.net/doc/user/en_US/ch-poformat.html -msgid "" -msgstr "" -"Content-Type: text/plain; charset=UTF-8\n" -"Language: es\n" -"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" - -msgid "Hi" -msgstr "Hola" - -msgid "List of configured instances" -msgstr "Lista de instancias configuradas" - -msgid "There is no instances yet, add more pressing the + sign" -msgstr "LodavÃa no hay instancias, puedes agregar mas presionando el signo +" - -msgid "Invalid payment address" -msgstr "Dirección de pago invalido" - -msgid "Problem reaching the server" -msgstr "Hubo problemas intentando llegar al servidor" - -msgid "The value %s is invalid for a payment url" -msgstr "El valor \"%s\" es una dirección de pago invalido" - -# msgctxt "fields.instance.name" -# msgid "placeholder" -# msgstr "" - -# |msgctxt "fields" -# |msgctxt "instance" -# msgctxt "fields.instance.id.label" - -msgid "fields.instance.id.label" -msgstr "Id" - -msgid "fields.instance.name.label" -msgstr "Nombre" - -msgid "fields.instance.merchant_pub.label" -msgstr "Clave publica" - -msgid "fields.instance.payment_targets.label" -msgstr "Dirección de pago" - -msgid "fields.instance.auth_token.label" -msgstr "Token de autorización" - -msgid "fields.instance.auth_token.tooltip" -msgstr "Use this token to secure an instance with a password" - -msgid "fields.instance.payto_uris.label" -msgstr "Dirección de cuenta" - -msgid "fields.instance.payto_uris.help" -msgstr "x-taler-bank/bank.taler:5882/blogger" - -msgid "fields.instance.default_max_deposit_fee.label" -msgstr "Máximo cobro por deposito" - -msgid "fields.instance.default_max_wire_fee.label" -msgstr "Máximo cobro por transferencia bancaria" - -msgid "fields.instance.default_wire_fee_amortization.label" -msgstr "Cobro por transferencia" - -msgid "fields.instance.address.label" -msgstr "Dirección" - -msgid "fields.instance.address.country.label" -msgstr "PaÃs" - -msgid "fields.instance.address.country_subdivision.label" -msgstr "PaÃs suvdivisión" - -msgid "fields.instance.address.district.label" -msgstr "Distrito" - -msgid "fields.instance.address.town.label" -msgstr "Ciudad" - -msgid "fields.instance.address.town_location.label" -msgstr "Ubicación" - -msgid "fields.instance.address.post_code.label" -msgstr "Código postal" - -msgid "fields.instance.address.street.label" -msgstr "Calle" - -msgid "fields.instance.address.building_name.label" -msgstr "Nombre de edificio" - -msgid "fields.instance.address.building_number.label" -msgstr "Numero de edificio" - -msgid "fields.instance.address.address_lines.label" -msgstr "Linea de dirección" - -msgid "fields.instance.jurisdiction.label" -msgstr "Juridiscción" - -msgid "fields.instance.jurisdiction.country.label" -msgstr "PaÃs" - -msgid "fields.instance.jurisdiction.country_subdivision.label" -msgstr "Country Subdivision" - -msgid "fields.instance.jurisdiction.district.label" -msgstr "District" - -msgid "fields.instance.jurisdiction.town.label" -msgstr "Town" - -msgid "fields.instance.jurisdiction.town_location.label" -msgstr "Town Location" - -msgid "fields.instance.jurisdiction.post_code.label" -msgstr "Post code" - -msgid "fields.instance.jurisdiction.street.label" -msgstr "Street" - -msgid "fields.instance.jurisdiction.building_name.label" -msgstr "Building Name" - -msgid "fields.instance.jurisdiction.building_number.label" -msgstr "Building Number" - -msgid "fields.instance.jurisdiction.address_lines.label" -msgstr "Adress Line" - -msgid "fields.instance.default_pay_delay.label" -msgstr "Demora de pago" - -msgid "fields.instance.default_wire_transfer_delay.label" -msgstr "Demora de transferencia" - -msgid "Couldnt access the server" -msgstr "Sin acceso a servidor" - -msgid "Got message: %s from: %s (hasToken: %s)" -msgstr "Se recibió el mensaje \"%s\" desde %s" - -msgid "Merchant" -msgstr "Mercader" - -msgid "Instances" -msgstr "Instancias" - -msgid "Update this instance" -msgstr "Actualizar esta instancia" - -msgid "Cancel" -msgstr "Cancelar" - -msgid "Clear" -msgstr "Limpiar" - -msgid "Confirm" -msgstr "Confirmar" - -msgid "fields.instance.old_token.label" -msgstr "Token previo" - -msgid "fields.instance.new_token.label" -msgstr "Token nuevo" - - -msgid "Access denied" -msgstr "Acceso denegado" - -msgid "Check your token is valid" -msgstr "Verifica que el token sea válido" - -msgid "delete" -msgstr "Borrar" - -msgid "update" -msgstr "Actualizar" - -msgid "Login required" -msgstr "Login requerido" - -msgid "Please enter your auth token. Token should have \"secret-token:\" and start with Bearer or ApiKey" -msgstr "Por favor, ingrese su token de autorización. El token debe contender \"secret-token:\" y comenzar con Bearer o ApiKey" - - diff --git a/packages/frontend/src/messages/index.ts b/packages/frontend/src/messages/index.ts @@ -1,18 +0,0 @@ -/* - 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/> - */ -export * as en from './en.po' -export * as es from './es.po' - diff --git a/packages/frontend/src/paths/admin/create/CreatePage.tsx b/packages/frontend/src/paths/admin/create/CreatePage.tsx @@ -20,7 +20,6 @@ */ import { h, VNode } from "preact"; -import { Message } from "preact-messages"; import { useState } from "preact/hooks"; import * as yup from 'yup'; import { FormErrors, FormProvider } from "../../../components/form/FormProvider"; @@ -33,6 +32,7 @@ import { InputSecured } from "../../../components/form/InputSecured"; import { InputWithAddon } from "../../../components/form/InputWithAddon"; import { useBackendContext } from "../../../context/backend"; import { MerchantBackend } from "../../../declaration"; +import { Translate, useTranslator } from "../../../i18n"; import { InstanceCreateSchema as schema } from '../../../schemas'; type Entity = MerchantBackend.Instances.InstanceConfigurationMessage & { auth_token?: string } @@ -46,9 +46,9 @@ interface Props { function with_defaults(id?: string): Partial<Entity> { return { id, - default_pay_delay: { d_ms: 1000*60*5 }, + default_pay_delay: { d_ms: 1000 * 60 * 5 }, default_wire_fee_amortization: 1, - default_wire_transfer_delay: { d_ms: 2000*60*5 }, + default_wire_transfer_delay: { d_ms: 2000 * 60 * 5 }, }; } @@ -67,12 +67,12 @@ export function CreatePage({ onCreate, onBack, forceId }: Props): VNode { onCreate(schema.cast(value) as Entity); } catch (err) { const errors = err.inner as yup.ValidationError[] - const pathMessages = errors.reduce((prev, cur) => !cur.path ? prev : ({ ...prev, [cur.path]: { type: cur.type, params: cur.params, message: cur.message } }), {}) + const pathMessages = errors.reduce((prev, cur) => !cur.path ? prev : ({ ...prev, [cur.path]: cur.message }), {}) setErrors(pathMessages) } } const backend = useBackendContext() - + const i18n = useTranslator() return <div> <section class="section is-main-section"> @@ -81,61 +81,63 @@ export function CreatePage({ onCreate, onBack, forceId }: Props): VNode { <div class="column is-two-thirds"> <FormProvider<Entity> errors={errors} object={value} valueHandler={valueHandler} > - <InputWithAddon<Entity> name="id" addonBefore={`${backend.url}/private/instances/`} readonly={!!forceId} /> + <InputWithAddon<Entity> name="id" label={i18n`ID`} addonBefore={`${backend.url}/private/instances/`} readonly={!!forceId} /> - <Input<Entity> name="name" /> + <Input<Entity> name="name" label={i18n`Name`} /> - <InputSecured<Entity> name="auth_token" /> + <InputSecured<Entity> name="auth_token" label={i18n`Auth token`} /> - <InputPayto<Entity> name="payto_uris" /> + <InputPayto<Entity> name="payto_uris" label={i18n`Account address`} /> - <InputCurrency<Entity> name="default_max_deposit_fee" /> + <InputCurrency<Entity> name="default_max_deposit_fee" label={i18n`Default max deposit fee`} /> - <InputCurrency<Entity> name="default_max_wire_fee" /> + <InputCurrency<Entity> name="default_max_wire_fee" label={i18n`Default max wire fee`} /> - <Input<Entity> name="default_wire_fee_amortization" /> + <Input<Entity> name="default_wire_fee_amortization" label={i18n`Default wire fee amortization`} /> - <InputGroup name="address"> - <Input name="address.country" /> + <InputGroup name="address" label={i18n`Address`}> + <Input name="address.country" label={i18n`Country`} /> <Input name="address.address_lines" inputType="multiline" + label={i18n`Address`} toStr={(v: string[] | undefined) => !v ? '' : v.join('\n')} fromStr={(v: string) => v.split('\n')} /> - <Input name="address.building_number" /> - <Input name="address.building_name" /> - <Input name="address.street" /> - <Input name="address.post_code" /> - <Input name="address.town_location" /> - <Input name="address.town" /> - <Input name="address.district" /> - <Input name="address.country_subdivision" /> + <Input name="address.building_number" label={i18n`Building number`} /> + <Input name="address.building_name" label={i18n`Building name`} /> + <Input name="address.street" label={i18n`Street`} /> + <Input name="address.post_code" label={i18n`Post code`} /> + <Input name="address.town_location" label={i18n`Town location`} /> + <Input name="address.town" label={i18n`Town`} /> + <Input name="address.district" label={i18n`District`} /> + <Input name="address.country_subdivision" label={i18n`Country subdivision`} /> </InputGroup> - <InputGroup name="jurisdiction"> - <Input name="jurisdiction.country" /> + <InputGroup name="jurisdiction" label={i18n`Jurisdiction`}> + <Input name="jurisdiction.country" label={i18n`Country`} /> <Input name="jurisdiction.address_lines" inputType="multiline" + label={i18n`Address`} toStr={(v: string[] | undefined) => !v ? '' : v.join('\n')} fromStr={(v: string) => v.split('\n')} /> - <Input name="jurisdiction.building_number" /> - <Input name="jurisdiction.building_name" /> - <Input name="jurisdiction.street" /> - <Input name="jurisdiction.post_code" /> - <Input name="jurisdiction.town_location" /> - <Input name="jurisdiction.town" /> - <Input name="jurisdiction.district" /> - <Input name="jurisdiction.country_subdivision" /> + <Input name="jurisdiction.building_number" label={i18n`Building number`} /> + <Input name="jurisdiction.building_name" label={i18n`Building name`} /> + <Input name="jurisdiction.street" label={i18n`Street`} /> + <Input name="jurisdiction.post_code" label={i18n`Post code`} /> + <Input name="jurisdiction.town_location" label={i18n`Town location`} /> + <Input name="jurisdiction.town" label={i18n`Town`} /> + <Input name="jurisdiction.district" label={i18n`District`} /> + <Input name="jurisdiction.country_subdivision" label={i18n`Country subdivision`} /> </InputGroup> - <InputDuration<Entity> name="default_pay_delay" /> + <InputDuration<Entity> name="default_pay_delay" label={i18n`Default pay delay`} /> - <InputDuration<Entity> name="default_wire_transfer_delay" /> + <InputDuration<Entity> name="default_wire_transfer_delay" label={i18n`Default wire transfer delay`} /> </FormProvider> <div class="buttons is-right mt-5"> - {onBack && <button class="button" onClick={onBack} ><Message id="Cancel" /></button>} - <button class="button is-success" onClick={submit} ><Message id="Confirm" /></button> + {onBack && <button class="button" onClick={onBack} ><Translate>Cancel</Translate></button>} + <button class="button is-success" onClick={submit} ><Translate>Confirm</Translate></button> </div> </div> diff --git a/packages/frontend/src/paths/admin/create/index.tsx b/packages/frontend/src/paths/admin/create/index.tsx @@ -22,6 +22,7 @@ import { useState } from "preact/hooks"; import { NotificationCard } from "../../../components/menu"; import { MerchantBackend } from "../../../declaration"; import { useAdminAPI } from "../../../hooks/admin"; +import { useTranslator } from "../../../i18n"; import { Notification } from "../../../utils/types"; import { CreatePage } from "./CreatePage"; import { InstanceCreatedSuccessfully } from "./InstanceCreatedSuccessfully"; @@ -37,6 +38,7 @@ export default function Create({ onBack, onConfirm, forceId }: Props): VNode { const { createInstance } = useAdminAPI(); const [notif, setNotif] = useState<Notification | undefined>(undefined) const [createdOk, setCreatedOk] = useState<Entity | undefined>(undefined); + const i18n = useTranslator() if (createdOk) { return <InstanceCreatedSuccessfully entity={createdOk} onConfirm={onConfirm} /> @@ -53,7 +55,7 @@ export default function Create({ onBack, onConfirm, forceId }: Props): VNode { setCreatedOk(d) }).catch((error) => { setNotif({ - message: 'could not create instance', + message: i18n`could not create instance`, type: "ERROR", description: error.message }) diff --git a/packages/frontend/src/paths/admin/list/Table.tsx b/packages/frontend/src/paths/admin/list/Table.tsx @@ -20,10 +20,10 @@ */ import { h, VNode } from "preact"; -import { Message } from "preact-messages"; import { StateUpdater, useEffect, useState } from "preact/hooks"; import { MerchantBackend } from "../../../declaration"; import { calculateRootPath } from "../../../hooks"; +import { Translate } from "../../../i18n"; interface Props { instances: MerchantBackend.Instances.Instance[]; @@ -54,13 +54,13 @@ export function CardTable({ instances, onCreate, onUpdate, onDelete, selected }: return <div class="card has-table"> <header class="card-header"> - <p class="card-header-title"><span class="icon"><i class="mdi mdi-desktop-mac" /></span><Message id="Instances" /></p> + <p class="card-header-title"><span class="icon"><i class="mdi mdi-desktop-mac" /></span><Translate>Instances</Translate></p> <div class="card-header-icon" aria-label="more options"> <button class={rowSelection.length > 0 ? "button is-danger" : "is-hidden"} type="button" onClick={(): void => actionQueueHandler(buildActions(instances, rowSelection, 'DELETE'))} > - Delete + <Translate>Delete</Translate> </button> </div> <div class="card-header-icon" aria-label="more options"> @@ -106,8 +106,8 @@ function Table({ rowSelection, rowSelectionHandler, instances, onUpdate, onDelet <span class="check" /> </label> </th> - <th><Message id="fields.instance.id.label" /></th> - <th><Message id="fields.instance.name.label" /></th> + <th><Translate>ID</Translate></th> + <th><Translate>Name</Translate></th> <th /> </tr> </thead> @@ -125,10 +125,10 @@ function Table({ rowSelection, rowSelectionHandler, instances, onUpdate, onDelet <td class="is-actions-cell right-sticky"> <div class="buttons is-right"> <button class="button is-small is-success jb-modal" type="button" onClick={(): void => onUpdate(i.id)}> - Edit + <Translate>Edit</Translate> </button> <button class="button is-small is-danger jb-modal" type="button" onClick={(): void => onDelete(i)}> - Delete + <Translate>Delete</Translate> </button> </div> </td> @@ -146,7 +146,7 @@ function EmptyTable(): VNode { <p> <span class="icon is-large"><i class="mdi mdi-emoticon-sad mdi-48px" /></span> </p> - <p><Message id="There is no instances yet, add more pressing the + sign" /></p> + <p><Translate>There is no instances yet, add more pressing the + sign</Translate></p> </div> } diff --git a/packages/frontend/src/paths/admin/list/View.tsx b/packages/frontend/src/paths/admin/list/View.tsx @@ -29,10 +29,9 @@ interface Props { onUpdate: (id: string) => void; onDelete: (id: MerchantBackend.Instances.Instance) => void; selected?: boolean; - isLoading: boolean; } -export function View({ instances, isLoading, onCreate, onDelete, onUpdate, selected }: Props): VNode { +export function View({ instances, onCreate, onDelete, onUpdate, selected }: Props): VNode { return <div id="app"> diff --git a/packages/frontend/src/paths/admin/list/index.tsx b/packages/frontend/src/paths/admin/list/index.tsx @@ -50,7 +50,6 @@ export default function Instances({ onUnauthorized, onLoadError, onNotFound, onC return <Fragment> <View instances={result.data.instances} - isLoading={false} onDelete={setDeleting} onCreate={onCreate} onUpdate={onUpdate} diff --git a/packages/frontend/src/paths/instance/details/DetailPage.tsx b/packages/frontend/src/paths/instance/details/DetailPage.tsx @@ -24,6 +24,7 @@ import { useState } from "preact/hooks"; import { FormProvider } from "../../../components/form/FormProvider"; import { Input } from "../../../components/form/Input"; import { MerchantBackend } from "../../../declaration"; +import { useTranslator } from "../../../i18n"; type Entity = MerchantBackend.Instances.InstanceReconfigurationMessage; interface Props { @@ -46,6 +47,8 @@ function convert(from: MerchantBackend.Instances.QueryInstancesResponse): Entity export function DetailPage({ selected }: Props): VNode { const [value, valueHandler] = useState<Partial<Entity>>(convert(selected)) + const i18n = useTranslator() + return <div> <section class="hero is-hero-bar"> <div class="hero-body"> @@ -70,8 +73,8 @@ export function DetailPage({ selected }: Props): VNode { <div class="column is-6"> <FormProvider<Entity> object={value} valueHandler={valueHandler} > - <Input<Entity> name="name" readonly /> - <Input<Entity> name="payto_uris" readonly /> + <Input<Entity> name="name" readonly label={i18n`Name`} /> + <Input<Entity> name="payto_uris" readonly label={i18n`Account address`} /> </FormProvider> </div> diff --git a/packages/frontend/src/paths/instance/details/index.tsx b/packages/frontend/src/paths/instance/details/index.tsx @@ -17,7 +17,7 @@ import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { Loading } from "../../../components/exception/loading"; import { DeleteModal } from "../../../components/modal"; -import { useInstanceContext } from "../../../context/backend"; +import { useInstanceContext } from "../../../context/instance"; import { HttpError } from "../../../hooks/backend"; import { useInstanceAPI, useInstanceDetails } from "../../../hooks/instance"; import { DetailPage } from "./DetailPage"; diff --git a/packages/frontend/src/paths/instance/orders/create/CreatePage.tsx b/packages/frontend/src/paths/instance/orders/create/CreatePage.tsx @@ -21,7 +21,6 @@ import { add } from "date-fns"; import { Fragment, h, VNode } from "preact"; -import { Message } from "preact-messages"; import { useEffect, useState } from "preact/hooks"; import * as yup from 'yup'; import { FormProvider, FormErrors } from "../../../../components/form/FormProvider"; @@ -30,9 +29,10 @@ import { InputCurrency } from "../../../../components/form/InputCurrency"; import { InputDate } from "../../../../components/form/InputDate"; import { InputGroup } from "../../../../components/form/InputGroup"; import { ProductList } from "../../../../components/product/ProductList"; -import { useConfigContext } from "../../../../context/backend"; +import { useConfigContext } from "../../../../context/config"; import { MerchantBackend, WithId } from "../../../../declaration"; import { useInstanceDetails } from "../../../../hooks/instance"; +import { Translate, useTranslator } from "../../../../i18n"; import { OrderCreateSchema as schema } from '../../../../schemas/index'; import { multiplyPrice, rate, subtractPrices, sumPrices } from "../../../../utils/amount"; import { InventoryProductForm } from "./InventoryProductForm"; @@ -105,9 +105,9 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { summary: order.pricing.summary, products: productList, extra: value.extra, - pay_deadline: value.payments.pay_deadline ? { t_ms: Math.floor(value.payments.pay_deadline.getTime()/1000)*1000 } : undefined, - wire_transfer_deadline: value.payments.pay_deadline ? { t_ms: Math.floor(value.payments.pay_deadline.getTime()/1000)*1000 } : undefined, - refund_deadline: value.payments.refund_deadline ? { t_ms: Math.floor(value.payments.refund_deadline.getTime()/1000)*1000 } : undefined, + pay_deadline: value.payments.pay_deadline ? { t_ms: Math.floor(value.payments.pay_deadline.getTime() / 1000) * 1000 } : undefined, + wire_transfer_deadline: value.payments.pay_deadline ? { t_ms: Math.floor(value.payments.pay_deadline.getTime() / 1000) * 1000 } : undefined, + refund_deadline: value.payments.refund_deadline ? { t_ms: Math.floor(value.payments.refund_deadline.getTime() / 1000) * 1000 } : undefined, max_fee: value.payments.max_fee, max_wire_fee: value.payments.max_wire_fee, delivery_date: value.payments.delivery_date ? { t_ms: value.payments.delivery_date.getTime() } : undefined, @@ -122,7 +122,7 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { onCreate(request); } catch (err) { const errors = err.inner as yup.ValidationError[] - const pathMessages = errors.reduce((prev, cur) => !cur.path ? prev : ({ ...prev, [cur.path]: { type: cur.type, params: cur.params, message: cur.message } }), {}) + const pathMessages = errors.reduce((prev, cur) => !cur.path ? prev : ({ ...prev, [cur.path]: cur.message }), {}) setErrors(pathMessages) } } @@ -188,7 +188,7 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { const discountOrRise = rate(value.pricing.order_price, totalPrice) - + useEffect(() => { valueHandler(v => { return ({ @@ -205,7 +205,7 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { const dmwf = !details_response.ok ? undefined : details_response.data.default_max_wire_fee; const dmdf = !details_response.ok ? undefined : details_response.data.default_max_deposit_fee; const dwfa = !details_response.ok ? undefined : details_response.data.default_wire_fee_amortization; - const dpd = !details_response.ok ? undefined : details_response.data.default_pay_delay; + const dpd = !details_response.ok ? undefined : details_response.data.default_pay_delay; useEffect(() => { if (details_response.ok) { valueHandler(v => { @@ -224,6 +224,8 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { } }, [details_response.ok, dmwf, dmdf, dwfa, dpd]) + const i18n = useTranslator() + return <div> <section class="section is-main-section"> @@ -231,7 +233,7 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { <div class="column" /> <div class="column is-four-fifths"> - <InputGroup name="inventory_products" alternative={ + <InputGroup name="inventory_products" label={i18n`Inventory products`} alternative={ inventoryList.length > 0 && <p> {inventoryList.length} products, in {inventoryList.reduce((prev, cur) => cur.quantity + prev, 0)} units, @@ -246,13 +248,13 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { {inventoryList.length > 0 && <ProductList list={inventoryList.map(asProduct)} actions={[{ - name: 'Remove', handler: (e) => removeProductFromTheInventoryList(e.product_id!) + name: i18n`Remove`, handler: (e) => removeProductFromTheInventoryList(e.product_id!) }]} /> } </InputGroup> - <InputGroup name="products" alternative={ + <InputGroup name="products" label={i18n`Products`} alternative={ productList.length > 0 && <p> {productList.length} products, in {productList.reduce((prev, cur) => cur.quantity + prev, 0)} units, @@ -267,7 +269,7 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { {productList.length > 0 && <ProductList list={productList} actions={[{ - name: 'Remove', handler: (e, index) => { + name: i18n`Remove`, handler: (e, index) => { removeFromNewProduct(index); setEditingProduct(e); } @@ -280,57 +282,59 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { <FormProvider<Entity> errors={errors} object={value} valueHandler={valueHandler as any}> {hasProducts ? <Fragment> - <InputCurrency name="pricing.products_price" readonly /> - <InputCurrency name="pricing.products_taxes" readonly /> + <InputCurrency name="pricing.products_price" label={i18n`Total price`} readonly /> + <InputCurrency name="pricing.products_taxes" label={i18n`Total tax`} readonly /> <InputCurrency name="pricing.order_price" + label={i18n`Order price`} addonAfter={value.pricing.order_price !== totalPrice && (discountOrRise < 1 ? `discount of %${Math.round((1 - discountOrRise) * 100)}` : `rise of %${Math.round((discountOrRise - 1) * 100)}`) } /> - <InputCurrency name="pricing.net" readonly /> + <InputCurrency name="pricing.net" label={i18n`Net`} readonly /> </Fragment> : - <InputCurrency name="pricing.order_price" /> + <InputCurrency name="pricing.order_price" label={i18n`Order price`} /> } - <Input name="pricing.summary" inputType="multiline" /> + <Input name="pricing.summary" inputType="multiline" label={i18n`Summary`} /> - <InputGroup name="payments"> - <InputDate name="payments.auto_refund_deadline" /> - <InputDate name="payments.refund_deadline" /> - <InputDate name="payments.pay_deadline" /> + <InputGroup name="payments" label={i18n`Payments options`}> + <InputDate name="payments.auto_refund_deadline" label={i18n`Auto refund deadline`} /> + <InputDate name="payments.refund_deadline" label={i18n`Refund deadline`} /> + <InputDate name="payments.pay_deadline" label={i18n`Pay deadline`} /> - <InputDate name="payments.delivery_date" /> - {value.payments.delivery_date && <InputGroup name="payments.delivery_location" > - <Input name="payments.delivery_location.country" /> + <InputDate name="payments.delivery_date" label={i18n`Delivery date`} /> + {value.payments.delivery_date && <InputGroup name="payments.delivery_location" label={i18n`Location`} > + <Input name="payments.delivery_location.country" label={i18n`Country`} /> <Input name="payments.delivery_location.address_lines" inputType="multiline" + label={i18n`Address`} toStr={(v: string[] | undefined) => !v ? '' : v.join('\n')} fromStr={(v: string) => v.split('\n')} /> - <Input name="payments.delivery_location.building_number" /> - <Input name="payments.delivery_location.building_name" /> - <Input name="payments.delivery_location.street" /> - <Input name="payments.delivery_location.post_code" /> - <Input name="payments.delivery_location.town_location" /> - <Input name="payments.delivery_location.town" /> - <Input name="payments.delivery_location.district" /> - <Input name="payments.delivery_location.country_subdivision" /> + <Input name="payments.delivery_location.building_number" label={i18n`Building number`} /> + <Input name="payments.delivery_location.building_name" label={i18n`Building name`} /> + <Input name="payments.delivery_location.street" label={i18n`Street`} /> + <Input name="payments.delivery_location.post_code" label={i18n`Post code`} /> + <Input name="payments.delivery_location.town_location" label={i18n`Town location`} /> + <Input name="payments.delivery_location.town" label={i18n`Town`} /> + <Input name="payments.delivery_location.district" label={i18n`District`} /> + <Input name="payments.delivery_location.country_subdivision" label={i18n`Country subdivision`} /> </InputGroup>} - <InputCurrency name="payments.max_fee" /> - <InputCurrency name="payments.max_wire_fee" /> - <Input name="payments.wire_fee_amortization" /> - <Input name="payments.fullfilment_url" /> + <InputCurrency name="payments.max_fee" label={i18n`Max fee`} /> + <InputCurrency name="payments.max_wire_fee" label={i18n`Max wire fee`} /> + <Input name="payments.wire_fee_amortization" label={i18n`Wire fee amortization`} /> + <Input name="payments.fullfilment_url" label={i18n`Fullfilment url`} /> </InputGroup> - <InputGroup name="extra"> - <Input name="extra" inputType="multiline" /> + <InputGroup name="extra" label={i18n`Extra information`}> + <Input name="extra" inputType="multiline" label={`JSON value`} /> </InputGroup> </FormProvider> <div class="buttons is-right mt-5"> - {onBack && <button class="button" onClick={onBack} ><Message id="Cancel" /></button>} - <button class="button is-success" onClick={submit} ><Message id="Confirm" /></button> + {onBack && <button class="button" onClick={onBack} ><Translate>Cancel</Translate></button>} + <button class="button is-success" onClick={submit} ><Translate>Confirm</Translate></button> </div> </div> diff --git a/packages/frontend/src/paths/instance/orders/create/InventoryProductForm.tsx b/packages/frontend/src/paths/instance/orders/create/InventoryProductForm.tsx @@ -19,6 +19,7 @@ import { FormProvider, FormErrors } from "../../../../components/form/FormProvid import { InputNumber } from "../../../../components/form/InputNumber"; import { InputSearchProduct } from "../../../../components/form/InputSearchProduct"; import { MerchantBackend, WithId } from "../../../../declaration"; +import { Translate, useTranslator } from "../../../../i18n"; import { ProductMap } from "./CreatePage"; type Form = { @@ -36,29 +37,31 @@ export function InventoryProductForm({ currentProducts, onAddProduct }: Props): const [state, setState] = useState<Partial<Form>>(initialState) const [errors, setErrors] = useState<FormErrors<Form>>({}) + const i18n = useTranslator() + const submit = (): void => { if (!state.product) { - setErrors({ product: { message: 'select a product first' } }); + setErrors({ product: i18n`select a product first` }); return; } if (state.product.total_stock === -1) { onAddProduct(state.product, 1) } else { if (!state.quantity || state.quantity <= 0) { - setErrors({ quantity: { message: 'should be greater than 0' } }); + setErrors({ quantity: i18n`should be greater than 0` }); return; } const currentStock = state.product.total_stock - state.product.total_lost - state.product.total_sold const p = currentProducts[state.product.id] if (p) { if (state.quantity + p.quantity > currentStock) { - setErrors({ quantity: { message: `cannot be greater than current stock and quantity previously added. max: ${currentStock - p.quantity}` } }); + setErrors({ quantity: i18n`cannot be greater than current stock and quantity previously added. max: ${currentStock - p.quantity}` }); return; } onAddProduct(state.product, state.quantity + p.quantity) } else { if (state.quantity > currentStock) { - setErrors({ quantity: { message: `cannot be greater than current stock ${currentStock}` } }); + setErrors({ quantity: i18n`cannot be greater than current stock ${currentStock}` }); return; } onAddProduct(state.product, state.quantity) @@ -70,9 +73,9 @@ export function InventoryProductForm({ currentProducts, onAddProduct }: Props): return <FormProvider<Form> errors={errors} object={state} valueHandler={setState}> <InputSearchProduct selected={state.product} onChange={(p) => setState(v => ({ ...v, product: p }))} /> - <InputNumber<Form> name="quantity" /> + <InputNumber<Form> name="quantity" label={i18n`Quantity`} /> <div class="buttons is-right mt-5"> - <button class="button is-success" onClick={submit}>add</button> + <button class="button is-success" onClick={submit}><Translate>Add</Translate></button> </div> </FormProvider> } \ No newline at end of file diff --git a/packages/frontend/src/paths/instance/orders/create/NonInventoryProductForm.tsx b/packages/frontend/src/paths/instance/orders/create/NonInventoryProductForm.tsx @@ -20,7 +20,6 @@ import { Input } from "../../../../components/form/Input"; import { InputCurrency } from "../../../../components/form/InputCurrency"; import { InputImage } from "../../../../components/form/InputImage"; import { InputNumber } from "../../../../components/form/InputNumber"; -import { Stock } from "../../../../components/form/InputStock"; import { InputTaxes } from "../../../../components/form/InputTaxes"; import { ConfirmModal } from "../../../../components/modal"; import { MerchantBackend } from "../../../../declaration"; @@ -29,6 +28,7 @@ import { NonInventoryProductSchema as schema } from '../../../../schemas'; import * as yup from 'yup'; +import { useTranslator } from "../../../../i18n"; type Entity = MerchantBackend.Product @@ -104,7 +104,7 @@ export function ProductForm({ onSubscribe, initial }: ProductProps) { return result } catch (err) { const errors = err.inner as yup.ValidationError[] - const pathMessages = errors.reduce((prev, cur) => !cur.path ? prev : ({ ...prev, [cur.path]: { type: cur.type, params: cur.params, message: cur.message } }), {}) + const pathMessages = errors.reduce((prev, cur) => !cur.path ? prev : ({ ...prev, [cur.path]: cur.message }), {}) setErrors(pathMessages) } }, [value]) @@ -113,17 +113,19 @@ export function ProductForm({ onSubscribe, initial }: ProductProps) { onSubscribe(submit) }, [submit]) + const i18n = useTranslator() + return <div> <FormProvider<NonInventoryProduct> name="product" errors={errors} object={value} valueHandler={valueHandler} > - <InputImage<NonInventoryProduct> name="image" /> - <Input<NonInventoryProduct> name="description" inputType="multiline" /> - <Input<NonInventoryProduct> name="unit" /> - <InputCurrency<NonInventoryProduct> name="price" /> + <InputImage<NonInventoryProduct> name="image" label={i18n`Image`} /> + <Input<NonInventoryProduct> name="description" inputType="multiline" label={i18n`Description`} /> + <Input<NonInventoryProduct> name="unit" label={i18n`Unit`} /> + <InputCurrency<NonInventoryProduct> name="price" label={i18n`Price`} /> - <InputNumber<NonInventoryProduct> name="quantity" /> + <InputNumber<NonInventoryProduct> name="quantity" label={i18n`Quantity`} /> - <InputTaxes<NonInventoryProduct> name="taxes" /> + <InputTaxes<NonInventoryProduct> name="taxes" label={i18n`Taxes`} /> </FormProvider> </div> diff --git a/packages/frontend/src/paths/instance/orders/details/DetailPage.tsx b/packages/frontend/src/paths/instance/orders/details/DetailPage.tsx @@ -28,8 +28,8 @@ import { InputCurrency } from "../../../../components/form/InputCurrency"; import { NotificationCard } from "../../../../components/menu"; import { ProductList } from "../../../../components/product/ProductList"; import { MerchantBackend } from "../../../../declaration"; +import { Translate, useTranslator } from "../../../../i18n"; import { mergeRefunds } from "../../../../utils/amount"; -import { copyToClipboard } from "../../../../utils/functions"; import { RefundModal } from "../list/Table"; import { Event, Timeline } from "./Timeline"; @@ -75,6 +75,7 @@ function ClaimedPage({ id, order }: { id: string; order: MerchantBackend.Orders. }) const [value, valueHandler] = useState<Partial<Claimed>>(order) + const i18n = useTranslator() return <div> <section class="section"> @@ -88,8 +89,8 @@ function ClaimedPage({ id, order }: { id: string; order: MerchantBackend.Orders. <div class="level"> <div class="level-left"> <div class="level-item"> - Order #{id} - <div class="tag is-info ml-4">claimed</div> + <Translate>Order</Translate> #{id} + <div class="tag is-info ml-4"><Translate>claimed</Translate></div> </div> </div> </div> @@ -106,7 +107,7 @@ function ClaimedPage({ id, order }: { id: string; order: MerchantBackend.Orders. <h1 class="title"> <button class="button is-info" onClick={() => { if (order.contract_terms.fulfillment_url) copyToClipboard(order.contract_terms.fulfillment_url) - }}>copy url</button> + }}><Translate>copy url</Translate></button> </h1> </div> </div> @@ -122,8 +123,8 @@ function ClaimedPage({ id, order }: { id: string; order: MerchantBackend.Orders. // maxWidth: '100%', }}> {/* <a href={order.order_status_url} rel="nofollow" target="new">{order.order_status_url}</a> */} - <p>pay at: <b>missing value, there is no order_status_url</b></p> - <p>created at: {format(new Date(order.contract_terms.timestamp.t_ms), 'yyyy-MM-dd HH:mm:ss')}</p> + <p><Translate>pay at</Translate>: <b>missing value, there is no order_status_url</b></p> + <p><Translate>created at</Translate>: {format(new Date(order.contract_terms.timestamp.t_ms), 'yyyy-MM-dd HH:mm:ss')}</p> </div> </div> </div> @@ -134,15 +135,15 @@ function ClaimedPage({ id, order }: { id: string; order: MerchantBackend.Orders. <section class="section"> <div class="columns"> <div class="column is-4"> - <div class="title">Timeline</div> + <div class="title"><Translate>Timeline</Translate></div> <Timeline events={events} /> </div> <div class="column is-8" > - <div class="title">Payment details</div> + <div class="title"><Translate>Payment details</Translate></div> <FormProvider<Claimed> object={value} valueHandler={valueHandler} > - <Input name="contract_terms.summary" readonly inputType="multiline" /> - <InputCurrency name="contract_terms.amount" readonly /> - <Input<Claimed> name="order_status" readonly /> + <Input name="contract_terms.summary" readonly inputType="multiline" label={i18n`Summary`} /> + <InputCurrency name="contract_terms.amount" readonly label={i18n`Amount`} /> + <Input<Claimed> name="order_status" readonly label={i18n`Order status`} /> </FormProvider> </div> </div> @@ -152,7 +153,7 @@ function ClaimedPage({ id, order }: { id: string; order: MerchantBackend.Orders. <section class="section"> <div class="columns"> <div class="column is-12" > - <div class="title">Product list</div> + <div class="title"><Translate>Product list</Translate></div> <ProductList list={order.contract_terms.products} /> </div> <div class="column" /> @@ -217,6 +218,7 @@ function PaidPage({ id, order, onRefund }: { id: string; order: MerchantBackend. const [value, valueHandler] = useState<Partial<Paid>>(order) const refundable = new Date().getTime() < order.contract_terms.refund_deadline.t_ms + const i18n = useTranslator() return <div> <section class="section"> @@ -230,13 +232,13 @@ function PaidPage({ id, order, onRefund }: { id: string; order: MerchantBackend. <div class="level"> <div class="level-left"> <div class="level-item"> - Order #{id} - <div class="tag is-success ml-4">paid</div> + <Translate>Order</Translate> #{id} + <div class="tag is-success ml-4"><Translate>paid</Translate></div> {order.wired ? - <div class="tag is-success ml-4">wired</div> : null + <div class="tag is-success ml-4"><Translate>wired</Translate></div> : null } {order.refunded ? - <div class="tag is-danger ml-4">refunded</div> : null + <div class="tag is-danger ml-4"><Translate>refunded</Translate></div> : null } </div> </div> @@ -253,10 +255,10 @@ function PaidPage({ id, order, onRefund }: { id: string; order: MerchantBackend. <div class="level-item"> <h1 class="title"> <div class="buttons"> - {refundable && <button class="button is-danger" onClick={() => onRefund(id)}>refund</button>} + {refundable && <button class="button is-danger" onClick={() => onRefund(id)}><Translate>refund</Translate></button>} <button class="button is-info" onClick={() => { if (order.contract_terms.fulfillment_url) copyToClipboard(order.contract_terms.fulfillment_url) - }}>copy url</button> + }}><Translate>copy url</Translate></button> </div> </h1> </div> @@ -284,17 +286,17 @@ function PaidPage({ id, order, onRefund }: { id: string; order: MerchantBackend. <section class="section"> <div class="columns"> <div class="column is-4"> - <div class="title">Timeline</div> + <div class="title"><Translate>Timeline</Translate></div> <Timeline events={events} /> </div> <div class="column is-8" > - <div class="title">Payment details</div> + <div class="title"><Translate>Payment details</Translate></div> <FormProvider<Paid> object={value} valueHandler={valueHandler} > - <Input name="contract_terms.summary" readonly inputType="multiline" /> - <InputCurrency name="contract_terms.amount" readonly /> - {order.refunded && <InputCurrency<Paid> name="refund_amount" readonly />} - <InputCurrency<Paid> name="deposit_total" readonly /> - <Input<Paid> name="order_status" readonly /> + <Input name="contract_terms.summary" readonly inputType="multiline" label={i18n`Summary`} /> + <InputCurrency name="contract_terms.amount" readonly label={i18n`Amount`} /> + {order.refunded && <InputCurrency<Paid> name="refund_amount" readonly label={i18n`Refunded amount`} />} + <InputCurrency<Paid> name="deposit_total" readonly label={i18n`Deposit total`} /> + <Input<Paid> name="order_status" readonly label={i18n`Order status`} /> </FormProvider> </div> </div> @@ -303,7 +305,7 @@ function PaidPage({ id, order, onRefund }: { id: string; order: MerchantBackend. {order.contract_terms.products.length ? <section class="section"> <div class="columns"> <div class="column is-12" > - <div class="title">Product list</div> + <div class="title"><Translate>Product list</Translate></div> <ProductList list={order.contract_terms.products} /> </div> <div class="column" /> @@ -319,6 +321,7 @@ function PaidPage({ id, order, onRefund }: { id: string; order: MerchantBackend. function UnpaidPage({ id, order }: { id: string; order: MerchantBackend.Orders.CheckPaymentUnpaidResponse }) { const [value, valueHandler] = useState<Partial<Unpaid>>(order) + const i18n = useTranslator() return <div> <section class="hero is-hero-bar"> @@ -327,10 +330,10 @@ function UnpaidPage({ id, order }: { id: string; order: MerchantBackend.Orders.C <div class="level-left"> <div class="level-item"> <h1 class="title"> - Order #{id} + <Translate>Order</Translate> #{id} </h1> </div> - <div class="tag is-dark">unpaid</div> + <div class="tag is-dark"><Translate>unpaid</Translate></div> </div> </div> @@ -343,8 +346,8 @@ function UnpaidPage({ id, order }: { id: string; order: MerchantBackend.Orders.C textOverflow: 'ellipsis', // maxWidth: '100%', }}> - <p>pay at: <a href={order.order_status_url} rel="nofollow" target="new">{order.order_status_url}</a></p> - <p>created at: <b>missing value, there is no contract term yet</b></p> + <p><Translate>pay at</Translate>: <a href={order.order_status_url} rel="nofollow" target="new">{order.order_status_url}</a></p> + <p><Translate>created at</Translate>: <b>missing value, there is no contract term yet</b></p> </div> </div> </div> @@ -357,9 +360,9 @@ function UnpaidPage({ id, order }: { id: string; order: MerchantBackend.Orders.C <div class="column" /> <div class="column is-6"> <FormProvider<Unpaid> object={value} valueHandler={valueHandler} > - <Input<Unpaid> name="order_status" readonly /> - <Input<Unpaid> name="order_status_url" readonly /> - <Input<Unpaid> name="taler_pay_uri" readonly /> + <Input<Unpaid> name="order_status" readonly label={i18n`Order status`} /> + <Input<Unpaid> name="order_status_url" readonly label={i18n`Order status URL`} /> + <Input<Unpaid> name="taler_pay_uri" readonly label={i18n`Pay URI`} /> </FormProvider> </div> <div class="column" /> @@ -377,7 +380,7 @@ export function DetailPage({ id, selected, onRefund }: Props): VNode { case 'claimed': return <ClaimedPage id={id} order={selected} /> case 'paid': return <PaidPage id={id} order={selected} onRefund={setShowRefund} /> case 'unpaid': return <UnpaidPage id={id} order={selected} /> - default: return <div>unknown order status</div> + default: return <div><Translate>Unknown order status. This is an error, please contact the administrator.</Translate></div> } } @@ -401,4 +404,10 @@ export function DetailPage({ id, selected, onRefund }: Props): VNode { }} />} </Fragment> -} -\ No newline at end of file +} + +async function copyToClipboard(text: string) { + return navigator.clipboard.writeText(text) +} + + diff --git a/packages/frontend/src/paths/instance/orders/details/index.tsx b/packages/frontend/src/paths/instance/orders/details/index.tsx @@ -19,6 +19,7 @@ import { Loading } from "../../../../components/exception/loading"; import { NotificationCard } from "../../../../components/menu"; import { HttpError } from "../../../../hooks/backend"; import { useOrderDetails, useOrderAPI } from "../../../../hooks/order"; +import { useTranslator } from "../../../../i18n"; import { Notification } from "../../../../utils/types"; import { DetailPage } from "./DetailPage"; @@ -36,6 +37,8 @@ export default function Update({ oid, onBack, onLoadError, onNotFound, onUnautho const result = useOrderDetails(oid) const [notif, setNotif] = useState<Notification | undefined>(undefined) + const i18n = useTranslator() + if (result.clientError && result.isUnauthorized) return onUnauthorized() if (result.clientError && result.isNotfound) return onNotFound() if (result.loading) return <Loading /> @@ -50,10 +53,10 @@ export default function Update({ oid, onBack, onLoadError, onNotFound, onUnautho id={oid} onRefund={(id, value) => refundOrder(id, value) .then(() => setNotif({ - message: 'refund created successfully', + message: i18n`refund created successfully`, type: "SUCCESS" })).catch((error) => setNotif({ - message: 'could not create the refund', + message: i18n`could not create the refund`, type: "ERROR", description: error.message })) diff --git a/packages/frontend/src/paths/instance/orders/list/Table.tsx b/packages/frontend/src/paths/instance/orders/list/Table.tsx @@ -21,7 +21,6 @@ import { format } from "date-fns"; import { h, VNode } from "preact"; -import { Message } from "preact-messages"; import { StateUpdater, useState } from "preact/hooks"; import { FormProvider, FormErrors } from "../../../../components/form/FormProvider"; import { Input } from "../../../../components/form/Input"; @@ -31,6 +30,7 @@ import { InputSelector } from "../../../../components/form/InputSelector"; import { ConfirmModal } from "../../../../components/modal"; import { MerchantBackend, WithId } from "../../../../declaration"; import { useOrderDetails } from "../../../../hooks/order"; +import { Translate, useTranslator } from "../../../../i18n"; import { RefoundSchema } from "../../../../schemas"; import { mergeRefunds, subtractPrices, sumPrices } from "../../../../utils/amount"; import { AMOUNT_ZERO_REGEX } from "../../../../utils/constants"; @@ -57,7 +57,7 @@ export function CardTable({ instances, onCreate, onRefund, onCopyURL, onSelect, return <div class="card has-table"> <header class="card-header"> - <p class="card-header-title"><span class="icon"><i class="mdi mdi-cash-register" /></span><Message id="Orders" /></p> + <p class="card-header-title"><span class="icon"><i class="mdi mdi-cash-register" /></span><Translate>Orders</Translate></p> <div class="card-header-icon" aria-label="more options" /> @@ -108,13 +108,13 @@ interface TableProps { function Table({ instances, onSelect, onRefund, onCopyURL, onLoadMoreAfter, onLoadMoreBefore, hasMoreAfter, hasMoreBefore }: TableProps): VNode { return <div class="table-container"> - {onLoadMoreBefore && <button class="button is-fullwidth" disabled={!hasMoreBefore} onClick={onLoadMoreBefore}> load newer orders </button>} + {onLoadMoreBefore && <button class="button is-fullwidth" disabled={!hasMoreBefore} onClick={onLoadMoreBefore}><Translate>load newer orders</Translate></button>} <table class="table is-striped is-hoverable is-fullwidth"> <thead> <tr> - <th style={{ minWidth: 100 }}><Message id="fields.order.date.label" /></th> - <th style={{ minWidth: 100 }}><Message id="fields.order.amount.label" /></th> - <th style={{ minWidth: 500 }}><Message id="fields.order.summary.label" /></th> + <th style={{ minWidth: 100 }}><Translate>Date</Translate></th> + <th style={{ minWidth: 100 }}><Translate>Amount</Translate></th> + <th style={{ minWidth: 500 }}><Translate>Summary</Translate></th> <th style={{ minWidth: 50 }} /> </tr> </thead> @@ -128,12 +128,12 @@ function Table({ instances, onSelect, onRefund, onCopyURL, onLoadMoreAfter, onLo <div class="buttons is-right"> {(i.refundable) && <button class="button is-small is-danger jb-modal" type="button" onClick={(): void => onRefund(i)}> - Refund + <Translate>Refund</Translate> </button> } {(!i.paid) && <button class="button is-small is-info jb-modal" type="button" onClick={(): void => onCopyURL(i)}> - copy url + <Translate>copy url</Translate> </button> } </div> @@ -142,7 +142,7 @@ function Table({ instances, onSelect, onRefund, onCopyURL, onLoadMoreAfter, onLo })} </tbody> </table> - {onLoadMoreAfter && <button class="button is-fullwidth" disabled={!hasMoreAfter} onClick={onLoadMoreAfter}> load older orders </button>} + {onLoadMoreAfter && <button class="button is-fullwidth" disabled={!hasMoreAfter} onClick={onLoadMoreAfter}><Translate>load older orders</Translate></button>} </div> } @@ -151,7 +151,7 @@ function EmptyTable(): VNode { <p> <span class="icon is-large"><i class="mdi mdi-emoticon-sad mdi-48px" /></span> </p> - <p>No orders has been found</p> + <p><Translate>No orders has been found</Translate></p> </div> } @@ -165,7 +165,7 @@ export function RefundModal({ id, onCancel, onConfirm }: RefundModalProps): VNod const result = useOrderDetails(id) type State = { mainReason?: string, description?: string, refund?: string } const [form, setValue] = useState<State>({}) - + const i18n = useTranslator(); const [errors, setErrors] = useState<FormErrors<State>>({}) const validateAndConfirm = () => { @@ -178,7 +178,7 @@ export function RefundModal({ id, onCancel, onConfirm }: RefundModalProps): VNod }) } catch (err) { const errors = err.inner as any[] - const pathMessages = errors.reduce((prev, cur) => !cur.path ? prev : ({ ...prev, [cur.path]: { type: cur.type, params: cur.params, message: cur.message } }), {}) + const pathMessages = errors.reduce((prev, cur) => !cur.path ? prev : ({ ...prev, [cur.path]: cur.message }), {}) setErrors(pathMessages) } } @@ -190,18 +190,18 @@ export function RefundModal({ id, onCancel, onConfirm }: RefundModalProps): VNod const totalRefundable = !orderPrice ? undefined : (refunds.length ? subtractPrices(orderPrice, totalRefunded) : orderPrice) const isRefundable = totalRefundable && !AMOUNT_ZERO_REGEX.test(totalRefundable) - + //FIXME: parameters in the translation return <ConfirmModal description="refund" danger active onCancel={onCancel} onConfirm={validateAndConfirm}> {refunds.length > 0 && <div class="columns"> <div class="column is-2" /> <div class="column is-8"> - <InputGroup name="asd" description={`${totalRefunded} was already refunded`}> + <InputGroup name="asd" label={`${totalRefunded} was already refunded`}> <table class="table is-fullwidth"> <thead> <tr> - <th>date</th> - <th>amount</th> - <th>reason</th> + <th><Translate>date</Translate></th> + <th><Translate>amount</Translate></th> + <th><Translate>reason</Translate></th> </tr> </thead> <tbody> @@ -219,13 +219,13 @@ export function RefundModal({ id, onCancel, onConfirm }: RefundModalProps): VNod <div class="column is-2" /> </div>} - { isRefundable && <FormProvider<State> errors={errors} object={form} valueHandler={(d) => setValue(d as any)}> - <InputCurrency<State> name="refund"> - Max refundable: {totalRefundable} + {isRefundable && <FormProvider<State> errors={errors} object={form} valueHandler={(d) => setValue(d as any)}> + <InputCurrency<State> name="refund" label={i18n`Refund`}> + <Translate>Max refundable:</Translate> {totalRefundable} </InputCurrency> - <InputSelector name="mainReason" values={['duplicated', 'requested by the customer', 'other']} /> - {form.mainReason && <Input<State> name="description" />} - </FormProvider> } + <InputSelector name="mainReason" label={i18n`Reason`} values={[i18n`duplicated`, i18n`requested by the customer`, i18n`other`]} /> + {form.mainReason && <Input<State> label={i18n`Description`} name="description" />} + </FormProvider>} </ConfirmModal> } diff --git a/packages/frontend/src/paths/instance/orders/list/index.tsx b/packages/frontend/src/paths/instance/orders/list/index.tsx @@ -27,7 +27,7 @@ import { DatePicker } from '../../../../components/form/DatePicker'; import { NotificationCard } from '../../../../components/menu'; import { HttpError } from '../../../../hooks/backend'; import { InstanceOrderFilter, useInstanceOrders, useOrderAPI } from '../../../../hooks/order'; -import { copyToClipboard } from '../../../../utils/functions'; +import { Translate, useTranslator } from '../../../../i18n'; import { Notification } from '../../../../utils/types'; import { CardTable } from './Table'; @@ -78,6 +78,8 @@ export default function ({ onUnauthorized, onLoadError, onCreate, onSelect, onNo } } + const i18n = useTranslator() + return <section class="section is-main-section"> <NotificationCard notification={notif} /> @@ -86,7 +88,7 @@ export default function ({ onUnauthorized, onLoadError, onCreate, onSelect, onNo <div class="level-item"> <div class="field has-addons"> <div class="control"> - <input class={errorOrderId ? "input is-danger" : "input"} type="text" value={orderId} onChange={e => setOrderId(e.currentTarget.value)} placeholder="go to order id" /> + <input class={errorOrderId ? "input is-danger" : "input"} type="text" value={orderId} onChange={e => setOrderId(e.currentTarget.value)} placeholder={i18n`go to order id`} /> {errorOrderId && <p class="help is-danger">{errorOrderId}</p>} </div> <div class="control"> @@ -102,10 +104,10 @@ export default function ({ onUnauthorized, onLoadError, onCreate, onSelect, onNo <div class="column"> <div class="tabs"> <ul> - <li class={isPaidActive}><a onClick={() => setFilter({ paid: 'yes' })}>Paid</a></li> - <li class={isRefundedActive}><a onClick={() => setFilter({ refunded: 'yes' })}>Refunded</a></li> - <li class={isNotWiredActive}><a onClick={() => setFilter({ wired: 'no' })}>Not wired</a></li> - <li class={isAllActive}><a onClick={() => setFilter({})}>All</a></li> + <li class={isPaidActive}><a onClick={() => setFilter({ paid: 'yes' })}><Translate>Paid</Translate></a></li> + <li class={isRefundedActive}><a onClick={() => setFilter({ refunded: 'yes' })}><Translate>Refunded</Translate></a></li> + <li class={isNotWiredActive}><a onClick={() => setFilter({ wired: 'no' })}><Translate>Not wired</Translate></a></li> + <li class={isAllActive}><a onClick={() => setFilter({})}><Translate>All</Translate></a></li> </ul> </div> </div> @@ -118,7 +120,7 @@ export default function ({ onUnauthorized, onLoadError, onCreate, onSelect, onNo </a> </div>} <div class="control"> - <input class="input" type="text" readonly value={!filter.date ? '' : format(filter.date, 'yyyy/MM/dd')} placeholder="pick a date" /> + <input class="input" type="text" readonly value={!filter.date ? '' : format(filter.date, 'yyyy/MM/dd')} placeholder={i18n`pick a date`} /> </div> <div class="control"> <a class="button" onClick={() => { setPickDate(true) }}> @@ -142,10 +144,10 @@ export default function ({ onUnauthorized, onLoadError, onCreate, onSelect, onNo onCopyURL={(id) => getPaymentURL(id).then((resp) => copyToClipboard(resp.data))} onRefund={(id, value) => refundOrder(id, value) .then(() => setNotif({ - message: 'refund created successfully', + message: i18n`refund created successfully`, type: "SUCCESS" })).catch((error) => setNotif({ - message: 'could not create the refund', + message: i18n`could not create the refund`, type: "ERROR", description: error.message })) @@ -154,4 +156,8 @@ export default function ({ onUnauthorized, onLoadError, onCreate, onSelect, onNo onLoadMoreAfter={result.loadMore} hasMoreAfter={!result.isReachingEnd} /> </section> -} -\ No newline at end of file +} + +async function copyToClipboard(text: string) { + return navigator.clipboard.writeText(text) +} diff --git a/packages/frontend/src/paths/instance/products/create/CreatePage.tsx b/packages/frontend/src/paths/instance/products/create/CreatePage.tsx @@ -20,10 +20,10 @@ */ import { h, VNode } from "preact"; -import { Message } from "preact-messages"; import { ProductForm } from "../../../../components/product/ProductForm"; import { MerchantBackend } from "../../../../declaration"; import { useListener } from "../../../../hooks"; +import { Translate } from "../../../../i18n"; type Entity = MerchantBackend.Products.ProductAddDetail & { product_id: string} @@ -47,8 +47,8 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { <ProductForm onSubscribe={addFormSubmitter} /> <div class="buttons is-right mt-5"> - {onBack && <button class="button" onClick={onBack} ><Message id="Cancel" /></button>} - <button class="button is-success" onClick={submitForm} ><Message id="Confirm" /></button> + {onBack && <button class="button" onClick={onBack} ><Translate>Cancel</Translate></button>} + <button class="button is-success" onClick={submitForm} ><Translate>Confirm</Translate></button> </div> </div> diff --git a/packages/frontend/src/paths/instance/products/create/index.tsx b/packages/frontend/src/paths/instance/products/create/index.tsx @@ -24,6 +24,7 @@ import { useState } from 'preact/hooks'; import { NotificationCard } from '../../../../components/menu'; import { MerchantBackend } from '../../../../declaration'; import { useProductAPI } from '../../../../hooks/product'; +import { useTranslator } from '../../../../i18n'; import { Notification } from '../../../../utils/types'; import { CreatePage } from './CreatePage'; @@ -35,7 +36,8 @@ interface Props { export default function CreateProduct({ onConfirm, onBack }: Props): VNode { const { createProduct } = useProductAPI() const [notif, setNotif] = useState<Notification | undefined>(undefined) - + const i18n = useTranslator() + return <Fragment> <NotificationCard notification={notif} /> <CreatePage @@ -43,7 +45,7 @@ export default function CreateProduct({ onConfirm, onBack }: Props): VNode { onCreate={(request: MerchantBackend.Products.ProductAddDetail) => { createProduct(request).then(() => onConfirm()).catch((error) => { setNotif({ - message: 'could not create product', + message: i18n`could not create product`, type: "ERROR", description: error.message }) diff --git a/packages/frontend/src/paths/instance/products/list/Table.tsx b/packages/frontend/src/paths/instance/products/list/Table.tsx @@ -21,13 +21,13 @@ import { format } from "date-fns" import { ComponentChildren, Fragment, h, VNode } from "preact" -import { Message } from "preact-messages" import { StateUpdater, useState } from "preact/hooks" import { FormProvider, FormErrors } from "../../../../components/form/FormProvider" import { InputCurrency } from "../../../../components/form/InputCurrency" import { InputNumber } from "../../../../components/form/InputNumber" import { MerchantBackend, WithId } from "../../../../declaration" import emptyImage from "../../../../assets/empty.png"; +import { Translate, useTranslator } from "../../../../i18n" type Entity = MerchantBackend.Products.ProductDetail & WithId @@ -45,7 +45,7 @@ export function CardTable({ instances, onCreate, onSelect, onUpdate, onDelete }: return <div class="card has-table"> <header class="card-header"> - <p class="card-header-title"><span class="icon"><i class="mdi mdi-shopping" /></span><Message id="Products" /></p> + <p class="card-header-title"><span class="icon"><i class="mdi mdi-shopping" /></span><Translate>Products</Translate></p> <div class="card-header-icon" aria-label="more options" /> <div class="card-header-icon" aria-label="more options"> @@ -82,13 +82,13 @@ function Table({ rowSelection, rowSelectionHandler, instances, onSelect, onUpdat <table class="table is-fullwidth is-striped is-hoverable is-fullwidth"> <thead> <tr> - <th><Message id="fields.product.image.label" style={{ with: 100 }} /></th> - <th><Message id="fields.product.description.label" /></th> - <th><Message id="fields.product.sell.label" /></th> - <th><Message id="fields.product.taxes.label" /></th> - <th><Message id="fields.product.profit.label" /></th> - <th><Message id="fields.product.stock.label" /></th> - <th><Message id="fields.product.sold.label" /></th> + <th><Translate>Image</Translate></th> + <th><Translate>Description</Translate></th> + <th><Translate>Sell</Translate></th> + <th><Translate>Taxes</Translate></th> + <th><Translate>Profit</Translate></th> + <th><Translate>Stock</Translate></th> + <th><Translate>Sold</Translate></th> <th /> </tr> </thead> @@ -154,15 +154,16 @@ interface FastProductUpdate { } function FastProductWithInfiniteStockUpdateForm({ product, onUpdate, onCancel }: FastProductUpdateFormProps) { - const [value, valueHandler] = useState<{price:string}>({price: product.price}) + const [value, valueHandler] = useState<{ price: string }>({ price: product.price }) + const i18n = useTranslator() return <Fragment> <FormProvider<FastProductUpdate> name="added" object={value} valueHandler={valueHandler as any} > - <InputCurrency<FastProductUpdate> name="price" /> + <InputCurrency<FastProductUpdate> name="price" label={i18n`Price`} /> </FormProvider> <div class="buttons is-right mt-5"> - <button class="button" onClick={onCancel} ><Message id="Cancel" /></button> + <button class="button" onClick={onCancel} ><Translate>Cancel</Translate></button> <button class="button is-info" onClick={() => { return onUpdate({ @@ -170,7 +171,7 @@ function FastProductWithInfiniteStockUpdateForm({ product, onUpdate, onCancel }: price: value.price, }) - }}><Message id="Confirm" /></button> + }}><Translate>Confirm</Translate></button> </div> </Fragment> @@ -184,9 +185,9 @@ function FastProductWithManagedStockUpdateForm({ product, onUpdate, onCancel }: const currentStock = product.total_stock - product.total_sold - product.total_lost const errors: FormErrors<FastProductUpdate> = { - lost: currentStock + value.incoming < value.lost ? { - message: `lost cannot be greater that current + incoming (max ${currentStock + value.incoming})` - } : undefined + lost: currentStock + value.incoming < value.lost ? + `lost cannot be greater that current + incoming (max ${currentStock + value.incoming})` + : undefined } const stockUpdateDescription = errors.lost ? '' : ( @@ -196,11 +197,12 @@ function FastProductWithManagedStockUpdateForm({ product, onUpdate, onCancel }: ) const hasErrors = Object.keys(errors).some(k => (errors as any)[k] !== undefined) + const i18n = useTranslator() return <Fragment> <FormProvider<FastProductUpdate> name="added" errors={errors} object={value} valueHandler={valueHandler as any} > - <InputNumber<FastProductUpdate> name="incoming" /> - <InputNumber<FastProductUpdate> name="lost" /> + <InputNumber<FastProductUpdate> name="incoming" label={i18n`Incoming`} /> + <InputNumber<FastProductUpdate> name="lost" label={i18n`Lost`} /> <div class="field is-horizontal"> <div class="field-label is-normal" /> <div class="field-body is-flex-grow-3"> @@ -209,11 +211,11 @@ function FastProductWithManagedStockUpdateForm({ product, onUpdate, onCancel }: </div> </div> </div> - <InputCurrency<FastProductUpdate> name="price" /> + <InputCurrency<FastProductUpdate> name="price" label={i18n`Price`} /> </FormProvider> <div class="buttons is-right mt-5"> - <button class="button" onClick={onCancel} ><Message id="Cancel" /></button> + <button class="button" onClick={onCancel} ><Translate>Cancel</Translate></button> <button class="button is-info" disabled={hasErrors} onClick={() => { return onUpdate({ @@ -223,7 +225,7 @@ function FastProductWithManagedStockUpdateForm({ product, onUpdate, onCancel }: price: value.price, }) - }}><Message id="Confirm" /></button> + }}><Translate>Confirm</Translate></button> </div> </Fragment> @@ -240,7 +242,7 @@ function EmptyTable(): VNode { <p> <span class="icon is-large"><i class="mdi mdi-emoticon-sad mdi-48px" /></span> </p> - <p><Message id="There is no instances yet, add more pressing the + sign" /></p> + <p><Translate>There is no instances yet, add more pressing the + sign</Translate></p> </div> } diff --git a/packages/frontend/src/paths/instance/products/list/index.tsx b/packages/frontend/src/paths/instance/products/list/index.tsx @@ -26,6 +26,7 @@ import { NotificationCard } from '../../../../components/menu'; import { MerchantBackend, WithId } from '../../../../declaration'; import { HttpError } from '../../../../hooks/backend'; import { useInstanceProducts, useProductAPI } from "../../../../hooks/product"; +import { useTranslator } from '../../../../i18n'; import { Notification } from '../../../../utils/types'; import { CardTable } from './Table'; @@ -41,6 +42,8 @@ export default function ProductList({ onUnauthorized, onLoadError, onCreate, onS const { deleteProduct, updateProduct } = useProductAPI() const [notif, setNotif] = useState<Notification | undefined>(undefined) + const i18n = useTranslator() + if (result.clientError && result.isUnauthorized) return onUnauthorized() if (result.clientError && result.isNotfound) return onNotFound() if (result.loading) return <Loading /> @@ -53,10 +56,10 @@ export default function ProductList({ onUnauthorized, onLoadError, onCreate, onS onCreate={onCreate} onUpdate={(id, prod) => updateProduct(id, prod) .then(() => setNotif({ - message: 'product updated successfully', + message: i18n`product updated successfully`, type: "SUCCESS" })).catch((error) => setNotif({ - message: 'could not update the product', + message: i18n`could not update the product`, type: "ERROR", description: error.message })) @@ -64,10 +67,10 @@ export default function ProductList({ onUnauthorized, onLoadError, onCreate, onS onSelect={(product) => onSelect(product.id)} onDelete={(prod: (MerchantBackend.Products.ProductDetail & WithId)) => deleteProduct(prod.id) .then(() => setNotif({ - message: 'product delete successfully', + message: i18n`product delete successfully`, type: "SUCCESS" })).catch((error) => setNotif({ - message: 'could not delete the product', + message: i18n`could not delete the product`, type: "ERROR", description: error.message })) diff --git a/packages/frontend/src/paths/instance/products/update/UpdatePage.tsx b/packages/frontend/src/paths/instance/products/update/UpdatePage.tsx @@ -20,10 +20,10 @@ */ import { h, VNode } from "preact"; -import { Message } from "preact-messages"; import { ProductForm } from "../../../../components/product/ProductForm"; import { MerchantBackend, WithId } from "../../../../declaration"; import { useListener } from "../../../../hooks"; +import { Translate } from "../../../../i18n"; type Entity = MerchantBackend.Products.ProductDetail & WithId @@ -51,8 +51,8 @@ export function UpdatePage({ product, onUpdate, onBack }: Props): VNode { }} alreadyExist /> <div class="buttons is-right mt-5"> - {onBack && <button class="button" onClick={onBack} ><Message id="Cancel" /></button>} - <button class="button is-success" onClick={submitForm} ><Message id="Confirm" /></button> + {onBack && <button class="button" onClick={onBack} ><Translate>Cancel</Translate></button>} + <button class="button is-success" onClick={submitForm} ><Translate>Confirm</Translate></button> </div> </div> diff --git a/packages/frontend/src/paths/instance/products/update/index.tsx b/packages/frontend/src/paths/instance/products/update/index.tsx @@ -26,6 +26,7 @@ import { NotificationCard } from '../../../../components/menu'; import { MerchantBackend } from '../../../../declaration'; import { HttpError } from '../../../../hooks/backend'; import { useProductAPI, useProductDetails } from '../../../../hooks/product'; +import { useTranslator } from '../../../../i18n'; import { Notification } from '../../../../utils/types'; import { UpdatePage } from './UpdatePage'; @@ -43,6 +44,8 @@ export default function UpdateProduct({ pid, onConfirm, onBack, onUnauthorized, const result = useProductDetails(pid) const [notif, setNotif] = useState<Notification | undefined>(undefined) + const i18n = useTranslator() + if (result.clientError && result.isUnauthorized) return onUnauthorized() if (result.clientError && result.isNotfound) return onNotFound() if (result.loading) return <Loading /> @@ -58,7 +61,7 @@ export default function UpdateProduct({ pid, onConfirm, onBack, onUnauthorized, .then(onConfirm) .catch((error) => { setNotif({ - message: 'could not create product', + message: i18n`could not create product`, type: "ERROR", description: error.message }) diff --git a/packages/frontend/src/paths/instance/tips/list/Table.tsx b/packages/frontend/src/paths/instance/tips/list/Table.tsx @@ -20,9 +20,9 @@ */ import { h, VNode } from "preact" -import { Message } from "preact-messages" import { StateUpdater, useEffect, useState } from "preact/hooks" import { MerchantBackend, WithId } from "../../../../declaration" +import { Translate } from "../../../../i18n" import { Actions, buildActions } from "../../../../utils/table" type Entity = MerchantBackend.Tips.ReserveStatusEntry & WithId @@ -56,7 +56,7 @@ export function CardTable({ instances, onCreate, onUpdate, onDelete, selected }: return <div class="card has-table"> <header class="card-header"> - <p class="card-header-title"><span class="icon"><i class="mdi mdi-cash" /></span><Message id="Tips" /></p> + <p class="card-header-title"><span class="icon"><i class="mdi mdi-cash" /></span><Translate>Tips</Translate></p> <div class="card-header-icon" aria-label="more options"> @@ -108,9 +108,9 @@ function Table({ rowSelection, rowSelectionHandler, instances, onUpdate, onDelet <span class="check" /> </label> </th> - <th><Message id="fields.tips.committed_amount.label" /></th> - <th><Message id="fields.tips.exchange_initial_amount.label" /></th> - <th><Message id="fields.tips.merchant_initial_amount.label" /></th> + <th><Translate>Committed amount</Translate></th> + <th><Translate>Exchange initial amount</Translate></th> + <th><Translate>Merchant initial amount</Translate></th> <th /> </tr> </thead> @@ -145,6 +145,6 @@ function EmptyTable(): VNode { <p> <span class="icon is-large"><i class="mdi mdi-emoticon-sad mdi-48px" /></span> </p> - <p><Message id="There is no tips yet, add more pressing the + sign" /></p> + <p><Translate>There is no tips yet, add more pressing the + sign</Translate></p> </div> } diff --git a/packages/frontend/src/paths/instance/tips/list/index.tsx b/packages/frontend/src/paths/instance/tips/list/index.tsx @@ -21,7 +21,7 @@ import { h, VNode } from 'preact'; import { Loading } from '../../../../components/exception/loading'; -import { useConfigContext } from '../../../../context/backend'; +import { useConfigContext } from '../../../../context/config'; import { MerchantBackend } from '../../../../declaration'; import { HttpError } from '../../../../hooks/backend'; import { useInstanceTips, useTipsMutateAPI } from "../../../../hooks/tips"; diff --git a/packages/frontend/src/paths/instance/transfers/list/Table.tsx b/packages/frontend/src/paths/instance/transfers/list/Table.tsx @@ -20,9 +20,9 @@ */ import { h, VNode } from "preact" -import { Message } from "preact-messages" import { StateUpdater, useEffect, useState } from "preact/hooks" import { MerchantBackend, WithId } from "../../../../declaration" +import { Translate } from "../../../../i18n" import { Actions, buildActions } from "../../../../utils/table" type Entity = MerchantBackend.Transfers.TransferDetails & WithId @@ -56,7 +56,7 @@ export function CardTable({ instances, onCreate, onUpdate, onDelete, selected }: return <div class="card has-table"> <header class="card-header"> - <p class="card-header-title"><span class="icon"><i class="mdi mdi-bank" /></span><Message id="Transfers" /></p> + <p class="card-header-title"><span class="icon"><i class="mdi mdi-bank" /></span><Translate>Transfers</Translate></p> <div class="card-header-icon" aria-label="more options"> @@ -108,8 +108,8 @@ function Table({ rowSelection, rowSelectionHandler, instances, onUpdate, onDelet <span class="check" /> </label> </th> - <th><Message id="fields.instance.id.label" /></th> - <th><Message id="fields.instance.name.label" /></th> + <th><Translate>ID</Translate></th> + <th><Translate>Name</Translate></th> <th /> </tr> </thead> @@ -144,7 +144,7 @@ function EmptyTable(): VNode { <p> <span class="icon is-large"><i class="mdi mdi-emoticon-sad mdi-48px" /></span> </p> - <p><Message id="There is no transfer yet, add more pressing the + sign" /></p> + <p><Translate>There is no transfer yet, add more pressing the + sign</Translate></p> </div> } diff --git a/packages/frontend/src/paths/instance/update/UpdatePage.tsx b/packages/frontend/src/paths/instance/update/UpdatePage.tsx @@ -20,7 +20,6 @@ */ import { h, VNode } from "preact"; -import { Message } from "preact-messages"; import { useState } from "preact/hooks"; import * as yup from 'yup'; import { FormProvider, FormErrors } from "../../../components/form/FormProvider"; @@ -30,8 +29,9 @@ import { InputDuration } from "../../../components/form/InputDuration"; import { InputGroup } from "../../../components/form/InputGroup"; import { InputPayto } from "../../../components/form/InputPayto"; import { InputSecured } from "../../../components/form/InputSecured"; -import { useInstanceContext } from "../../../context/backend"; +import { useInstanceContext } from "../../../context/instance"; import { MerchantBackend } from "../../../declaration"; +import { Translate, useTranslator } from "../../../i18n"; import { InstanceUpdateSchema as schema } from '../../../schemas'; @@ -88,11 +88,13 @@ export function UpdatePage({ onUpdate, selected, onBack }: Props): VNode { onBack() } catch (err) { const errors = err.inner as yup.ValidationError[] - const pathMessages = errors.reduce((prev, cur) => !cur.path ? prev : ({ ...prev, [cur.path]: { type: cur.type, params: cur.params, message: cur.message } }), {}) + const pathMessages = errors.reduce((prev, cur) => !cur.path ? prev : ({ ...prev, [cur.path]: cur.message }), {}) setErrors(pathMessages) } } + const i18n = useTranslator() + return <div> <section class="section is-main-section"> <div class="columns"> @@ -100,59 +102,61 @@ export function UpdatePage({ onUpdate, selected, onBack }: Props): VNode { <div class="column is-four-fifths"> <FormProvider<Entity> errors={errors} object={value} valueHandler={valueHandler} > - <Input<Entity> name="name" /> + <Input<Entity> name="name" label={i18n`Name`} /> - <InputSecured<Entity> name="auth_token" /> + <InputSecured<Entity> name="auth_token" label={i18n`Auth token`} /> - <InputPayto<Entity> name="payto_uris" /> + <InputPayto<Entity> name="payto_uris" label={i18n`Account address`} /> - <InputCurrency<Entity> name="default_max_deposit_fee" /> + <InputCurrency<Entity> name="default_max_deposit_fee" label={i18n`Default max deposit fee`} /> - <InputCurrency<Entity> name="default_max_wire_fee" /> + <InputCurrency<Entity> name="default_max_wire_fee" label={i18n`Default max wire fee`} /> - <Input<Entity> name="default_wire_fee_amortization" inputType="number" /> + <Input<Entity> name="default_wire_fee_amortization" inputType="number" label={i18n`Default wire fee amortization`} /> - <InputGroup name="address"> - <Input name="address.country" /> + <InputGroup name="address" label={i18n`Address`}> + <Input name="address.country" label={i18n`Country`} /> <Input name="address.address_lines" inputType="multiline" + label={i18n`Address`} toStr={(v: string[] | undefined) => !v ? '' : v.join('\n')} fromStr={(v: string) => v.split('\n')} /> - <Input name="address.building_number" /> - <Input name="address.building_name" /> - <Input name="address.street" /> - <Input name="address.post_code" /> - <Input name="address.town_location" /> - <Input name="address.town" /> - <Input name="address.district" /> - <Input name="address.country_subdivision" /> + <Input name="address.building_number" label={i18n`Building number`} /> + <Input name="address.building_name" label={i18n`Building name`} /> + <Input name="address.street" label={i18n`Street`} /> + <Input name="address.post_code" label={i18n`Post code`} /> + <Input name="address.town_location" label={i18n`Town location`} /> + <Input name="address.town" label={i18n`Town`} /> + <Input name="address.district" label={i18n`District`} /> + <Input name="address.country_subdivision" label={i18n`Country subdivision`} /> </InputGroup> - <InputGroup name="jurisdiction"> - <Input name="jurisdiction.country" /> + <InputGroup name="jurisdiction" label={i18n`Jurisdiction`}> + <Input name="jurisdiction.country" label={i18n`Country`} /> <Input name="jurisdiction.address_lines" inputType="multiline" + label={i18n`Address`} toStr={(v: string[] | undefined) => !v ? '' : v.join('\n')} fromStr={(v: string) => v.split('\n')} /> - <Input name="jurisdiction.building_number" /> - <Input name="jurisdiction.building_name" /> - <Input name="jurisdiction.street" /> - <Input name="jurisdiction.post_code" /> - <Input name="jurisdiction.town_location" /> - <Input name="jurisdiction.town" /> - <Input name="jurisdiction.district" /> - <Input name="jurisdiction.country_subdivision" /> + <Input name="jurisdiction.building_number" label={i18n`Building number`} /> + <Input name="jurisdiction.building_name" label={i18n`Building name`} /> + <Input name="jurisdiction.street" label={i18n`Street`} /> + <Input name="jurisdiction.post_code" label={i18n`Post code`} /> + <Input name="jurisdiction.town_location" label={i18n`Town location`} /> + <Input name="jurisdiction.town" label={i18n`Town`} /> + <Input name="jurisdiction.district" label={i18n`District`} /> + <Input name="jurisdiction.country_subdivision" label={i18n`Country subdivision`} /> </InputGroup> - <InputDuration<Entity> name="default_pay_delay" /> + <InputDuration<Entity> name="default_pay_delay" label={i18n`Default pay delay`} /> - <InputDuration<Entity> name="default_wire_transfer_delay" /> + <InputDuration<Entity> name="default_wire_transfer_delay" label={i18n`Default wire transfer delay`} /> </FormProvider> <div class="buttons is-right mt-4"> - <button class="button" onClick={onBack} ><Message id="Cancel" /></button> - <button class="button is-success" onClick={submit} ><Message id="Confirm" /></button> + <button class="button" onClick={onBack} ><Translate>Cancel</Translate></button> + <button class="button is-success" onClick={submit} ><Translate>Confirm</Translate></button> </div> </div> <div class="column" /> diff --git a/packages/frontend/src/utils/functions.ts b/packages/frontend/src/utils/functions.ts @@ -1,42 +0,0 @@ -/* - 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/> - */ - -import { MessageError } from "preact-messages"; - -export function hasKey<O>(obj: O, key: string | number | symbol): key is keyof O { - return key in obj -} - -declare global { - interface Window { MerchantBackoffice: any; } -} - -if (typeof window !== "undefined") { - window.MerchantBackoffice = window.MerchantBackoffice || { - missing_locales: [], - getMissingTranslation: () => Array.from(new Set(window.MerchantBackoffice.missing_locales)).filter(i => i).map(i => `msgid "${i}"\nmsgstr ""\n`).join('\n') - }; -} - -export function onTranslationError(error: MessageError) { - if (typeof window === "undefined") return; - window.MerchantBackoffice.missing_locales = window.MerchantBackoffice.missing_locales.concat(error.path.join()) -} - -export async function copyToClipboard(text:string) { - return navigator.clipboard.writeText(text) -} - diff --git a/packages/frontend/tests/header.test.tsx b/packages/frontend/tests/header.test.tsx @@ -23,7 +23,7 @@ import { h } from 'preact'; import { ProductList } from '../src/components/product/ProductList'; // See: https://github.com/preactjs/enzyme-adapter-preact-pure import { shallow } from 'enzyme'; -import * as backend from '../src/context/backend'; +import * as backend from '../src/context/config'; describe('Initial Test of the Sidebar', () => { beforeEach(() => { diff --git a/packages/frontend/tests/hooks/swr/order-create.test.tsx b/packages/frontend/tests/hooks/swr/order-create.test.tsx @@ -21,8 +21,8 @@ import { renderHook } from '@testing-library/preact-hooks'; import * as axios from 'axios'; -// import { cache, } from "swr"; -import * as ctx from '../../../src/context/backend'; +import * as backend from '../../../src/context/backend'; +import * as instance from '../../../src/context/instance'; import { MerchantBackend } from '../../../src/declaration'; import { useInstanceOrders, useOrderAPI } from '../../../src/hooks/order'; import { simulateBackendResponse } from '../../util' @@ -33,8 +33,8 @@ jest.mock('axios'); describe('order api', () => { beforeEach(() => { - jest.spyOn(ctx, 'useBackendContext').mockImplementation(() => ({ url: 'http://backend', token: 'token' } as any)); - jest.spyOn(ctx, 'useInstanceContext').mockImplementation(() => ({ token: 'token', id: 'default', admin: true, } as any)); + jest.spyOn(backend, 'useBackendContext').mockImplementation(() => ({ url: 'http://backend', token: 'token' } as any)); + jest.spyOn(instance, 'useInstanceContext').mockImplementation(() => ({ token: 'token', id: 'default', admin: true, } as any)); }) it('should not have problem with cache after an creation', async () => { diff --git a/packages/frontend/tests/hooks/swr/order-pagination.test.tsx b/packages/frontend/tests/hooks/swr/order-pagination.test.tsx @@ -21,8 +21,8 @@ import { act, renderHook } from '@testing-library/preact-hooks'; import * as axios from 'axios'; -// import { cache, } from "swr"; -import * as ctx from '../../../src/context/backend'; +import * as backend from '../../../src/context/backend'; +import * as instance from '../../../src/context/instance'; import { MerchantBackend } from '../../../src/declaration'; import { useInstanceOrders } from '../../../src/hooks/order'; import { simulateBackendResponse } from '../../util' @@ -33,8 +33,8 @@ jest.mock('axios'); describe('order pagination', () => { beforeEach(() => { - jest.spyOn(ctx, 'useBackendContext').mockImplementation(() => ({ url: 'http://backend', token: 'token' } as any)); - jest.spyOn(ctx, 'useInstanceContext').mockImplementation(() => ({ token: 'token', id: 'default', admin: true, } as any)); + jest.spyOn(backend, 'useBackendContext').mockImplementation(() => ({ url: 'http://backend', token: 'token' } as any)); + jest.spyOn(instance, 'useInstanceContext').mockImplementation(() => ({ token: 'token', id: 'default', admin: true, } as any)); }) it('should change pagination', async () => { diff --git a/packages/frontend/tests/hooks/swr/product-create.test.tsx b/packages/frontend/tests/hooks/swr/product-create.test.tsx @@ -21,8 +21,8 @@ import { renderHook } from '@testing-library/preact-hooks'; import * as axios from 'axios'; -// import { cache, } from "swr"; -import * as ctx from '../../../src/context/backend'; +import * as backend from '../../../src/context/backend'; +import * as instance from '../../../src/context/instance'; import { MerchantBackend } from '../../../src/declaration'; import { useInstanceProducts, useProductAPI } from '../../../src/hooks/product'; import { simulateBackendResponse } from '../../util' @@ -33,8 +33,8 @@ jest.mock('axios'); describe('product api', () => { beforeEach(() => { - jest.spyOn(ctx, 'useBackendContext').mockImplementation(() => ({ url: 'http://backend', token: 'token' } as any)); - jest.spyOn(ctx, 'useInstanceContext').mockImplementation(() => ({ token: 'token', id: 'default', admin: true, } as any)); + jest.spyOn(backend, 'useBackendContext').mockImplementation(() => ({ url: 'http://backend', token: 'token' } as any)); + jest.spyOn(instance, 'useInstanceContext').mockImplementation(() => ({ token: 'token', id: 'default', admin: true, } as any)); }) it('should not have problem with cache after an creation', async () => { diff --git a/packages/frontend/tests/hooks/swr/product-delete.test.tsx b/packages/frontend/tests/hooks/swr/product-delete.test.tsx @@ -20,7 +20,8 @@ */ import { renderHook } from '@testing-library/preact-hooks'; -import * as ctx from '../../../src/context/backend'; +import * as backend from '../../../src/context/backend'; +import * as instance from '../../../src/context/instance'; import { MerchantBackend } from '../../../src/declaration'; import { useInstanceProducts, useProductAPI } from '../../../src/hooks/product'; import { simulateBackendResponse } from '../../util' @@ -35,8 +36,8 @@ axios.default describe('product api', () => { beforeEach(() => { - jest.spyOn(ctx, 'useBackendContext').mockImplementation(() => ({ url: 'http://backend', token: 'token' } as any)); - jest.spyOn(ctx, 'useInstanceContext').mockImplementation(() => ({ token: 'token', id: 'default', admin: true, } as any)); + jest.spyOn(backend, 'useBackendContext').mockImplementation(() => ({ url: 'http://backend', token: 'token' } as any)); + jest.spyOn(instance, 'useInstanceContext').mockImplementation(() => ({ token: 'token', id: 'default', admin: true, } as any)); // console.log("CLEAR") }) diff --git a/packages/frontend/tests/hooks/swr/product-details-update.test.tsx b/packages/frontend/tests/hooks/swr/product-details-update.test.tsx @@ -21,9 +21,10 @@ import { renderHook } from '@testing-library/preact-hooks'; import * as axios from 'axios'; -import * as ctx from '../../../src/context/backend'; +import * as backend from '../../../src/context/backend'; +import * as instance from '../../../src/context/instance'; import { MerchantBackend } from '../../../src/declaration'; -import { useInstanceProducts, useProductAPI, useProductDetails } from '../../../src/hooks/product'; +import { useProductAPI, useProductDetails } from '../../../src/hooks/product'; import { simulateBackendResponse } from '../../util' @@ -32,9 +33,8 @@ jest.mock('axios'); describe('product api', () => { beforeEach(() => { - jest.spyOn(ctx, 'useBackendContext').mockImplementation(() => ({ url: 'http://backend', token: 'token' } as any)); - jest.spyOn(ctx, 'useInstanceContext').mockImplementation(() => ({ token: 'token', id: 'default', admin: true, } as any)); - // console.log("CLEAR") + jest.spyOn(backend, 'useBackendContext').mockImplementation(() => ({ url: 'http://backend', token: 'token' } as any)); + jest.spyOn(instance, 'useInstanceContext').mockImplementation(() => ({ token: 'token', id: 'default', admin: true, } as any)); }) it('should not have problem with cache after an update', async () => { diff --git a/packages/frontend/tests/hooks/swr/product-update.test.tsx b/packages/frontend/tests/hooks/swr/product-update.test.tsx @@ -21,7 +21,8 @@ import { renderHook } from '@testing-library/preact-hooks'; import * as axios from 'axios'; -import * as ctx from '../../../src/context/backend'; +import * as backend from '../../../src/context/backend'; +import * as instance from '../../../src/context/instance'; import { MerchantBackend } from '../../../src/declaration'; import { useInstanceProducts, useProductAPI } from '../../../src/hooks/product'; import { simulateBackendResponse } from '../../util' @@ -32,8 +33,8 @@ jest.mock('axios'); describe('product api', () => { beforeEach(() => { - jest.spyOn(ctx, 'useBackendContext').mockImplementation(() => ({ url: 'http://backend', token: 'token' } as any)); - jest.spyOn(ctx, 'useInstanceContext').mockImplementation(() => ({ token: 'token', id: 'default', admin: true, } as any)); + jest.spyOn(backend, 'useBackendContext').mockImplementation(() => ({ url: 'http://backend', token: 'token' } as any)); + jest.spyOn(instance, 'useInstanceContext').mockImplementation(() => ({ token: 'token', id: 'default', admin: true, } as any)); // console.log("CLEAR") }) diff --git a/packages/frontend/tests/stories.test.tsx b/packages/frontend/tests/stories.test.tsx @@ -20,7 +20,7 @@ */ import { mount } from 'enzyme'; import { h } from 'preact'; -import * as ctx from '../src/context/backend'; +import * as ctx from '../src/context/config'; import fs from 'fs'; diff --git a/packages/frontend/tsconfig.json b/packages/frontend/tsconfig.json @@ -8,6 +8,7 @@ // "checkJs": true, /* Report errors in .js files. */ "jsx": "react", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ "jsxFactory": "h", /* Specify the JSX factory function to use when targeting react JSX emit, e.g. React.createElement or h. */ + "jsxFragmentFactory": "Fragment", // https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-0.html#custom-jsx-factories // "declaration": true, /* Generates corresponding '.d.ts' file. */ // "sourceMap": true, /* Generates corresponding '.map' file. */ // "outFile": "./", /* Concatenate and emit output to single file. */ diff --git a/packages/preact-messages/.gitignore b/packages/preact-messages/.gitignore @@ -1,2 +0,0 @@ -/example/dist/ -/lib/ diff --git a/packages/preact-messages/CHANGELOG.md b/packages/preact-messages/CHANGELOG.md @@ -1,16 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -# 1.0.0-beta.1 (2020-11-29) - - -### Features - -* Add @messageformat/react (was react-message-context) ([#292](https://github.com/messageformat/messageformat/issues/292)) ([9089f0a](https://github.com/messageformat/messageformat/commit/9089f0ad52f21f8ab6c356fd4f51bb140dc36855)) - - -# 0.6.2 and earlier - -For earlier changes, see https://github.com/eemeli/react-message-context/releases diff --git a/packages/preact-messages/LICENSE b/packages/preact-messages/LICENSE @@ -1,20 +0,0 @@ -Copyright OpenJS Foundation and contributors, https://openjsf.org/ - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/preact-messages/README.md b/packages/preact-messages/README.md @@ -1,126 +0,0 @@ -# @messageformat/react - -An efficient React front-end for message formatting libraries. -Designed in particular for use with [messageformat], but will work with any messages. -Provides the best possible API for a front-end developer, without making the back end any more difficult than it needs to be either. -Should add at most about 1kB to your compiled & minified bundle size. - -This package was previously named [react-message-context](https://www.npmjs.com/package/react-message-context). - -[messageformat]: https://messageformat.github.io - -## Installation - -``` -npm install @messageformat/react -``` - -The library has React 16.8 or later as a peer dependency. -It is published as an **ES module** only, which should work directly with almost all tools and environments that support modern development targeting browser environments. -For tools such as Jest that define their own import methods, you may need to add something like `transformIgnorePatterns: ['node_modules/(?!@messageformat/react)']` to your configuration. - -## [API Documentation] - -- [`<MessageProvider messages [locale] [onError] [pathSep]>`](http://messageformat.github.io/messageformat/api/react.messageprovider/) -- [`<Message id [locale] [props] [...msgProps]>`](http://messageformat.github.io/messageformat/api/react.message/) -- [`useLocales()`](http://messageformat.github.io/messageformat/api/react.uselocales/) -- [`useMessage(id, [params], [locale])`](http://messageformat.github.io/messageformat/api/react.usemessage/) -- [`useMessageGetter(rootId, [{ baseParams, locale }])`](http://messageformat.github.io/messageformat/api/react.usemessagegetter/) - -## Usage Examples - -In addition to the examples included below and in the [API documentation], see the [example] for a simple, but fully functional example of using this library along with [@messageformat/core] and [@messageformat/loader] to handle localized messages, with dynamic loading of non-default locales. - -[api documentation]: http://messageformat.github.io/messageformat/api/react/ -[example]: https://github.com/messageformat/messageformat/tree/master/packages/react/example -[@messageformat/core]: https://www.npmjs.com/package/@messageformat/core -[@messageformat/loader]: https://www.npmjs.com/package/@messageformat/loader - ---- - -Within a `MessageProvider`, access to the messages is possible using either the `Message` component, or via custom hooks such as `useMessageGetter`: - -```js -import React from 'preact'; -import { - Message, - MessageProvider, - useMessageGetter -} from '@messageformat/react'; - -const messages = { - message: 'Your message is important', - answers: { - sixByNine: ({ base }) => (6 * 9).toString(base), - universe: 42 - } -}; - -function Equality() { - const getAnswer = useMessageGetter('answers'); - const foo = getAnswer('sixByNine', { base: 13 }); - const bar = getAnswer('universe'); - return `${foo} and ${bar} are equal`; -} - -export const Example = () => ( - <MessageProvider messages={messages}> - <ul> - <li> - <Message id="message" /> - </li> - <li> - <Equality /> - </li> - </ul> - </MessageProvider> -); - -// Will render as: -// - Your message is important -// - 42 and 42 are equal -``` - ---- - -Using MessageProviders within each other allows for multiple locales and namespaces: - -```jsx -import React from 'preact'; -import { Message, MessageProvider } from '@messageformat/react'; - -export const Example = () => ( - <MessageProvider locale="en" messages={{ foo: 'FOO', qux: 'QUX' }}> - <MessageProvider locale="fi" messages={{ foo: 'FÖÖ', bar: 'BÄR' }}> - <ul> - <li> - <Message id="foo" /> - </li> - <li> - <Message id="foo" locale="en" /> - </li> - <li> - <Message id="bar" /> - </li> - <li> - <Message id="bar" locale="en" /> - </li> - <li> - <Message id="qux" /> - </li> - <li> - <Message id="quux">xyzzy</Message> - </li> - </ul> - </MessageProvider> - </MessageProvider> -); - -// Will render as: -// - FÖÖ -// - FOO -// - BÄR -// - bar (uses fallback to key) -// - QUX (uses fallback to "en" locale) -// - xyzzy (uses fallback to child node) -``` diff --git a/packages/preact-messages/package.json b/packages/preact-messages/package.json @@ -1,44 +0,0 @@ -{ - "name": "preact-messages", - "version": "1.0.0-beta.1", - "description": "PReact hooks and other bindings for messages", - "keywords": [ - "i18n", - "preact", - "context", - "messages", - "messageformat", - "provider" - ], - "contributors": [ - "Eemeli Aro <eemeli@gmail.com>" - ], - "license": "MIT", - "homepage": "http://messageformat.github.io/messageformat/api/react/", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "exports": { - ".": "./lib/index.js", - "./package.json": "./package.json" - }, - "files": [ - "lib/" - ], - "sideEffects": false, - "scripts": { - "build": "tsc", - "compile": "tsc", - "clean": "rimraf lib", - "extract-api": "api-extractor run --local --verbose" - }, - "peerDependencies": { - "preact": ">=10.3.0" - }, - "dependencies": { - "preact": "^10.5.13", - "typescript": "^4.2.3" - }, - "devDependencies": { - "rimraf": "^3.0.2" - } -} diff --git a/packages/preact-messages/src/MessageProvider.ts b/packages/preact-messages/src/MessageProvider.ts @@ -1,183 +0,0 @@ -import { createElement } from 'preact'; -import { useContext, useMemo } from 'preact/hooks'; -import { MessageContext, MessageObject, defaultValue } from './message-context'; -// import { MessageProviderProps, getPathSep, getLocales, getMessages, getOnError } from './message-provider'; -import { MessageError, ErrorCode, errorMessages } from './message-error'; - -/** - * `<MessageProvider messages [locale] [merge] [onError] [pathSep]>` - * - * Makes the messages available for its descendants via a React Context. - * To support multiple locales and/or namespaces, MessageProviders may be used within each other, merging each provider's messages with those of its parents. - * The locale preference order is also set similarly, from nearest to furthest. - * - * @public - * - * @example - * ```js - * import React from 'preact' - * import { Message, MessageProvider } from '@messageformat/react' - * - * const messages = { example: { key: 'Your message here' } } - * const extended = { other: { key: 'Another message' } } - * - * const Example = () => ( - * <span> - * <Message id={['example', 'key']} /> - * {' | '} - * <Message id="other/key" /> - * </span> - * ) // 'Your message here | Another message' - * - * export const App = () => ( - * <MessageProvider messages={messages} pathSep="/"> - * <MessageProvider messages={extended}> - * <Example /> - * </MessageProvider> - * </MessageProvider> - * ) - * ``` - */ - -export function MessageProvider(props: MessageProviderProps) { - const { - children, - context: propContext, - debug, - locale = '', - merge, - messages, - onError, - pathSep - } = props; - let parent = useContext(MessageContext); - if (propContext) - parent = propContext; - else if (propContext === null) - parent = defaultValue; - const value: MessageContext = useMemo(() => { - const ps = getPathSep(parent, pathSep); - return { - locales: getLocales(parent, locale), - merge: merge || parent.merge, - messages: getMessages(parent, locale, messages), - onError: getOnError(parent, ps, onError, debug), - pathSep: ps - }; - }, [parent, locale, merge, messages, pathSep]); - return createElement(MessageContext.Provider, { value } as any, children); -} - - - -/** @public */ -export interface MessageProviderProps { - children: any; - - /** - * A hierarchical object containing the messages as boolean, number, string or function values. - */ - messages: MessageObject; - context?: MessageContext; - - /** @deprecated Use onError instead */ - debug?: 'error' | 'warn' | ((msg: string) => any); - - /** - * A key for the locale of the given messages. - * If uset, will inherit the locale from the parent context, or ultimately use en empty string. - */ - locale?: string; - - /** - * By default, top-level namespaces defined in a child `MessageProvider` overwrite those defined in a parent. - * Set this to {@link https://lodash.com/docs/#merge | _.merge} or some other function with the same arguments as - * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign | Object.assign} to allow for deep merges. - */ - merge?: MessageContext['merge']; - - /** - * What to do on errors; most often called if a message is not found. - * - * - `"silent"`: Ignore the error; use the message's id as the replacement message. - * - * - `"error"`: Throw the error. - * - * - `"warn"` (default): Print a warning in the console and use the message's id as the replacement message. - * - * - `(error) => any`: A custom function that is called with an `Error` object with `code: string` and `path: string[]` fields set. - * The return falue is used as the replacement message. - */ - onError?: 'error' | 'silent' | 'warn' | ((error: MessageError) => any); - - /** - * By default, `.` in a `<Message id>` splits the path into parts, such that e.g. `'a.b'` is equivalent to `['a', 'b']`. - * Use this option to customize or disable this behaviour (by setting it to `null`). - */ - pathSep?: string; -} - -export function getOnError( - parent: MessageContext, - pathSep: string | null, - onError: MessageProviderProps['onError'], - debug: MessageProviderProps['debug'] -) { - const asId = (path: string[]) => path.join(pathSep || ','); - function msgError(path: string[], code: ErrorCode) { - throw new MessageError(path, code, asId); - } - function msgWarning(path: string[], code: ErrorCode) { - console.warn(errorMessages[code], path); - return asId(path); - } - - if (onError === undefined) { - // debug is deprecated, will be removed later - if (typeof debug === 'function') - return (path: string[], code: ErrorCode) => - debug(`${errorMessages[code]}: ${asId(path)}`); - onError = debug; - } - - switch (onError) { - case 'silent': - return asId; - case 'error': - return msgError; - case 'warn': - return msgWarning; - default: - if (typeof onError === 'function') { - const _onError = onError; - return (path: string[], code: ErrorCode) => - _onError(new MessageError(path, code, asId)); - } - return parent.onError || msgWarning; - } -} - -export function getLocales({ locales }: MessageContext, locale: string) { - const fallback = locales.filter(fb => fb !== locale); - return [locale].concat(fallback); -} - -export function getMessages( - { merge, messages }: MessageContext, - locale: string, - lcMessages: MessageObject -) { - const res = Object.assign({}, messages); - const prev = res[locale]; - res[locale] = - prev && typeof prev === 'object' ? merge({}, prev, lcMessages) : lcMessages; - return res; -} - -export function getPathSep(context: MessageContext, pathSep?: string | null) { - return pathSep === null || typeof pathSep === 'string' - ? pathSep - : context.pathSep; -} - - diff --git a/packages/preact-messages/src/declarations.d.ts b/packages/preact-messages/src/declarations.d.ts @@ -1,3 +0,0 @@ -export module "" { - -} -\ No newline at end of file diff --git a/packages/preact-messages/src/get-message.ts b/packages/preact-messages/src/get-message.ts @@ -1,87 +0,0 @@ -import { - MessageContext, - MessageObject, - MessageValue -} from './message-context.js'; - -function getIn(messages: MessageValue | MessageObject, path: string[]) { - if (messages) { - for (let i = 0; i < path.length; ++i) { - if (typeof messages !== 'object') return undefined; - messages = messages[path[i]]; - if (messages === undefined) return undefined; - } - } - return messages; -} - -export function getPath(id?: string | string[], pathSep?: string | null) { - if (!id) return []; - if (Array.isArray(id)) return id; - return pathSep ? id.split(pathSep) : [id]; -} - -/** - * Given a `MessageContext` instance, fetches an entry from the messages object of the current or given locale. - * The returned value will be `undefined` if not found, or otherwise exactly as set in the `MessageProvider` props. - * - * @public - * @param id - The key or key path of the message or message object. - * If empty or `[]`, matches the root of the messages object - * @param locale - If set, overrides the current locale precedence as set by parent MessageProviders. - */ -export function getMessage( - context: MessageContext, - id?: string | string[], - locale?: string | string[] -) { - const { locales, messages, onError, pathSep } = context; - const lca = - locale == null ? locales : Array.isArray(locale) ? locale : [locale]; - const path = getPath(id, pathSep); - for (let i = 0; i < lca.length; ++i) { - const lc = lca[i]; - const msg = getIn(messages[lc], path); - if (msg !== undefined) return msg; - } - return onError ? onError(path, 'ENOMSG') : undefined; -} - -/** - * @param id - Message identifier; extends the path set by `rootId` - * @param params - Parameters for a function message - */ -export interface MessageGetterOptions { - baseParams?: any; - locale?: string | string[]; -} - -/** - * Given a `MessageContext` instance, returns a message getter function, which may have a preset root id path, locale, and/or base parameters for message functions. - * - * The returned function takes two parameters `(msgId, msgParams)`, which will extend any values set by the hook's arguments. - * - * @public - * @param context - The `MessageContext` instance - * @param rootId - The key or key path of the message or message object. - * If empty or `[]`, matches the root of the messages object - * @param options - If `baseParams` is set, message function parameters will be assumed to always be an object, with these values initially set. - * `locale` overrides the current locale precedence as set by parent MessageProviders. - */ -export function getMessageGetter( - context: MessageContext, - rootId?: string | string[], - { baseParams, locale }: MessageGetterOptions = {} -) { - const { pathSep } = context; - const pathPrefix = getPath(rootId, pathSep); - return function message(id?: string | string[], params?: any) { - const path = pathPrefix.concat(getPath(id, pathSep)); - const msg = getMessage(context, path, locale); - if (typeof msg !== 'function') return msg; - const msgParams = baseParams - ? Object.assign({}, baseParams, params) - : params; - return msg(msgParams); - }; -} diff --git a/packages/preact-messages/src/index.ts b/packages/preact-messages/src/index.ts @@ -1,32 +0,0 @@ -/** - * An efficient React front-end for message formatting - * - * @packageDocumentation - * @remarks - * Designed in particular for use with {@link https://messageformat.github.io | messageformat}, but will work with any messages. - * Provides the best possible API for a front-end developer, without making the back end any more difficult than it needs to be either. - * Should add at most about 1kB to your compiled & minified bundle size. - * - * @example - * ```js - * import { - * MessageContext, - * MessageProvider, - * Message, - * getMessage, - * getMessageGetter, - * useLocales, - * useMessage, - * useMessageGetter - * } from '@messageformat/react' - * ``` - */ -export { getMessage, getMessageGetter } from './get-message'; -export { Message, MessageProps } from './message'; -export { MessageContext, MessageObject, MessageValue } from './message-context'; -export { MessageError } from './message-error'; -export { MessageProvider } from './MessageProvider'; -export { useLocales } from './use-locales'; -export { useMessage } from './use-message'; -export { useMessageGetter } from './use-message-getter'; -export { useMessageTemplate } from './use-message-template'; diff --git a/packages/preact-messages/src/message-context.ts b/packages/preact-messages/src/message-context.ts @@ -1,72 +0,0 @@ -// @ts-ignore - https://github.com/microsoft/rushstack/issues/1050 -import { createContext } from 'preact'; -import { ErrorCode } from './message-error'; - -/** @internal */ -export type MessageValue = string | number | boolean | ((props: any) => any); - -/** @internal */ -export interface MessageObject { - [key: string]: MessageValue | MessageObject; -} - -/** @public */ -export interface MessageContext { - locales: string[]; - merge: (target: MessageObject, ...sources: MessageObject[]) => MessageObject; - messages: MessageObject; - - /** Always defined in MessageProvider children */ - onError?: (path: string[], code: ErrorCode) => any; - pathSep: string | null; -} - -export const defaultValue: MessageContext = { - locales: [], - merge: Object.assign, - messages: {}, - pathSep: '.' -}; - -/** - * The context object used internally by the library. - * Probably only useful with `Class.contextType` or for building custom hooks. - * - * @public - * - * @example - * ```js - * import React, { Component } from 'preact' - * import { - * getMessage, - * getMessageGetter, - * MessageContext, - * MessageProvider - * } from '@messageformat/react' - * - * const messages = { - * example: { key: 'Your message here' }, - * other: { key: 'Another message' } - * } - * - * class Example extends Component { - * render() { - * const message = getMessage(this.context, 'example.key') - * const otherMsg = getMessageGetter(this.context, 'other') - * return ( - * <span> - * {message} | {otherMsg('key')} - * </span> - * ) // 'Your message here | Another message' - * } - * } - * Example.contextType = MessageContext - * - * export const App = () => ( - * <MessageProvider messages={messages}> - * <Example /> - * </MessageProvider> - * ) - * ``` - */ -export const MessageContext = createContext(defaultValue); diff --git a/packages/preact-messages/src/message-error.ts b/packages/preact-messages/src/message-error.ts @@ -1,22 +0,0 @@ -export const errorMessages = { - EBADMSG: 'Message with unexpected object value', - ENOMSG: 'Message not found' -}; - -export type ErrorCode = keyof typeof errorMessages; - -/** @internal */ -export class MessageError extends Error { - code: ErrorCode; - path: string[]; - - constructor( - path: string[], - code: ErrorCode, - asId: (path: string[]) => string - ) { - super(`${errorMessages[code]}: ${asId(path)}`); - this.code = code; - this.path = path; - } -} diff --git a/packages/preact-messages/src/message.ts b/packages/preact-messages/src/message.ts @@ -1,89 +0,0 @@ -import { useContext } from 'preact/hooks'; -import { getMessage, getPath } from './get-message'; -import { MessageContext } from './message-context'; - -/** @public */ -export interface MessageProps { - /** - * If a function, will be called with the found message. - * In this case, `params` will be ignored and `id` is optional. - * If some other type of non-empty renderable node, it will be used as a fallback value if the message is not found. - */ - children?: any; - - /** The key or key path of the message. */ - id?: string | string[]; - - /** If set, overrides the `locale` of the nearest MessageProvider. */ - locale?: string | string[]; - - /** - * Parameters to pass to function messages as their first and only argument. - * `params` will override `msgParams`, to allow for data keys such as `key` and `locale`. - */ - params?: any; - - /** - * Parameters to pass to function messages as their first and only argument. - * Overriden by `params`, to allow for data keys such as `key` and `locale`. - */ - [msgParamKey: string]: any; -} - -// Just using { foo, ...bar } adds a polyfill with a boilerplate copyright -// statement that would add 50% to the minified size of the whole library. -function rest(props: { [key: string]: any }, exclude: string[]) { - const t: typeof props = {}; - for (const k of Object.keys(props)) if (!exclude.includes(k)) t[k] = props[k]; - return t; -} - -/** - * `<Message id [locale] [params] [...msgParams]>` - * - * The value of a message. - * May also be used with a render prop: `<Message id={id}>{msg => {...}}</Message>`. - * - * @public - * - * @example - * ```js - * import React from 'preact' - * import { Message, MessageProvider } from '@messageformat/react' - * - * const messages = { example: { key: ({ thing }) => `Your ${thing} here` } } - * - * const Example = () => ( - * <span> - * <Message id="example.key" thing="message" /> - * </span> - * ) // 'Your message here' - * - * export const App = () => ( - * <MessageProvider messages={messages}> - * <Example /> - * </MessageProvider> - * ) - * ``` - */ -export function Message(props: MessageProps) { - const { children, id, locale, params } = props; - const msgParams = rest(props, ['children', 'id', 'locale', 'params']); - let context = useContext(MessageContext); - let fallback = false; - if (children && typeof children !== 'function') - context = Object.assign({}, context, { onError: () => (fallback = true) }); - const msg = getMessage(context, id, locale); - if (fallback) return children; - if (typeof children === 'function') return children(msg); - switch (typeof msg) { - case 'function': - return msg(Object.assign(msgParams, params)); - case 'boolean': - return String(msg); - case 'object': - if (msg && !Array.isArray(msg)) - return context.onError ? context.onError(getPath(id), 'EBADMSG') : null; - } - return msg || null; -} diff --git a/packages/preact-messages/src/use-locales.ts b/packages/preact-messages/src/use-locales.ts @@ -1,44 +0,0 @@ -import { useContext } from 'preact/hooks'; -import { MessageContext } from './message-context'; - -/** - * A custom React hook providing the current locales as an array of string identifiers, with earlier entries taking precedence over latter ones. - * Undefined locales are identified by an empty string `''`. - * - * @public - * - * @example - * ```js - * import React from 'preact' - * import { MessageProvider, useLocales } from '@messageformat/react' - * - * <MessageProvider locale="en" messages={ { foo: 'FOO' } }> - * {() => useLocales().join(',') // 'en' - * } - * <MessageProvider locale="fi" messages={ { foo: 'FÖÖ' } }> - * {() => useLocales().join(',') // 'fi,en' - * } - * </MessageProvider> - * </MessageProvider> - * ``` - * - * @example - * ```js - * import React, { Component } from 'preact' - * import { MessageContext, MessageProvider, useLocales } from '@messageformat/react' - * - * // Within a class component, locales are available via the context object - * class Foo extends Component { - * static contextType = MessageContext - * declare context: React.ContextType<typeof MessageContext> // TS - * render() { - * const { locales } = this.context - * return locales.join(',') - * } - * } - * ``` - */ -export function useLocales() { - const { locales } = useContext(MessageContext); - return locales.slice(); -} diff --git a/packages/preact-messages/src/use-message-getter.ts b/packages/preact-messages/src/use-message-getter.ts @@ -1,47 +0,0 @@ -import { useContext } from 'preact/hooks'; -import { getMessageGetter, MessageGetterOptions } from './get-message'; -import { MessageContext } from './message-context'; - -/** - * A custom [React hook] providing a message getter function, which may have a preset root id path, locale, and/or base parameters for message functions. - * - * The returned function takes two parameters `(msgId, msgParams)`, which will extend any values set by the hook's arguments. - * - * @public - * @param rootId - The key or key path of the message or message object. - * If empty or `[]`, matches the root of the messages object - * @param options - If `baseParams` is set, message function parameters will be assumed to always be an object, with these values initially set. - * `locale` overrides the current locale precedence as set by parent MessageProviders. - * - * @example - * ```js - * import React from 'preact' - * import { MessageProvider, useMessageGetter } from '@messageformat/react' - * - * const messages = { - * example: { - * funMsg: ({ thing }) => `Your ${thing} here`, - * thing: 'message' - * } - * } - * - * function Example() { - * const getMsg = useMessageGetter('example') - * const thing = getMsg('thing') // 'message' - * return getMsg('funMsg', { thing }) // 'Your message here' - * } - * - * export const App = () => ( - * <MessageProvider messages={messages}> - * <Example /> - * </MessageProvider> - * ) - * ``` - */ -export function useMessageGetter( - rootId: string | string[], - opt?: MessageGetterOptions -) { - const context = useContext(MessageContext); - return getMessageGetter(context, rootId, opt); -} diff --git a/packages/preact-messages/src/use-message-template.ts b/packages/preact-messages/src/use-message-template.ts @@ -1,31 +0,0 @@ -import { useContext } from 'preact/hooks'; -import { MessageGetterOptions, getPath, getMessage } from './get-message'; -import { MessageContext } from './message-context'; - - -export function useMessageTemplate( - rootId?: string | string[], - opt?: MessageGetterOptions -) { - const context = useContext(MessageContext); - return getMessageGetter(context, rootId, opt); -} - -export function getMessageGetter( - context: MessageContext, - rootId?: string | string[], - { baseParams, locale }: MessageGetterOptions = {} -) { - const { pathSep } = context; - const pathPrefix = getPath(rootId, pathSep); - return function message(id?: TemplateStringsArray, ...params: any) { - const path = pathPrefix.concat(getPath(id?.join('%s'), pathSep)); - const msg = getMessage(context, path, locale); - if (typeof msg !== 'function') return msg; - const msgParams = baseParams - ? Object.assign({}, baseParams, params) - : params; - return msg(msgParams); - }; -} - diff --git a/packages/preact-messages/src/use-message.ts b/packages/preact-messages/src/use-message.ts @@ -1,58 +0,0 @@ -import { useContext } from 'preact/hooks'; -import { getMessage } from './get-message'; -import { MessageContext } from './message-context'; - -/** - * A custom React hook providing an entry from the messages object of the current or given locale. - * The returned value will be `undefined` if not found. - * - * If the identified message value is a function, the returned value will be the result of calling it with a single argument `params`, or `{}` if empty. - * Otherwise the value set in the `MessageProvider` props will be returned directly. - * - * @public - * @param id - The key or key path of the message or message object. - * If empty or `[]`, matches the root of the messages object - * @param params - Argument to use if the identified message is a function - * @param locale - If set, overrides the current locale precedence as set by parent MessageProviders. - * - * @example - * ```js - * import React from 'preact' - * import { MessageProvider, useLocales, useMessage } from '@messageformat/react' - * - * const en = { example: { key: 'Your message here' } } - * const fi = { example: { key: 'Lisää viestisi tähän' } } - * - * // Intl.ListFormat may require a polyfill, such as intl-list-format - * function Example() { - * const locales = useLocales() // ['fi', 'en'] - * const lfOpt = { style: 'long', type: 'conjunction' } - * const lf = new Intl.ListFormat(locales, lfOpt) - * const lcMsg = lf.format(locales.map(lc => JSON.stringify(lc))) // '"fi" ja "en"' - * const keyMsg = useMessage('example.key') // 'Lisää viestisi tähän' - * return ( - * <article> - * <h1>{lcMsg}</h1> - * <p>{keyMsg}</p> - * </article> - * ) - * } - * - * export const App = () => ( - * <MessageProvider locale="en" messages={en}> - * <MessageProvider locale="fi" messages={fi}> - * <Example /> - * </MessageProvider> - * </MessageProvider> - * ) - * ``` - */ -export function useMessage( - id: string | string[], - params?: any, - locale?: string | string[] -) { - const context = useContext(MessageContext); - const msg = getMessage(context, id, locale); - return typeof msg === 'function' ? msg(params == null ? {} : params) : msg; -} diff --git a/packages/preact-messages/tsconfig.json b/packages/preact-messages/tsconfig.json @@ -1,60 +0,0 @@ -{ - "compilerOptions": { - /* Basic Options */ - "target": "ES5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */ - "module": "ESNext", /* Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ - // "lib": [], /* Specify library files to be included in the compilation: */ - "allowJs": true, /* Allow javascript files to be compiled. */ - // "checkJs": true, /* Report errors in .js files. */ - "jsx": "react", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ - "jsxFactory": "h", /* Specify the JSX factory function to use when targeting react JSX emit, e.g. React.createElement or h. */ - "declaration": true, /* Generates corresponding '.d.ts' file. */ - // "sourceMap": true, /* Generates corresponding '.map' file. */ - // "outFile": "./", /* Concatenate and emit output to single file. */ - "outDir": "./lib/", /* Redirect output structure to the directory. */ - // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ - // "removeComments": true, /* Do not emit comments to output. */ - "noEmit": false, /* Do not emit outputs. */ - // "importHelpers": true, /* Import emit helpers from 'tslib'. */ - // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ - // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ - - /* Strict Type-Checking Options */ - "strict": true, /* Enable all strict type-checking options. */ - // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* Enable strict null checks. */ - // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ - // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ - - /* Additional Checks */ - // "noUnusedLocals": true, /* Report errors on unused locals. */ - // "noUnusedParameters": true, /* Report errors on unused parameters. */ - // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ - // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ - - /* Module Resolution Options */ - "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ - "esModuleInterop": true, /* */ - // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ - // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ - // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ - // "typeRoots": [], /* List of folders to include type definitions from. */ - // "types": [], /* Type declaration files to be included in compilation. */ - // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ - // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ - - /* Source Map Options */ - // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ - // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ - // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ - - /* Experimental Options */ - // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ - // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ - - /* Advanced Options */ - "skipLibCheck": true /* Skip type checking of declaration files. */ - }, - "include": ["src/**/*", "tests/**/*"] -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml @@ -10,6 +10,8 @@ importers: '@babel/core': ^7.13.16 '@babel/plugin-transform-react-jsx-source': ^7.12.13 '@creativebulma/bulma-tooltip': ^1.2.0 + '@gnu-taler/pogen': ^0.0.5 + '@gnu-taler/taler-util': ^0.8.2 '@storybook/addon-a11y': ^6.2.9 '@storybook/addon-actions': ^6.2.9 '@storybook/addon-essentials': ^6.2.9 @@ -24,7 +26,6 @@ importers: '@types/mocha': ^8.2.2 '@typescript-eslint/eslint-plugin': ^4.22.0 '@typescript-eslint/parser': ^4.22.0 - ava: ^3.15.0 axios: ^0.21.1 babel-loader: ^8.2.2 base64-inline-loader: ^1.1.1 @@ -47,14 +48,13 @@ importers: html-webpack-inline-source-plugin: 0.0.10 html-webpack-skip-assets-plugin: ^1.0.1 inline-chunk-html-plugin: ^1.1.1 + jed: ^1.1.1 jest: ^26.6.3 jest-preset-preact: ^4.0.2 - messageformat: ^2.3.0 - messageformat-po-loader: ^0.3.0 node-sass: ^5.0.0 + po2json: ^0.4.5 preact: ^10.5.13 preact-cli: ^3.0.5 - preact-messages: workspace:* preact-render-to-json: ^3.6.6 preact-render-to-string: ^5.1.19 preact-router: ^3.2.1 @@ -67,12 +67,12 @@ importers: typescript: ^4.2.4 yup: ^0.32.9 dependencies: + '@gnu-taler/taler-util': 0.8.2 axios: 0.21.1 date-fns: 2.21.1 history: 4.10.1 - messageformat: 2.3.0 + jed: 1.1.1 preact: 10.5.13 - preact-messages: link:../preact-messages preact-router: 3.2.1_preact@10.5.13 swr: 0.5.5 yup: 0.32.9 @@ -80,6 +80,7 @@ importers: '@babel/core': 7.13.16 '@babel/plugin-transform-react-jsx-source': 7.12.13_@babel+core@7.13.16 '@creativebulma/bulma-tooltip': 1.2.0 + '@gnu-taler/pogen': 0.0.5 '@storybook/addon-a11y': 6.2.9 '@storybook/addon-actions': 6.2.9 '@storybook/addon-essentials': 6.2.9_472ba1443a3a7dfb9d5f96aaff5418de @@ -94,7 +95,6 @@ importers: '@types/mocha': 8.2.2 '@typescript-eslint/eslint-plugin': 4.22.0_e3b52a83531895e7febd6ecd5ba813eb '@typescript-eslint/parser': 4.22.0_eslint@7.25.0+typescript@4.2.4 - ava: 3.15.0 babel-loader: 8.2.2_@babel+core@7.13.16 base64-inline-loader: 1.1.1 bulma: 0.9.2 @@ -116,8 +116,8 @@ importers: inline-chunk-html-plugin: 1.1.1 jest: 26.6.3 jest-preset-preact: 4.0.2_669f037bdb6c36f0a67e918c516dafdd - messageformat-po-loader: 0.3.0_messageformat@2.3.0 node-sass: 5.0.0 + po2json: 0.4.5 preact-cli: 3.0.5_c069246dc1d99535ac277c76f8ef56e0 preact-render-to-json: 3.6.6_preact@10.5.13 preact-render-to-string: 5.1.19_preact@10.5.13 @@ -128,17 +128,6 @@ importers: typedoc: 0.20.36_typescript@4.2.4 typescript: 4.2.4 - packages/preact-messages: - specifiers: - preact: ^10.5.13 - rimraf: ^3.0.2 - typescript: ^4.2.3 - dependencies: - preact: 10.5.13 - typescript: 4.2.3 - devDependencies: - rimraf: 3.0.2 - packages: /@babel/code-frame/7.10.4: @@ -1421,13 +1410,6 @@ packages: minimist: 1.2.5 dev: true - /@concordance/react/2.0.0: - resolution: {integrity: sha512-huLSkUuM2/P+U0uy2WwlKuixMsTODD8p4JVQBI4VKeopkiN0C7M3N9XYVawb4M+4spN5RrO/eLhk7KoQX6nsfA==} - engines: {node: '>=6.12.3 <7 || >=8.9.4 <9 || >=10.0.0'} - dependencies: - arrify: 1.0.1 - dev: true - /@creativebulma/bulma-tooltip/1.2.0: resolution: {integrity: sha512-ooImbeXEBxf77cttbzA7X5rC5aAWm9UsXIGViFOnsqB+6M944GkB28S5R4UWRqjFd2iW4zGEkEifAU+q43pt2w==} dev: true @@ -1587,6 +1569,18 @@ packages: - supports-color dev: true + /@gnu-taler/pogen/0.0.5: + resolution: {integrity: sha1-bB0QCi9T3Yr9o4wvq9EUUnE5R1Y=, tarball: https://gitlab.com/api/v4/projects/20136151/packages/npm/@gnu-taler/pogen/-/@gnu-taler/pogen-0.0.5.tgz} + dependencies: + '@types/node': 14.14.43 + dev: true + + /@gnu-taler/taler-util/0.8.2: + resolution: {integrity: sha1-B6/UuryzdS4wsbBtK1vTn/kNAaM=, tarball: https://gitlab.com/api/v4/projects/20136151/packages/npm/@gnu-taler/taler-util/-/@gnu-taler/taler-util-0.8.2.tgz} + dependencies: + tslib: 2.2.0 + dev: false + /@hapi/address/2.1.4: resolution: {integrity: sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ==} deprecated: Moved to 'npm install @sideway/address' @@ -4184,11 +4178,6 @@ packages: engines: {node: '>=0.4.0'} dev: true - /acorn-walk/8.1.0: - resolution: {integrity: sha512-mjmzmv12YIG/G8JQdQuz2MUDShEJ6teYpT5bmWA4q7iwoGen8xtt3twF3OvzIUl+Q06aWIjvnwQUKvQ6TtMRjg==} - engines: {node: '>=0.4.0'} - dev: true - /acorn/5.7.4: resolution: {integrity: sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==} engines: {node: '>=0.4.0'} @@ -4335,6 +4324,11 @@ packages: engines: {node: '>=8'} dev: true + /ansi-styles/1.0.0: + resolution: {integrity: sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=} + engines: {node: '>=0.8.0'} + dev: true + /ansi-styles/2.2.1: resolution: {integrity: sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=} engines: {node: '>=0.10.0'} @@ -4354,11 +4348,6 @@ packages: color-convert: 2.0.1 dev: true - /ansi-styles/5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} - dev: true - /ansi-to-html/0.6.14: resolution: {integrity: sha512-7ZslfB1+EnFSDO5Ju+ue5Y6It19DRnZXWv8jrGHgIlPna5Mh4jz7BV5jCbQneXNFurQcKoolaaAjHtgSBfOIuA==} hasBin: true @@ -4509,16 +4498,6 @@ packages: is-string: 1.0.5 dev: true - /arrgv/1.0.2: - resolution: {integrity: sha512-a4eg4yhp7mmruZDQFqVMlxNRFGi/i1r87pt8SDHy0/I8PqSXoUTlWZRdAZo0VXgvEARcujbtTk8kiZRi1uDGRw==} - engines: {node: '>=8.0.0'} - dev: true - - /arrify/1.0.1: - resolution: {integrity: sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=} - engines: {node: '>=0.10.0'} - dev: true - /arrify/2.0.1: resolution: {integrity: sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==} engines: {node: '>=8'} @@ -4611,71 +4590,6 @@ packages: postcss-value-parser: 4.1.0 dev: true - /ava/3.15.0: - resolution: {integrity: sha512-HGAnk1SHPk4Sx6plFAUkzV/XC1j9+iQhOzt4vBly18/yo0AV8Oytx7mtJd/CR8igCJ5p160N/Oo/cNJi2uSeWA==} - engines: {node: '>=10.18.0 <11 || >=12.14.0 <12.17.0 || >=12.17.0 <13 || >=14.0.0 <15 || >=15'} - hasBin: true - dependencies: - '@concordance/react': 2.0.0 - acorn: 8.2.1 - acorn-walk: 8.1.0 - ansi-styles: 5.2.0 - arrgv: 1.0.2 - arrify: 2.0.1 - callsites: 3.1.0 - chalk: 4.1.1 - chokidar: 3.5.1 - chunkd: 2.0.1 - ci-info: 2.0.0 - ci-parallel-vars: 1.0.1 - clean-yaml-object: 0.1.0 - cli-cursor: 3.1.0 - cli-truncate: 2.1.0 - code-excerpt: 3.0.0 - common-path-prefix: 3.0.0 - concordance: 5.0.4 - convert-source-map: 1.7.0 - currently-unhandled: 0.4.1 - debug: 4.3.1 - del: 6.0.0 - emittery: 0.8.1 - equal-length: 1.0.1 - figures: 3.2.0 - globby: 11.0.3 - ignore-by-default: 2.0.0 - import-local: 3.0.2 - indent-string: 4.0.0 - is-error: 2.2.2 - is-plain-object: 5.0.0 - is-promise: 4.0.0 - lodash: 4.17.21 - matcher: 3.0.0 - md5-hex: 3.0.1 - mem: 8.1.1 - ms: 2.1.3 - ora: 5.4.0 - p-event: 4.2.0 - p-map: 4.0.0 - picomatch: 2.2.3 - pkg-conf: 3.1.0 - plur: 4.0.0 - pretty-ms: 7.0.1 - read-pkg: 5.2.0 - resolve-cwd: 3.0.0 - slash: 3.0.0 - source-map-support: 0.5.19 - stack-utils: 2.0.3 - strip-ansi: 6.0.0 - supertap: 2.0.0 - temp-dir: 2.0.0 - trim-off-newlines: 1.0.1 - update-notifier: 5.1.0 - write-file-atomic: 3.0.3 - yargs: 16.2.0 - transitivePeerDependencies: - - supports-color - dev: true - /aws-sign2/0.7.0: resolution: {integrity: sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=} dev: true @@ -5058,22 +4972,10 @@ packages: dev: true optional: true - /bl/4.1.0: - resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - dependencies: - buffer: 5.7.1 - inherits: 2.0.4 - readable-stream: 3.6.0 - dev: true - /bluebird/3.7.2: resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} dev: true - /blueimp-md5/2.18.0: - resolution: {integrity: sha512-vE52okJvzsVWhcgUHOv+69OG3Mdg151xyn41aVQN/5W5S+S43qZhxECtYLAEHMSFWX6Mv5IZrzj3T5+JqXfj5Q==} - dev: true - /bn.js/4.12.0: resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} dev: true @@ -5127,20 +5029,6 @@ packages: widest-line: 3.1.0 dev: true - /boxen/5.0.1: - resolution: {integrity: sha512-49VBlw+PrWEF51aCmy7QIteYPIFZxSpvqBdP/2itCPPlJ49kj9zg/XPRFrdkne2W+CfwXUls8exMvu1RysZpKA==} - engines: {node: '>=10'} - dependencies: - ansi-align: 3.0.0 - camelcase: 6.2.0 - chalk: 4.1.1 - cli-boxes: 2.2.1 - string-width: 4.2.2 - type-fest: 0.20.2 - widest-line: 3.1.0 - wrap-ansi: 7.0.0 - dev: true - /brace-expansion/1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: @@ -5283,13 +5171,6 @@ packages: isarray: 1.0.0 dev: true - /buffer/5.7.1: - resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - dev: true - /builtin-modules/3.2.0: resolution: {integrity: sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==} engines: {node: '>=6'} @@ -5532,6 +5413,15 @@ packages: resolution: {integrity: sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==} dev: true + /chalk/0.4.0: + resolution: {integrity: sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=} + engines: {node: '>=0.8.0'} + dependencies: + ansi-styles: 1.0.0 + has-color: 0.1.7 + strip-ansi: 0.1.1 + dev: true + /chalk/1.1.3: resolution: {integrity: sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=} engines: {node: '>=0.10.0'} @@ -5668,10 +5558,6 @@ packages: engines: {node: '>=6.0'} dev: true - /chunkd/2.0.1: - resolution: {integrity: sha512-7d58XsFmOq0j6el67Ug9mHf9ELUXsQXYJBkyxhH/k+6Ke0qXRnv0kbemx+Twc6fRJ07C49lcbdgm9FL1Ei/6SQ==} - dev: true - /ci-env/1.16.0: resolution: {integrity: sha512-ucF9caQEX5wQlY449KZBIJPx91+kRg9tJ3tWSc4+KzrvC5KNiPm/3g1noP8VhdI3046+Vw3jLmKAD0fjCRJTmw==} dev: true @@ -5680,10 +5566,6 @@ packages: resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} dev: true - /ci-parallel-vars/1.0.1: - resolution: {integrity: sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg==} - dev: true - /cipher-base/1.0.4: resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} dependencies: @@ -5721,11 +5603,6 @@ packages: engines: {node: '>=6'} dev: true - /clean-yaml-object/0.1.0: - resolution: {integrity: sha1-Y/sRDcLOGoTcIfbZM0h20BCui2g=} - engines: {node: '>=0.10.0'} - dev: true - /cli-boxes/2.2.1: resolution: {integrity: sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==} engines: {node: '>=6'} @@ -5753,14 +5630,6 @@ packages: colors: 1.4.0 dev: true - /cli-truncate/2.1.0: - resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} - engines: {node: '>=8'} - dependencies: - slice-ansi: 3.0.0 - string-width: 4.2.2 - dev: true - /clipboard/2.0.8: resolution: {integrity: sha512-Y6WO0unAIQp5bLmk1zdThRhgJt/x3ks6f30s3oE3H1mgIEU33XyQjEf8gsf6DxC7NPX8Y1SsNWjUjL/ywLnnbQ==} dependencies: @@ -5786,14 +5655,6 @@ packages: wrap-ansi: 6.2.0 dev: true - /cliui/7.0.4: - resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} - dependencies: - string-width: 4.2.2 - strip-ansi: 6.0.0 - wrap-ansi: 7.0.0 - dev: true - /clone-deep/4.0.1: resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==} engines: {node: '>=6'} @@ -5828,13 +5689,6 @@ packages: q: 1.5.1 dev: true - /code-excerpt/3.0.0: - resolution: {integrity: sha512-VHNTVhd7KsLGOqfX3SyeO8RyYPMp1GJOg194VITk04WMYCv4plV68YWe6TJZxd9MhobjtpMRnVky01gqZsalaw==} - engines: {node: '>=10'} - dependencies: - convert-to-spaces: 1.0.2 - dev: true - /code-point-at/1.1.0: resolution: {integrity: sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=} engines: {node: '>=0.10.0'} @@ -5933,10 +5787,6 @@ packages: engines: {node: '>= 6'} dev: true - /common-path-prefix/3.0.0: - resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} - dev: true - /common-tags/1.8.0: resolution: {integrity: sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==} engines: {node: '>=4.0.0'} @@ -6002,20 +5852,6 @@ packages: typedarray: 0.0.6 dev: true - /concordance/5.0.4: - resolution: {integrity: sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==} - engines: {node: '>=10.18.0 <11 || >=12.14.0 <13 || >=14'} - dependencies: - date-time: 3.1.0 - esutils: 2.0.3 - fast-diff: 1.2.0 - js-string-escape: 1.0.1 - lodash: 4.17.21 - md5-hex: 3.0.1 - semver: 7.3.5 - well-known-symbols: 2.0.0 - dev: true - /configstore/5.0.1: resolution: {integrity: sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==} engines: {node: '>=8'} @@ -6068,11 +5904,6 @@ packages: safe-buffer: 5.1.2 dev: true - /convert-to-spaces/1.0.2: - resolution: {integrity: sha1-fj5Iu+bZl7FBfdyihoIEtNPYVxU=} - engines: {node: '>= 4'} - dev: true - /cookie-signature/1.0.6: resolution: {integrity: sha1-4wOogrNCzD7oylE6eZmXNNqzriw=} dev: true @@ -6577,13 +6408,6 @@ packages: engines: {node: '>=0.11'} dev: false - /date-time/3.1.0: - resolution: {integrity: sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==} - engines: {node: '>=6'} - dependencies: - time-zone: 1.0.0 - dev: true - /debug/2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} dependencies: @@ -6737,20 +6561,6 @@ packages: rimraf: 2.7.1 dev: true - /del/6.0.0: - resolution: {integrity: sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==} - engines: {node: '>=10'} - dependencies: - globby: 11.0.3 - graceful-fs: 4.2.6 - is-glob: 4.0.1 - is-path-cwd: 2.2.0 - is-path-inside: 3.0.3 - p-map: 4.0.0 - rimraf: 3.0.2 - slash: 3.0.0 - dev: true - /delayed-stream/1.0.0: resolution: {integrity: sha1-3zrhmayt+31ECqrgsp4icrJOxhk=} engines: {node: '>=0.4.0'} @@ -7098,11 +6908,6 @@ packages: engines: {node: '>=10'} dev: true - /emittery/0.8.1: - resolution: {integrity: sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==} - engines: {node: '>=10'} - dev: true - /emoji-regex/6.1.1: resolution: {integrity: sha1-xs0OwbBkLio8Z6ETfvxeeW2k+I4=} dev: true @@ -7247,11 +7052,6 @@ packages: string.prototype.trim: 1.2.4 dev: true - /equal-length/1.0.1: - resolution: {integrity: sha1-IcoRLUirJLTh5//A5TOdMf38J0w=} - engines: {node: '>=4'} - dev: true - /errno/0.1.8: resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} hasBin: true @@ -7346,11 +7146,6 @@ packages: engines: {node: '>=8'} dev: true - /escape-string-regexp/4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - dev: true - /escodegen/1.14.3: resolution: {integrity: sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==} engines: {node: '>=4.0'} @@ -7772,10 +7567,6 @@ packages: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} dev: true - /fast-diff/1.2.0: - resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==} - dev: true - /fast-glob/2.2.7: resolution: {integrity: sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==} engines: {node: '>=4.0.0'} @@ -7837,13 +7628,6 @@ packages: resolution: {integrity: sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==} dev: true - /figures/3.2.0: - resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} - engines: {node: '>=8'} - dependencies: - escape-string-regexp: 1.0.5 - dev: true - /file-entry-cache/6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -8303,18 +8087,10 @@ packages: assert-plus: 1.0.0 dev: true - /gettext-parser/1.4.0: - resolution: {integrity: sha512-sedZYLHlHeBop/gZ1jdg59hlUEcpcZJofLq2JFwJT1zTqAU3l2wFv6IsuwFHGqbiT9DWzMUW4/em2+hspnmMMA==} + /gettext-parser/1.1.0: + resolution: {integrity: sha1-LFpmONiTk0ubVQN9CtgstwBLJnk=} dependencies: encoding: 0.1.13 - safe-buffer: 5.2.1 - dev: true - - /gettext-to-messageformat/0.3.1: - resolution: {integrity: sha512-UyqIL3Ul4NryU95Wome/qtlcuVIqgEWVIFw0zi7Lv14ACLXfaVDCbrjZ7o+3BZ7u+4NS1mP/2O1eXZoHCoas8g==} - engines: {node: '>=6.0'} - dependencies: - gettext-parser: 1.4.0 dev: true /github-slugger/1.3.0: @@ -8391,13 +8167,6 @@ packages: ini: 1.3.7 dev: true - /global-dirs/3.0.0: - resolution: {integrity: sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==} - engines: {node: '>=10'} - dependencies: - ini: 2.0.0 - dev: true - /global-modules/2.0.0: resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==} engines: {node: '>=6'} @@ -8608,6 +8377,11 @@ packages: resolution: {integrity: sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==} dev: true + /has-color/0.1.7: + resolution: {integrity: sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=} + engines: {node: '>=0.10.0'} + dev: true + /has-flag/3.0.0: resolution: {integrity: sha1-tdRU3CGZriJWmfNGfloH87lVuv0=} engines: {node: '>=4'} @@ -9089,11 +8863,6 @@ packages: resolution: {integrity: sha1-xg7taebY/bazEEofy8ocGS3FtQE=} dev: true - /ignore-by-default/2.0.0: - resolution: {integrity: sha512-+mQSgMRiFD3L3AOxLYOCxjIq4OnAmo5CIuC+lj5ehCJcPtV++QacEV7FdpzvYxH6DaOySWzQU6RR0lPLy37ckA==} - engines: {node: '>=10 <11 || >=12 <13 || >=14'} - dev: true - /ignore/3.3.10: resolution: {integrity: sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==} dev: true @@ -9217,11 +8986,6 @@ packages: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} dev: true - /ini/2.0.0: - resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==} - engines: {node: '>=10'} - dev: true - /inline-chunk-html-plugin/1.1.1: resolution: {integrity: sha512-6W1eGIj8z/Yla6xJx5il6jJfCxMZS3kVkbiLQThbbjdsDLRIWkUVmpnhfW2l6WAwCW+qfy0zoXVGBZM1E5XF3g==} dev: true @@ -9277,11 +9041,6 @@ packages: engines: {node: '>= 0.10'} dev: true - /irregular-plurals/3.3.0: - resolution: {integrity: sha512-MVBLKUTangM3EfRPFROhmWQQKRDsrgI83J8GS3jXy+OwYqiR2/aoWndYQ5416jLE3uaGgLH7ncme3X9y09gZ3g==} - engines: {node: '>=8'} - dev: true - /is-absolute-url/2.1.0: resolution: {integrity: sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=} engines: {node: '>=0.10.0'} @@ -9454,10 +9213,6 @@ packages: is-window: 1.0.2 dev: true - /is-error/2.2.2: - resolution: {integrity: sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==} - dev: true - /is-extendable/0.1.1: resolution: {integrity: sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=} engines: {node: '>=0.10.0'} @@ -9544,14 +9299,6 @@ packages: is-path-inside: 3.0.3 dev: true - /is-installed-globally/0.4.0: - resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==} - engines: {node: '>=10'} - dependencies: - global-dirs: 3.0.0 - is-path-inside: 3.0.3 - dev: true - /is-interactive/1.0.0: resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} engines: {node: '>=8'} @@ -9575,11 +9322,6 @@ packages: engines: {node: '>=8'} dev: true - /is-npm/5.0.0: - resolution: {integrity: sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==} - engines: {node: '>=10'} - dev: true - /is-number-object/1.0.4: resolution: {integrity: sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==} engines: {node: '>= 0.4'} @@ -9657,19 +9399,10 @@ packages: engines: {node: '>=0.10.0'} dev: true - /is-plain-object/5.0.0: - resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} - engines: {node: '>=0.10.0'} - dev: true - /is-potential-custom-element-name/1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} dev: true - /is-promise/4.0.0: - resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} - dev: true - /is-regex/1.1.2: resolution: {integrity: sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==} engines: {node: '>= 0.4'} @@ -9726,11 +9459,6 @@ packages: resolution: {integrity: sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=} dev: true - /is-unicode-supported/0.1.0: - resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} - engines: {node: '>=10'} - dev: true - /is-utf8/0.2.1: resolution: {integrity: sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=} dev: true @@ -9864,6 +9592,10 @@ packages: iterate-iterator: 1.0.1 dev: true + /jed/1.1.1: + resolution: {integrity: sha1-elSbvZ/+FYWwzQoZHiAwVb7ldLQ=} + dev: false + /jest-changed-files/26.6.2: resolution: {integrity: sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ==} engines: {node: '>= 10.14.2'} @@ -10659,17 +10391,6 @@ packages: strip-bom: 2.0.0 dev: true - /load-json-file/5.3.0: - resolution: {integrity: sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==} - engines: {node: '>=6'} - dependencies: - graceful-fs: 4.2.6 - parse-json: 4.0.0 - pify: 4.0.1 - strip-bom: 3.0.0 - type-fest: 0.3.1 - dev: true - /loader-runner/2.4.0: resolution: {integrity: sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==} engines: {node: '>=4.3.0 <5.0.0 || >=5.10'} @@ -10800,14 +10521,6 @@ packages: chalk: 2.4.2 dev: true - /log-symbols/4.1.0: - resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} - engines: {node: '>=10'} - dependencies: - chalk: 4.1.1 - is-unicode-supported: 0.1.0 - dev: true - /loglevel/1.7.1: resolution: {integrity: sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==} engines: {node: '>= 0.6.0'} @@ -10904,26 +10617,12 @@ packages: semver: 6.3.0 dev: true - /make-plural/4.3.0: - resolution: {integrity: sha512-xTYd4JVHpSCW+aqDof6w/MebaMVNTVYBZhbB/vi513xXdiPT92JMVCo0Jq8W2UZnzYRFeVbQiQ+I25l13JuKvA==} - hasBin: true - optionalDependencies: - minimist: 1.2.5 - dev: false - /makeerror/1.0.11: resolution: {integrity: sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=} dependencies: tmpl: 1.0.4 dev: true - /map-age-cleaner/0.1.3: - resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==} - engines: {node: '>=6'} - dependencies: - p-defer: 1.0.0 - dev: true - /map-cache/0.2.2: resolution: {integrity: sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=} engines: {node: '>=0.10.0'} @@ -10992,20 +10691,6 @@ packages: hasBin: true dev: true - /matcher/3.0.0: - resolution: {integrity: sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==} - engines: {node: '>=10'} - dependencies: - escape-string-regexp: 4.0.0 - dev: true - - /md5-hex/3.0.1: - resolution: {integrity: sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==} - engines: {node: '>=8'} - dependencies: - blueimp-md5: 2.18.0 - dev: true - /md5.js/1.3.5: resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} dependencies: @@ -11060,14 +10745,6 @@ packages: engines: {node: '>= 0.6'} dev: true - /mem/8.1.1: - resolution: {integrity: sha512-qFCFUDs7U3b8mBDPyz5EToEKoAkgCzqquIgi9nkkR9bixxOVOre+09lbuH7+9Kn2NFpm56M3GUWVbU2hQgdACA==} - engines: {node: '>=10'} - dependencies: - map-age-cleaner: 0.1.3 - mimic-fn: 3.1.0 - dev: true - /memfs/3.2.2: resolution: {integrity: sha512-RE0CwmIM3CEvpcdK3rZ19BC4E6hv9kADkMN5rPduRak58cNArWLi/9jFLsa4rhsjfVxMP3v0jO7FHXq7SvFY5Q==} engines: {node: '>= 4.0.0'} @@ -11125,33 +10802,6 @@ packages: engines: {node: '>= 8'} dev: true - /messageformat-formatters/2.0.1: - resolution: {integrity: sha512-E/lQRXhtHwGuiQjI7qxkLp8AHbMD5r2217XNe/SREbBlSawe0lOqsFb7rflZJmlQFSULNLIqlcjjsCPlB3m3Mg==} - dev: false - - /messageformat-parser/4.1.3: - resolution: {integrity: sha512-2fU3XDCanRqeOCkn7R5zW5VQHWf+T3hH65SzuqRvjatBK7r4uyFa5mEX+k6F9Bd04LVM5G4/BHBTUJsOdW7uyg==} - dev: false - - /messageformat-po-loader/0.3.0_messageformat@2.3.0: - resolution: {integrity: sha512-thu/A7hNl/iBHsRXUdmiy/nEFJZku3bsBMXL53HgHm+I0JaVU9lSpwuQAe7huCO4INGxgZtDoPAEpeb1ZeI5lg==} - engines: {node: '>=6.0'} - peerDependencies: - messageformat: 1.x | 2.x - dependencies: - gettext-to-messageformat: 0.3.1 - loader-utils: 1.4.0 - messageformat: 2.3.0 - dev: true - - /messageformat/2.3.0: - resolution: {integrity: sha512-uTzvsv0lTeQxYI2y1NPa1lItL5VRI8Gb93Y2K2ue5gBPyrbJxfDi/EYWxh2PKv5yO42AJeeqblS9MJSh/IEk4w==} - dependencies: - make-plural: 4.3.0 - messageformat-formatters: 2.0.1 - messageformat-parser: 4.1.3 - dev: false - /methods/1.1.2: resolution: {integrity: sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=} engines: {node: '>= 0.6'} @@ -11225,11 +10875,6 @@ packages: engines: {node: '>=6'} dev: true - /mimic-fn/3.1.0: - resolution: {integrity: sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==} - engines: {node: '>=8'} - dev: true - /mimic-response/1.0.1: resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} engines: {node: '>=4'} @@ -11270,6 +10915,7 @@ packages: /minimist/1.2.5: resolution: {integrity: sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==} + dev: true /minipass-collect/1.0.2: resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==} @@ -11606,6 +11252,14 @@ packages: resolution: {integrity: sha512-4a5FH4WLi+daH/CGD5o/JWRR8W5tlCkd3nrDSkxbOzscJTyTUITltvOJeQjg3HJ1YgEuNyiPhQbvbtRjkQBByQ==} dev: true + /nomnom/1.8.1: + resolution: {integrity: sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=} + deprecated: Package no longer supported. Contact support@npmjs.com for more info. + dependencies: + chalk: 0.4.0 + underscore: 1.6.0 + dev: true + /nopt/5.0.0: resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==} engines: {node: '>=6'} @@ -11909,21 +11563,6 @@ packages: wcwidth: 1.0.1 dev: true - /ora/5.4.0: - resolution: {integrity: sha512-1StwyXQGoU6gdjYkyVcqOLnVlbKj+6yPNNOxJVgpt9t4eksKjiriiHuxktLYkgllwk+D6MbC4ihH84L1udRXPg==} - engines: {node: '>=10'} - dependencies: - bl: 4.1.0 - chalk: 4.1.1 - cli-cursor: 3.1.0 - cli-spinners: 2.6.0 - is-interactive: 1.0.0 - is-unicode-supported: 0.1.0 - log-symbols: 4.1.0 - strip-ansi: 6.0.0 - wcwidth: 1.0.1 - dev: true - /original/1.0.2: resolution: {integrity: sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==} dependencies: @@ -11950,11 +11589,6 @@ packages: engines: {node: '>=6'} dev: true - /p-defer/1.0.0: - resolution: {integrity: sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=} - engines: {node: '>=4'} - dev: true - /p-each-series/2.2.0: resolution: {integrity: sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==} engines: {node: '>=8'} @@ -12140,11 +11774,6 @@ packages: lines-and-columns: 1.1.6 dev: true - /parse-ms/2.1.0: - resolution: {integrity: sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==} - engines: {node: '>=6'} - dev: true - /parse5-htmlparser2-tree-adapter/6.0.1: resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} dependencies: @@ -12307,14 +11936,6 @@ packages: node-modules-regexp: 1.0.0 dev: true - /pkg-conf/3.1.0: - resolution: {integrity: sha512-m0OTbR/5VPNPqO1ph6Fqbj7Hv6QU7gR/tQW40ZqrL1rjgCU85W6C1bJn0BItuJqnR98PWzw7Z8hHeChD1WrgdQ==} - engines: {node: '>=6'} - dependencies: - find-up: 3.0.0 - load-json-file: 5.3.0 - dev: true - /pkg-dir/3.0.0: resolution: {integrity: sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==} engines: {node: '>=6'} @@ -12343,13 +11964,6 @@ packages: find-up: 3.0.0 dev: true - /plur/4.0.0: - resolution: {integrity: sha512-4UGewrYgqDFw9vV6zNV+ADmPAUAfJPKtGvb/VdpQAx25X5f3xXdGdyOEVFwkl8Hl/tl7+xbeHqSEM+D5/TirUg==} - engines: {node: '>=10'} - dependencies: - irregular-plurals: 3.3.0 - dev: true - /pn/1.1.0: resolution: {integrity: sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==} dev: true @@ -12363,6 +11977,15 @@ packages: - typescript dev: true + /po2json/0.4.5: + resolution: {integrity: sha1-R7spUtoy1Yob4vJWpZjuvAt0URg=} + engines: {node: '>= 0.8.0'} + hasBin: true + dependencies: + gettext-parser: 1.1.0 + nomnom: 1.8.1 + dev: true + /polished/4.1.2: resolution: {integrity: sha512-jq4t3PJUpVRcveC53nnbEX35VyQI05x3tniwp26WFdm1dwaNUBHAi5awa/roBlwQxx1uRhwNSYeAi/aMbfiJCQ==} engines: {node: '>=10'} @@ -12919,13 +12542,6 @@ packages: engines: {node: '>= 0.8'} dev: true - /pretty-ms/7.0.1: - resolution: {integrity: sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==} - engines: {node: '>=10'} - dependencies: - parse-ms: 2.1.0 - dev: true - /prismjs/1.23.0: resolution: {integrity: sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA==} optionalDependencies: @@ -14263,13 +13879,6 @@ packages: statuses: 1.5.0 dev: true - /serialize-error/7.0.1: - resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} - engines: {node: '>=10'} - dependencies: - type-fest: 0.13.1 - dev: true - /serialize-javascript/4.0.0: resolution: {integrity: sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==} dependencies: @@ -14485,15 +14094,6 @@ packages: engines: {node: '>=8'} dev: true - /slice-ansi/3.0.0: - resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==} - engines: {node: '>=8'} - dependencies: - ansi-styles: 4.3.0 - astral-regex: 2.0.0 - is-fullwidth-code-point: 3.0.0 - dev: true - /slice-ansi/4.0.0: resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} engines: {node: '>=10'} @@ -14891,6 +14491,12 @@ packages: is-regexp: 1.0.0 dev: true + /strip-ansi/0.1.1: + resolution: {integrity: sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=} + engines: {node: '>=0.8.0'} + hasBin: true + dev: true + /strip-ansi/3.0.1: resolution: {integrity: sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=} engines: {node: '>=0.10.0'} @@ -14919,11 +14525,6 @@ packages: is-utf8: 0.2.1 dev: true - /strip-bom/3.0.0: - resolution: {integrity: sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=} - engines: {node: '>=4'} - dev: true - /strip-bom/4.0.0: resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} engines: {node: '>=8'} @@ -14991,17 +14592,6 @@ packages: postcss-selector-parser: 3.1.2 dev: true - /supertap/2.0.0: - resolution: {integrity: sha512-jRzcXlCeDYvKoZGA5oRhYyR3jUIYu0enkSxtmAgHRlD7HwrovTpH4bDSi0py9FtuA8si9cW/fKommJHuaoDHJA==} - engines: {node: '>=10'} - dependencies: - arrify: 2.0.1 - indent-string: 4.0.0 - js-yaml: 3.14.1 - serialize-error: 7.0.1 - strip-ansi: 6.0.0 - dev: true - /supports-color/2.0.0: resolution: {integrity: sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=} engines: {node: '>=0.8.0'} @@ -15139,11 +14729,6 @@ packages: engines: {node: '>=4'} dev: true - /temp-dir/2.0.0: - resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} - engines: {node: '>=8'} - dev: true - /tempy/0.3.0: resolution: {integrity: sha512-WrH/pui8YCwmeiAoxV+lpRH9HpRtgBhSR2ViBPgpGb/wnYDzp21R4MN45fsCGvLROvY67o3byhJRYRONJyImVQ==} engines: {node: '>=8'} @@ -15245,11 +14830,6 @@ packages: resolution: {integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==} dev: true - /time-zone/1.0.0: - resolution: {integrity: sha1-mcW/VZWJZq9tBtg73zgA3IL67F0=} - engines: {node: '>=4'} - dev: true - /timers-browserify/2.0.12: resolution: {integrity: sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==} engines: {node: '>=0.6.0'} @@ -15386,11 +14966,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /trim-off-newlines/1.0.1: - resolution: {integrity: sha1-n5up2e+odkw4dpi8v+sshI8RrbM=} - engines: {node: '>=0.10.0'} - dev: true - /trim-trailing-lines/1.1.4: resolution: {integrity: sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==} dev: true @@ -15440,7 +15015,6 @@ packages: /tslib/2.2.0: resolution: {integrity: sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==} - dev: true /tsutils/3.21.0_typescript@4.2.4: resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} @@ -15485,11 +15059,6 @@ packages: engines: {node: '>=4'} dev: true - /type-fest/0.13.1: - resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} - engines: {node: '>=10'} - dev: true - /type-fest/0.20.2: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} @@ -15565,12 +15134,6 @@ packages: hasBin: true dev: true - /typescript/4.2.3: - resolution: {integrity: sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==} - engines: {node: '>=4.2.0'} - hasBin: true - dev: false - /typescript/4.2.4: resolution: {integrity: sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==} engines: {node: '>=4.2.0'} @@ -15602,6 +15165,10 @@ packages: which-boxed-primitive: 1.0.2 dev: true + /underscore/1.6.0: + resolution: {integrity: sha1-izixDKze9jM3uLJOT/htRa6lKag=} + dev: true + /unfetch/4.2.0: resolution: {integrity: sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==} dev: true @@ -15791,26 +15358,6 @@ packages: xdg-basedir: 4.0.0 dev: true - /update-notifier/5.1.0: - resolution: {integrity: sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==} - engines: {node: '>=10'} - dependencies: - boxen: 5.0.1 - chalk: 4.1.1 - configstore: 5.0.1 - has-yarn: 2.1.0 - import-lazy: 2.1.0 - is-ci: 2.0.0 - is-installed-globally: 0.4.0 - is-npm: 5.0.0 - is-yarn-global: 0.3.0 - latest-version: 5.1.0 - pupa: 2.1.1 - semver: 7.3.5 - semver-diff: 3.1.1 - xdg-basedir: 4.0.0 - dev: true - /upper-case/1.1.3: resolution: {integrity: sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=} dev: true @@ -16334,11 +15881,6 @@ packages: engines: {node: '>=0.8.0'} dev: true - /well-known-symbols/2.0.0: - resolution: {integrity: sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==} - engines: {node: '>=6'} - dev: true - /whatwg-encoding/1.0.5: resolution: {integrity: sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==} dependencies: @@ -16593,15 +16135,6 @@ packages: strip-ansi: 6.0.0 dev: true - /wrap-ansi/7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.2 - strip-ansi: 6.0.0 - dev: true - /wrappy/1.0.2: resolution: {integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=} dev: true @@ -16656,11 +16189,6 @@ packages: resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} dev: true - /y18n/5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - dev: true - /yallist/2.1.2: resolution: {integrity: sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=} dev: true @@ -16693,11 +16221,6 @@ packages: decamelize: 1.2.0 dev: true - /yargs-parser/20.2.7: - resolution: {integrity: sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==} - engines: {node: '>=10'} - dev: true - /yargs/13.3.2: resolution: {integrity: sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==} dependencies: @@ -16730,19 +16253,6 @@ packages: yargs-parser: 18.1.3 dev: true - /yargs/16.2.0: - resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} - engines: {node: '>=10'} - dependencies: - cliui: 7.0.4 - escalade: 3.1.1 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.2 - y18n: 5.0.8 - yargs-parser: 20.2.7 - dev: true - /yocto-queue/0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'}