diff options
Diffstat (limited to 'packages/backend/src')
55 files changed, 16369 insertions, 0 deletions
diff --git a/packages/backend/src/assets/empty.png b/packages/backend/src/assets/empty.png Binary files differnew file mode 100644 index 0000000..5120d31 --- /dev/null +++ b/packages/backend/src/assets/empty.png diff --git a/packages/backend/src/assets/icons/android-chrome-192x192.png b/packages/backend/src/assets/icons/android-chrome-192x192.png Binary files differnew file mode 100644 index 0000000..93ebe2e --- /dev/null +++ b/packages/backend/src/assets/icons/android-chrome-192x192.png diff --git a/packages/backend/src/assets/icons/android-chrome-512x512.png b/packages/backend/src/assets/icons/android-chrome-512x512.png Binary files differnew file mode 100644 index 0000000..52d1623 --- /dev/null +++ b/packages/backend/src/assets/icons/android-chrome-512x512.png diff --git a/packages/backend/src/assets/icons/apple-touch-icon.png b/packages/backend/src/assets/icons/apple-touch-icon.png Binary files differnew file mode 100644 index 0000000..254e4bb --- /dev/null +++ b/packages/backend/src/assets/icons/apple-touch-icon.png diff --git a/packages/backend/src/assets/icons/favicon-16x16.png b/packages/backend/src/assets/icons/favicon-16x16.png Binary files differnew file mode 100644 index 0000000..e81177d --- /dev/null +++ b/packages/backend/src/assets/icons/favicon-16x16.png diff --git a/packages/backend/src/assets/icons/favicon-32x32.png b/packages/backend/src/assets/icons/favicon-32x32.png Binary files differnew file mode 100644 index 0000000..40e9b5b --- /dev/null +++ b/packages/backend/src/assets/icons/favicon-32x32.png diff --git a/packages/backend/src/assets/icons/languageicon.svg b/packages/backend/src/assets/icons/languageicon.svg new file mode 100644 index 0000000..22d58da --- /dev/null +++ b/packages/backend/src/assets/icons/languageicon.svg @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 2411.2 2794" style="enable-background:new 0 0 2411.2 2794;" xml:space="preserve">
+<style type="text/css">
+ .st0{fill:#FFFFFF;}
+ .st1{fill-rule:evenodd;clip-rule:evenodd;}
+ .st2{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;}
+</style>
+<g id="Layer_2">
+</g>
+<g id="Layer_x5F_1_x5F_1">
+ <g>
+ <polygon points="1204.6,359.2 271.8,30 271.8,2060.1 1204.6,1758.3 "/>
+ <polygon class="st0" points="1182.2,358.1 2150.6,29 2150.6,2059 1182.2,1757.3 "/>
+ <polygon class="st0" points="30,2415.4 1182.2,2031.4 1182.2,357.9 30,742 "/>
+ <polygon points="1707.2,2440.7 1870.5,2709.4 1956.6,2459.8 "/>
+ <g>
+ <path d="M421.7,934.8c-6.1-6,8,49.1,27.6,68.9c34.8,35.1,61.9,39.6,76.4,40.2c32,1.3,71.5-8,94.9-17.8
+ c22.7-9.7,62.4-30,77.5-59.6c3.2-6.3,11.9-17,6.4-43.2c-4.2-20.2-17-27.3-32.7-26.2c-15.7,1.1-63.2,13.7-86.1,20.8
+ c-23,7-70.3,21.4-90.9,25.8C474.3,948.2,429,941.7,421.7,934.8z"/>
+ <path d="M1003.1,1593.7c-9.1-3.3-196.9-81.1-223.6-93.9c-21.8-10.5-75.2-33.1-100.4-43.3c70.8-109.2,115.5-191.6,121.5-204.1
+ c11-23,86-169.6,87.7-178.7c1.7-9.1,3.8-42.9,2.2-51c-1.7-8.2-29.1,7.6-66.4,20.2c-37.4,12.6-108.4,58.8-135.8,64.6
+ c-27.5,5.7-115.5,39.1-160.5,54c-45,14.9-130.2,40.9-165.2,50.4c-35.1,9.5-65.7,10.2-85.3,16.2c0,0,2.6,27.5,7.8,35.7
+ c5.2,8.2,23.7,28.4,45.3,34.1c21.6,5.7,57.3,3.4,73.6-0.3c16.3-3.8,44.4-17.5,48.2-23.6c3.8-6.1-2-24.9,4.5-30.6
+ c6.5-5.6,92.2-25.7,124.6-35.4c32.4-10,156.3-52.6,173.1-50.5c-5.3,17.7-105,215.1-137.1,274c-32.1,58.9-218.6,318-258.3,363.6
+ c-30.1,34.7-103.2,123.5-128.5,143.6c6.4,1.8,51.6-2.1,59.9-7.2c51.3-31.6,136.9-138.1,164.4-170.5
+ c81.9-96,153.8-196.8,210.8-283.4h0.1c11.1,4.6,100.9,77.8,124.4,94c23.4,16.2,115.9,67.8,136,76.4c20,8.7,97.1,44.2,100.3,32.2
+ C1029.4,1668,1012.2,1597.1,1003.1,1593.7z"/>
+ </g>
+ <path class="st1" d="M569,2572c18,11,35,20,54,29c38,19,81,39,122,54c56,21,112,38,168,51c31,7,65,13,98,18c3,0,92,11,110,11h90
+ c35-3,68-5,103-10c28-4,59-9,89-16c22-5,45-10,67-17c21-6,45-14,68-22c15-5,31-12,47-18c13-6,29-13,44-19c18-8,39-19,59-29
+ c16-8,34-18,51-28c13-7,43-30,59-30c18,0,30,16,30,30c0,29-39,38-57,51c-19,13-42,23-62,34c-40,21-81,39-120,54
+ c-51,19-107,37-157,49c-19,4-38,9-57,12c-10,2-114,18-143,18h-132c-35-3-72-7-107-12c-31-5-64-11-95-18c-24-5-50-12-73-19
+ c-40-11-79-25-117-40c-69-26-141-60-209-105c-12-8-13-16-13-25c0-15,11-29,29-29C531,2546,563,2569,569,2572z"/>
+ <path class="st1" d="M1151,2009L61,2372V764l1090-363V2009z M1212,354v1680c-1,5-3,10-7,15c-2,3-6,7-9,8c-25,10-1151,388-1166,388
+ c-12,0-23-8-29-21c0-1-1-2-1-4V739c2-5,3-12,7-16c8-11,22-13,31-16c17-6,1126-378,1142-378C1190,329,1212,336,1212,354z"/>
+ <path class="st1" d="M2120,2017l-907-282V380l907-308V2017z M2181,32v2023c-1,23-17,33-32,33c-13,0-107-32-123-37
+ c-126-39-253-78-378-117c-28-9-57-18-84-27c-24-7-50-15-74-23c-107-33-216-66-323-102c-4-1-14-15-14-18V351c2-5,4-11,9-15
+ c8-9,351-123,486-168c36-13,487-168,501-168C2167,0,2181,13,2181,32z"/>
+ <polygon points="2411.2,2440.7 1199.5,2054.5 1204.6,373.2 2411.2,757.2 "/>
+ <g>
+ <path class="st2" d="M1800.3,1124.6L1681.4,1412l218.6,66.3L1800.3,1124.6z M1729,853.2l156.1,47.3l284.4,1025l-160.3-48.7
+ l-57.6-210.4L1620.2,1566l-71.3,171.4l-160.4-48.7L1729,853.2z"/>
+ </g>
+ </g>
+</g>
+</svg>
diff --git a/packages/backend/src/assets/icons/mstile-150x150.png b/packages/backend/src/assets/icons/mstile-150x150.png Binary files differnew file mode 100644 index 0000000..9cfb889 --- /dev/null +++ b/packages/backend/src/assets/icons/mstile-150x150.png diff --git a/packages/backend/src/context/backend.ts b/packages/backend/src/context/backend.ts new file mode 100644 index 0000000..a920d6f --- /dev/null +++ b/packages/backend/src/context/backend.ts @@ -0,0 +1,82 @@ +/* + 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 { useCallback, useContext, useState } from 'preact/hooks' +import { useBackendDefaultToken, useBackendURL } from '../hooks'; + +interface BackendContextType { + url: string; + token?: string; + triedToLog: boolean; + resetBackend: () => void; + clearAllTokens: () => void; + addTokenCleaner: (c: () => void) => void; + updateLoginStatus: (url: string, token?: string) => void; +} + +const BackendContext = createContext<BackendContextType>({ + url: '', + token: undefined, + triedToLog: false, + resetBackend: () => null, + clearAllTokens: () => null, + addTokenCleaner: () => null, + updateLoginStatus: () => null, +}) + +function useBackendContextState(defaultUrl?: string): BackendContextType { + const [url, triedToLog, changeBackend, resetBackend] = useBackendURL(defaultUrl); + const [token, _updateToken] = useBackendDefaultToken(); + const updateToken = (t?: string) => { + _updateToken(t) + } + + 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() + } + + const updateLoginStatus = (url: string, token?: string) => { + changeBackend(url); + if (token) updateToken(token); + }; + + + return { url, token, triedToLog, updateLoginStatus, resetBackend, clearAllTokens, addTokenCleaner: addTokenCleanerMemo } +} + +export const BackendContextProvider = ({ children, defaultUrl }: { children: any, defaultUrl?: string }): VNode => { + const value = useBackendContextState(defaultUrl) + + return h(BackendContext.Provider, { value, children }); +} + +export const useBackendContext = (): BackendContextType => useContext(BackendContext); diff --git a/packages/backend/src/context/config.ts b/packages/backend/src/context/config.ts new file mode 100644 index 0000000..5cd7723 --- /dev/null +++ b/packages/backend/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/backend/src/context/fetch.ts b/packages/backend/src/context/fetch.ts new file mode 100644 index 0000000..52a4f9c --- /dev/null +++ b/packages/backend/src/context/fetch.ts @@ -0,0 +1,40 @@ +/* + 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 { h, createContext, VNode, ComponentChildren } from 'preact' +import { useContext } from 'preact/hooks' +import useSWR, { trigger, useSWRInfinite, cache, mutate } from 'swr'; + +interface Type { + useSWR: typeof useSWR, + useSWRInfinite: typeof useSWRInfinite, +} + +const Context = createContext<Type>({} as any) + +export const useFetchContext = (): Type => useContext(Context); +export const FetchContextProvider = ({ children }: { children: ComponentChildren }): VNode => { + return h(Context.Provider, { value: { useSWR, useSWRInfinite }, children }); +} + +export const FetchContextProviderTesting = ({ children, data }: { children: ComponentChildren, data:any }): VNode => { + return h(Context.Provider, { value: { useSWR: () => data, useSWRInfinite }, children }); +} diff --git a/packages/backend/src/context/instance.ts b/packages/backend/src/context/instance.ts new file mode 100644 index 0000000..fecf364 --- /dev/null +++ b/packages/backend/src/context/instance.ts @@ -0,0 +1,35 @@ +/* + 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; + changeToken: (t?:string) => void; +} + +const Context = createContext<Type>({} as any) + +export const InstanceContextProvider = Context.Provider +export const useInstanceContext = (): Type => useContext(Context); diff --git a/packages/backend/src/context/listener.ts b/packages/backend/src/context/listener.ts new file mode 100644 index 0000000..659db0a --- /dev/null +++ b/packages/backend/src/context/listener.ts @@ -0,0 +1,35 @@ +/* + 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; + changeToken: (t?:string) => void; +} + +const Context = createContext<Type>({} as any) + +export const ListenerContextProvider = Context.Provider +export const useListenerContext = (): Type => useContext(Context); diff --git a/packages/backend/src/context/translation.ts b/packages/backend/src/context/translation.ts new file mode 100644 index 0000000..952a1e3 --- /dev/null +++ b/packages/backend/src/context/translation.ts @@ -0,0 +1,59 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +import { createContext, h, VNode } from 'preact' +import { useContext, useEffect } from 'preact/hooks' +import { useLang } from '../hooks' +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, + forceLang?: string +} + +export const TranslationProvider = ({ initial, children, forceLang }: Props): VNode => { + const [lang, changeLanguage] = useLang(initial) + useEffect(() => { + if (forceLang) { + changeLanguage(forceLang) + } + }) + 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/backend/src/css/pure-min.css b/packages/backend/src/css/pure-min.css new file mode 100644 index 0000000..77217b5 --- /dev/null +++ b/packages/backend/src/css/pure-min.css @@ -0,0 +1,973 @@ +/*! + Pure v2.0.3 + Copyright 2013 Yahoo! + Licensed under the BSD License. + https://github.com/pure-cs s/pure/blob/master/LICENSE.md +*/ +/*! + normalize.cs s v | MIT License | git.io/normalize + Copyright (c) Nicolas Gallagher and Jonathan Neal +*/ +/*! normalize.cs s v8.0.1 | MIT License | github.com/necolas/normalize.cs s */ + +.talerbar { + text-align: center; +} + +html { + line-height: 1.15; + -webkit-text-size-adjust: 100%; +} +body { + margin: 0; +} +main { + display: block; +} +h1 { + font-size: 2em; + margin: 0.67em 0; +} +hr { + -webkit-box-sizing: content-box; + box-sizing: content-box; + height: 0; + overflow: visible; +} +pre { + font-family: monospace, monospace; + font-size: 1em; +} +a { + background-color: transparent; +} +abbr[title] { + border-bottom: none; + text-decoration: underline; + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} +b, +strong { + font-weight: bolder; +} +code, +kbd, +samp { + font-family: monospace, monospace; + font-size: 1em; +} +small { + font-size: 80%; +} +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} +sub { + bottom: -0.25em; +} +sup { + top: -0.5em; +} +img { + border-style: none; +} +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + font-size: 100%; + line-height: 1.15; + margin: 0; +} +button, +input { + overflow: visible; +} +button, +select { + text-transform: none; +} +[type="button"], +[type="reset"], +[type="submit"], +button { + -webkit-appearance: button; +} +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner, +button::-moz-focus-inner { + border-style: none; + padding: 0; +} +[type="button"]:-moz-focusring, +[type="reset"]:-moz-focusring, +[type="submit"]:-moz-focusring, +button:-moz-focusring { + outline: 1px dotted ButtonText; +} +fieldset { + padding: 0.35em 0.75em 0.625em; +} +legend { + -webkit-box-sizing: border-box; + box-sizing: border-box; + color: inherit; + display: table; + max-width: 100%; + padding: 0; + white-space: normal; +} +progress { + vertical-align: baseline; +} +textarea { + overflow: auto; +} +[type="checkbox"], +[type="radio"] { + -webkit-box-sizing: border-box; + box-sizing: border-box; + padding: 0; +} +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} +[type="search"] { + -webkit-appearance: textfield; + outline-offset: -2px; +} +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} +::-webkit-file-upload-button { + -webkit-appearance: button; + font: inherit; +} +details { + display: block; +} +summary { + display: list-item; +} +template { + display: none; +} +[hidden] { + display: none; +} +html { + font-family: sans-serif; +} +.hidden, +[hidden] { + display: none !important; +} +.pure-img { + max-width: 100%; + height: auto; + display: block; +} +.pure-g { + letter-spacing: -0.31em; + text-rendering: optimizespeed; + font-family: FreeSans, Arimo, "Droid Sans", Helvetica, Arial, sans-serif; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-flow: row wrap; + flex-flow: row wrap; + -ms-flex-line-pack: start; + align-content: flex-start; +} +@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) { + table .pure-g { + display: block; + } +} +.opera-only :-o-prefocus, +.pure-g { + word-spacing: -0.43em; +} +.pure-u { + display: inline-block; + letter-spacing: normal; + word-spacing: normal; + vertical-align: top; + text-rendering: auto; +} +.pure-g [class*="pure-u"] { + font-family: sans-serif; +} +.pure-u-1, +.pure-u-1-1, +.pure-u-1-12, +.pure-u-1-2, +.pure-u-1-24, +.pure-u-1-3, +.pure-u-1-4, +.pure-u-1-5, +.pure-u-1-6, +.pure-u-1-8, +.pure-u-10-24, +.pure-u-11-12, +.pure-u-11-24, +.pure-u-12-24, +.pure-u-13-24, +.pure-u-14-24, +.pure-u-15-24, +.pure-u-16-24, +.pure-u-17-24, +.pure-u-18-24, +.pure-u-19-24, +.pure-u-2-24, +.pure-u-2-3, +.pure-u-2-5, +.pure-u-20-24, +.pure-u-21-24, +.pure-u-22-24, +.pure-u-23-24, +.pure-u-24-24, +.pure-u-3-24, +.pure-u-3-4, +.pure-u-3-5, +.pure-u-3-8, +.pure-u-4-24, +.pure-u-4-5, +.pure-u-5-12, +.pure-u-5-24, +.pure-u-5-5, +.pure-u-5-6, +.pure-u-5-8, +.pure-u-6-24, +.pure-u-7-12, +.pure-u-7-24, +.pure-u-7-8, +.pure-u-8-24, +.pure-u-9-24 { + display: inline-block; + letter-spacing: normal; + word-spacing: normal; + vertical-align: top; + text-rendering: auto; +} +.pure-u-1-24 { + width: 4.1667%; +} +.pure-u-1-12, +.pure-u-2-24 { + width: 8.3333%; +} +.pure-u-1-8, +.pure-u-3-24 { + width: 12.5%; +} +.pure-u-1-6, +.pure-u-4-24 { + width: 16.6667%; +} +.pure-u-1-5 { + width: 20%; +} +.pure-u-5-24 { + width: 20.8333%; +} +.pure-u-1-4, +.pure-u-6-24 { + width: 25%; +} +.pure-u-7-24 { + width: 29.1667%; +} +.pure-u-1-3, +.pure-u-8-24 { + width: 33.3333%; +} +.pure-u-3-8, +.pure-u-9-24 { + width: 37.5%; +} +.pure-u-2-5 { + width: 40%; +} +.pure-u-10-24, +.pure-u-5-12 { + width: 41.6667%; +} +.pure-u-11-24 { + width: 45.8333%; +} +.pure-u-1-2, +.pure-u-12-24 { + width: 50%; +} +.pure-u-13-24 { + width: 54.1667%; +} +.pure-u-14-24, +.pure-u-7-12 { + width: 58.3333%; +} +.pure-u-3-5 { + width: 60%; +} +.pure-u-15-24, +.pure-u-5-8 { + width: 62.5%; +} +.pure-u-16-24, +.pure-u-2-3 { + width: 66.6667%; +} +.pure-u-17-24 { + width: 70.8333%; +} +.pure-u-18-24, +.pure-u-3-4 { + width: 75%; +} +.pure-u-19-24 { + width: 79.1667%; +} +.pure-u-4-5 { + width: 80%; +} +.pure-u-20-24, +.pure-u-5-6 { + width: 83.3333%; +} +.pure-u-21-24, +.pure-u-7-8 { + width: 87.5%; +} +.pure-u-11-12, +.pure-u-22-24 { + width: 91.6667%; +} +.pure-u-23-24 { + width: 95.8333%; +} +.pure-u-1, +.pure-u-1-1, +.pure-u-24-24, +.pure-u-5-5 { + width: 100%; +} +.pure-button { + display: inline-block; + line-height: normal; + white-space: nowrap; + vertical-align: middle; + text-align: center; + cursor: pointer; + -webkit-user-drag: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} +.pure-button::-moz-focus-inner { + padding: 0; + border: 0; +} +.pure-button-group { + letter-spacing: -0.31em; + text-rendering: optimizespeed; +} +.opera-only :-o-prefocus, +.pure-button-group { + word-spacing: -0.43em; +} +.pure-button-group .pure-button { + letter-spacing: normal; + word-spacing: normal; + vertical-align: top; + text-rendering: auto; +} +.pure-button { + font-family: inherit; + font-size: 100%; + padding: 0.5em 1em; + color: rgba(0, 0, 0, 0.8); + border: none transparent; + background-color: #e6e6e6; + text-decoration: none; + border-radius: 2px; +} +.pure-button-hover, +.pure-button:focus, +.pure-button:hover { + background-image: -webkit-gradient( + linear, + left top, + left bottom, + from(transparent), + color-stop(40%, rgba(0, 0, 0, 0.05)), + to(rgba(0, 0, 0, 0.1)) + ); + background-image: linear-gradient( + transparent, + rgba(0, 0, 0, 0.05) 40%, + rgba(0, 0, 0, 0.1) + ); +} +.pure-button:focus { + outline: 0; +} +.pure-button-active, +.pure-button:active { + -webkit-box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15) inset, + 0 0 6px rgba(0, 0, 0, 0.2) inset; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15) inset, + 0 0 6px rgba(0, 0, 0, 0.2) inset; + border-color: #000; +} +.pure-button-disabled, +.pure-button-disabled:active, +.pure-button-disabled:focus, +.pure-button-disabled:hover, +.pure-button[disabled] { + border: none; + background-image: none; + opacity: 0.4; + cursor: not-allowed; + -webkit-box-shadow: none; + box-shadow: none; + pointer-events: none; +} +.pure-button-hidden { + display: none; +} +.pure-button-primary, +.pure-button-selected, +a.pure-button-primary, +a.pure-button-selected { + background-color: #0078e7; + color: #fff; +} +.pure-button-group .pure-button { + margin: 0; + border-radius: 0; + border-right: 1px solid rgba(0, 0, 0, 0.2); +} +.pure-button-group .pure-button:first-child { + border-top-left-radius: 2px; + border-bottom-left-radius: 2px; +} +.pure-button-group .pure-button:last-child { + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-right: none; +} +.pure-form input[type="color"], +.pure-form input[type="date"], +.pure-form input[type="datetime-local"], +.pure-form input[type="datetime"], +.pure-form input[type="email"], +.pure-form input[type="month"], +.pure-form input[type="number"], +.pure-form input[type="password"], +.pure-form input[type="search"], +.pure-form input[type="tel"], +.pure-form input[type="text"], +.pure-form input[type="time"], +.pure-form input[type="url"], +.pure-form input[type="week"], +.pure-form select, +.pure-form textarea { + padding: 0.5em 0.6em; + display: inline-block; + border: 1px solid #ccc; + -webkit-box-shadow: inset 0 1px 3px #ddd; + box-shadow: inset 0 1px 3px #ddd; + border-radius: 4px; + vertical-align: middle; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} +.pure-form input:not([type]) { + padding: 0.5em 0.6em; + display: inline-block; + border: 1px solid #ccc; + -webkit-box-shadow: inset 0 1px 3px #ddd; + box-shadow: inset 0 1px 3px #ddd; + border-radius: 4px; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} +.pure-form input[type="color"] { + padding: 0.2em 0.5em; +} +.pure-form input[type="color"]:focus, +.pure-form input[type="date"]:focus, +.pure-form input[type="datetime-local"]:focus, +.pure-form input[type="datetime"]:focus, +.pure-form input[type="email"]:focus, +.pure-form input[type="month"]:focus, +.pure-form input[type="number"]:focus, +.pure-form input[type="password"]:focus, +.pure-form input[type="search"]:focus, +.pure-form input[type="tel"]:focus, +.pure-form input[type="text"]:focus, +.pure-form input[type="time"]:focus, +.pure-form input[type="url"]:focus, +.pure-form input[type="week"]:focus, +.pure-form select:focus, +.pure-form textarea:focus { + outline: 0; + border-color: #129fea; +} +.pure-form input:not([type]):focus { + outline: 0; + border-color: #129fea; +} +.pure-form input[type="checkbox"]:focus, +.pure-form input[type="file"]:focus, +.pure-form input[type="radio"]:focus { + outline: thin solid #129fea; + outline: 1px auto #129fea; +} +.pure-form .pure-checkbox, +.pure-form .pure-radio { + margin: 0.5em 0; + display: block; +} +.pure-form input[type="color"][disabled], +.pure-form input[type="date"][disabled], +.pure-form input[type="datetime-local"][disabled], +.pure-form input[type="datetime"][disabled], +.pure-form input[type="email"][disabled], +.pure-form input[type="month"][disabled], +.pure-form input[type="number"][disabled], +.pure-form input[type="password"][disabled], +.pure-form input[type="search"][disabled], +.pure-form input[type="tel"][disabled], +.pure-form input[type="text"][disabled], +.pure-form input[type="time"][disabled], +.pure-form input[type="url"][disabled], +.pure-form input[type="week"][disabled], +.pure-form select[disabled], +.pure-form textarea[disabled] { + cursor: not-allowed; + background-color: #eaeded; + color: #cad2d3; +} +.pure-form input:not([type])[disabled] { + cursor: not-allowed; + background-color: #eaeded; + color: #cad2d3; +} +.pure-form input[readonly], +.pure-form select[readonly], +.pure-form textarea[readonly] { + background-color: #eee; + color: #777; + border-color: #ccc; +} +.pure-form input:focus:invalid, +.pure-form select:focus:invalid, +.pure-form textarea:focus:invalid { + color: #b94a48; + border-color: #e9322d; +} +.pure-form input[type="checkbox"]:focus:invalid:focus, +.pure-form input[type="file"]:focus:invalid:focus, +.pure-form input[type="radio"]:focus:invalid:focus { + outline-color: #e9322d; +} +.pure-form select { + height: 2.25em; + border: 1px solid #ccc; + background-color: #fff; +} +.pure-form select[multiple] { + height: auto; +} +.pure-form label { + margin: 0.5em 0 0.2em; +} +.pure-form fieldset { + margin: 0; + padding: 0.35em 0 0.75em; + border: 0; +} +.pure-form legend { + display: block; + width: 100%; + padding: 0.3em 0; + margin-bottom: 0.3em; + color: #333; + border-bottom: 1px solid #e5e5e5; +} +.pure-form-stacked input[type="color"], +.pure-form-stacked input[type="date"], +.pure-form-stacked input[type="datetime-local"], +.pure-form-stacked input[type="datetime"], +.pure-form-stacked input[type="email"], +.pure-form-stacked input[type="file"], +.pure-form-stacked input[type="month"], +.pure-form-stacked input[type="number"], +.pure-form-stacked input[type="password"], +.pure-form-stacked input[type="search"], +.pure-form-stacked input[type="tel"], +.pure-form-stacked input[type="text"], +.pure-form-stacked input[type="time"], +.pure-form-stacked input[type="url"], +.pure-form-stacked input[type="week"], +.pure-form-stacked label, +.pure-form-stacked select, +.pure-form-stacked textarea { + display: block; + margin: 0.25em 0; +} +.pure-form-stacked input:not([type]) { + display: block; + margin: 0.25em 0; +} +.pure-form-aligned input, +.pure-form-aligned select, +.pure-form-aligned textarea, +.pure-form-message-inline { + display: inline-block; + vertical-align: middle; +} +.pure-form-aligned textarea { + vertical-align: top; +} +.pure-form-aligned .pure-control-group { + margin-bottom: 0.5em; +} +.pure-form-aligned .pure-control-group label { + text-align: right; + display: inline-block; + vertical-align: middle; + width: 10em; + margin: 0 1em 0 0; +} +.pure-form-aligned .pure-controls { + margin: 1.5em 0 0 11em; +} +.pure-form .pure-input-rounded, +.pure-form input.pure-input-rounded { + border-radius: 2em; + padding: 0.5em 1em; +} +.pure-form .pure-group fieldset { + margin-bottom: 10px; +} +.pure-form .pure-group input, +.pure-form .pure-group textarea { + display: block; + padding: 10px; + margin: 0 0 -1px; + border-radius: 0; + position: relative; + top: -1px; +} +.pure-form .pure-group input:focus, +.pure-form .pure-group textarea:focus { + z-index: 3; +} +.pure-form .pure-group input:first-child, +.pure-form .pure-group textarea:first-child { + top: 1px; + border-radius: 4px 4px 0 0; + margin: 0; +} +.pure-form .pure-group input:first-child:last-child, +.pure-form .pure-group textarea:first-child:last-child { + top: 1px; + border-radius: 4px; + margin: 0; +} +.pure-form .pure-group input:last-child, +.pure-form .pure-group textarea:last-child { + top: -2px; + border-radius: 0 0 4px 4px; + margin: 0; +} +.pure-form .pure-group button { + margin: 0.35em 0; +} +.pure-form .pure-input-1 { + width: 100%; +} +.pure-form .pure-input-3-4 { + width: 75%; +} +.pure-form .pure-input-2-3 { + width: 66%; +} +.pure-form .pure-input-1-2 { + width: 50%; +} +.pure-form .pure-input-1-3 { + width: 33%; +} +.pure-form .pure-input-1-4 { + width: 25%; +} +.pure-form-message-inline { + display: inline-block; + padding-left: 0.3em; + color: #666; + vertical-align: middle; + font-size: 0.875em; +} +.pure-form-message { + display: block; + color: #666; + font-size: 0.875em; +} +@media only screen and (max-width: 480px) { + .pure-form button[type="submit"] { + margin: 0.7em 0 0; + } + .pure-form input:not([type]), + .pure-form input[type="color"], + .pure-form input[type="date"], + .pure-form input[type="datetime-local"], + .pure-form input[type="datetime"], + .pure-form input[type="email"], + .pure-form input[type="month"], + .pure-form input[type="number"], + .pure-form input[type="password"], + .pure-form input[type="search"], + .pure-form input[type="tel"], + .pure-form input[type="text"], + .pure-form input[type="time"], + .pure-form input[type="url"], + .pure-form input[type="week"], + .pure-form label { + margin-bottom: 0.3em; + display: block; + } + .pure-group input:not([type]), + .pure-group input[type="color"], + .pure-group input[type="date"], + .pure-group input[type="datetime-local"], + .pure-group input[type="datetime"], + .pure-group input[type="email"], + .pure-group input[type="month"], + .pure-group input[type="number"], + .pure-group input[type="password"], + .pure-group input[type="search"], + .pure-group input[type="tel"], + .pure-group input[type="text"], + .pure-group input[type="time"], + .pure-group input[type="url"], + .pure-group input[type="week"] { + margin-bottom: 0; + } + .pure-form-aligned .pure-control-group label { + margin-bottom: 0.3em; + text-align: left; + display: block; + width: 100%; + } + .pure-form-aligned .pure-controls { + margin: 1.5em 0 0 0; + } + .pure-form-message, + .pure-form-message-inline { + display: block; + font-size: 0.75em; + padding: 0.2em 0 0.8em; + } +} +.pure-menu { + -webkit-box-sizing: border-box; + box-sizing: border-box; +} +.pure-menu-fixed { + position: fixed; + left: 0; + top: 0; + z-index: 3; +} +.pure-menu-item, +.pure-menu-list { + position: relative; +} +.pure-menu-list { + list-style: none; + margin: 0; + padding: 0; +} +.pure-menu-item { + padding: 0; + margin: 0; + height: 100%; +} +.pure-menu-heading, +.pure-menu-link { + display: block; + text-decoration: none; + white-space: nowrap; +} +.pure-menu-horizontal { + width: 100%; + white-space: nowrap; +} +.pure-menu-horizontal .pure-menu-list { + display: inline-block; +} +.pure-menu-horizontal .pure-menu-heading, +.pure-menu-horizontal .pure-menu-item, +.pure-menu-horizontal .pure-menu-separator { + display: inline-block; + vertical-align: middle; +} +.pure-menu-item .pure-menu-item { + display: block; +} +.pure-menu-children { + display: none; + position: absolute; + left: 100%; + top: 0; + margin: 0; + padding: 0; + z-index: 3; +} +.pure-menu-horizontal .pure-menu-children { + left: 0; + top: auto; + width: inherit; +} +.pure-menu-active > .pure-menu-children, +.pure-menu-allow-hover:hover > .pure-menu-children { + display: block; + position: absolute; +} +.pure-menu-has-children > .pure-menu-link:after { + padding-left: 0.5em; + content: "\25B8"; + font-size: small; +} +.pure-menu-horizontal .pure-menu-has-children > .pure-menu-link:after { + content: "\25BE"; +} +.pure-menu-scrollable { + overflow-y: scroll; + overflow-x: hidden; +} +.pure-menu-scrollable .pure-menu-list { + display: block; +} +.pure-menu-horizontal.pure-menu-scrollable .pure-menu-list { + display: inline-block; +} +.pure-menu-horizontal.pure-menu-scrollable { + white-space: nowrap; + overflow-y: hidden; + overflow-x: auto; + padding: 0.5em 0; +} +.pure-menu-horizontal .pure-menu-children .pure-menu-separator, +.pure-menu-separator { + background-color: #ccc; + height: 1px; + margin: 0.3em 0; +} +.pure-menu-horizontal .pure-menu-separator { + width: 1px; + height: 1.3em; + margin: 0 0.3em; +} +.pure-menu-horizontal .pure-menu-children .pure-menu-separator { + display: block; + width: auto; +} +.pure-menu-heading { + text-transform: uppercase; + color: #565d64; +} +.pure-menu-link { + color: #777; +} +.pure-menu-children { + background-color: #fff; +} +.pure-menu-disabled, +.pure-menu-heading, +.pure-menu-link { + padding: 0.5em 1em; +} +.pure-menu-disabled { + opacity: 0.5; +} +.pure-menu-disabled .pure-menu-link:hover { + background-color: transparent; +} +.pure-menu-active > .pure-menu-link, +.pure-menu-link:focus, +.pure-menu-link:hover { + background-color: #eee; +} +.pure-menu-selected > .pure-menu-link, +.pure-menu-selected > .pure-menu-link:visited { + color: #000; +} +.pure-table { + border-collapse: collapse; + border-spacing: 0; + empty-cells: show; + border: 1px solid #cbcbcb; +} +.pure-table caption { + color: #000; + font: italic 85%/1 arial, sans-serif; + padding: 1em 0; + text-align: center; +} +.pure-table td, +.pure-table th { + border-left: 1px solid #cbcbcb; + border-width: 0 0 0 1px; + font-size: inherit; + margin: 0; + overflow: visible; + padding: 0.5em 1em; +} +.pure-table thead { + background-color: #e0e0e0; + color: #000; + text-align: left; + vertical-align: bottom; +} +.pure-table td { + background-color: transparent; +} +.pure-table-odd td { + background-color: #f2f2f2; +} +.pure-table-striped tr:nth-child(2n-1) td { + background-color: #f2f2f2; +} +.pure-table-bordered td { + border-bottom: 1px solid #cbcbcb; +} +.pure-table-bordered tbody > tr:last-child > td { + border-bottom-width: 0; +} +.pure-table-horizontal td, +.pure-table-horizontal th { + border-width: 0 0 1px 0; + border-bottom: 1px solid #cbcbcb; +} +.pure-table-horizontal tbody > tr:last-child > td { + border-bottom-width: 0; +} diff --git a/packages/backend/src/css/style.css b/packages/backend/src/css/style.css new file mode 100644 index 0000000..e03b632 --- /dev/null +++ b/packages/backend/src/css/style.css @@ -0,0 +1,62 @@ +/*! + Pure v2.0.3 + Copyright 2013 Yahoo! + Licensed under the BSD License. + https://github.com/pure-ss/pure/blob/master/LICENSE.md +*/ +/*! + normalize.cs v | MIT License | git.io/normalize + Copyright (c) Nicolas Gallagher and Jonathan Neal +*/ +/*! normalize.ss v8.0.1 | MIT License | github.com/necolas/normalize.cs */ + +.talerbar { + text-align: center; +} +.tt { + font-family: "Lucida Console", Monaco, monospace; +} +.content { + overflow-x: auto; + padding-left: 15%; + padding-right: 15%; +} +.qr { + margin: auto; + text-align: center; +} +.qrtext { + width: max-content; + margin: auto; + transition: font-size 0.2s; + font-family: "Lucida Console", Monaco, monospace; + font-size: 0.5em; +} +.qrtext:hover { + font-size: 1em; +} +.talerbar { + margin: 0; + bottom: 0; + background-color: #033; + color: white; + width: 100%; + padding: 1em; + overflow: auto; +} +body { + overflow-y: scroll; +} +@media (min-width: 500px) { + .content { + padding-bottom: 2em; + margin-right: 1em; + overflow-y: auto; + } +} +#main a:link, +#main a:visited, +#main a:hover, +#main a:active { + color: black; +}
\ No newline at end of file diff --git a/packages/backend/src/custom.d.ts b/packages/backend/src/custom.d.ts new file mode 100644 index 0000000..d270500 --- /dev/null +++ b/packages/backend/src/custom.d.ts @@ -0,0 +1,40 @@ +/* + 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/> + */ +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; +} +declare module "*.png" { + const content: any; + export default content; +} +declare module '*.svg' { + const content: any; + export default content; +} + +declare module '*.scss' { + const content: Record<string, string>; + export default content; +} diff --git a/packages/backend/src/declaration.d.ts b/packages/backend/src/declaration.d.ts new file mode 100644 index 0000000..1722a3d --- /dev/null +++ b/packages/backend/src/declaration.d.ts @@ -0,0 +1,1384 @@ +/* + 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) +*/ + + +type HashCode = string; +type EddsaPublicKey = string; +type EddsaSignature = string; +type WireTransferIdentifierRawP = string; +type RelativeTime = Duration; +type ImageDataUrl = string; + +export interface WithId { + id: string +} + +interface Timestamp { + // Milliseconds since epoch, or the special + // value "forever" to represent an event that will + // never happen. + t_ms: number | "never"; +} +interface Duration { + // Duration in milliseconds or "forever" + // to represent an infinite duration. + d_ms: number | "forever"; +} + +interface WithId { + id: string; +} + +type Amount = string; +type UUID = string; +type Integer = number; + +export namespace ExchangeBackend { + interface WireResponse { + + // Master public key of the exchange, must match the key returned in /keys. + master_public_key: EddsaPublicKey; + + // Array of wire accounts operated by the exchange for + // incoming wire transfers. + accounts: WireAccount[]; + + // Object mapping names of wire methods (i.e. "sepa" or "x-taler-bank") + // to wire fees. + fees: { method: AggregateTransferFee }; + } + interface WireAccount { + // payto:// URI identifying the account and wire method + payto_uri: string; + + // Signature using the exchange's offline key + // with purpose TALER_SIGNATURE_MASTER_WIRE_DETAILS. + master_sig: EddsaSignature; + } + interface AggregateTransferFee { + // Per transfer wire transfer fee. + wire_fee: Amount; + + // Per transfer closing fee. + closing_fee: Amount; + + // What date (inclusive) does this fee go into effect? + // The different fees must cover the full time period in which + // any of the denomination keys are valid without overlap. + start_date: Timestamp; + + // What date (exclusive) does this fee stop going into effect? + // The different fees must cover the full time period in which + // any of the denomination keys are valid without overlap. + end_date: Timestamp; + + // Signature of TALER_MasterWireFeePS with + // purpose TALER_SIGNATURE_MASTER_WIRE_FEES. + sig: EddsaSignature; + } + +} +export namespace MerchantBackend { + interface ErrorDetail { + + // Numeric error code unique to the condition. + // The other arguments are specific to the error value reported here. + code: number; + + // Human-readable description of the error, i.e. "missing parameter", "commitment violation", ... + // Should give a human-readable hint about the error's nature. Optional, may change without notice! + hint?: string; + + // Optional detail about the specific input value that failed. May change without notice! + detail?: string; + + // Name of the parameter that was bogus (if applicable). + parameter?: string; + + // Path to the argument that was bogus (if applicable). + path?: string; + + // Offset of the argument that was bogus (if applicable). + offset?: string; + + // Index of the argument that was bogus (if applicable). + index?: string; + + // Name of the object that was bogus (if applicable). + object?: string; + + // Name of the currency than was problematic (if applicable). + currency?: string; + + // Expected type (if applicable). + type_expected?: string; + + // Type that was provided instead (if applicable). + type_actual?: string; + } + + + // Delivery location, loosely modeled as a subset of + // ISO20022's PostalAddress25. + interface Tax { + // the name of the tax + name: string; + + // amount paid in tax + tax: Amount; + } + + interface Auditor { + // official name + name: string; + + // Auditor's public key + auditor_pub: EddsaPublicKey; + + // Base URL of the auditor + url: string; + } + interface Exchange { + // the exchange's base URL + url: string; + + // master public key of the exchange + master_pub: EddsaPublicKey; + } + + interface Product { + // merchant-internal identifier for the product. + product_id?: string; + + // Human-readable product description. + description: string; + + // Map from IETF BCP 47 language tags to localized descriptions + description_i18n?: { [lang_tag: string]: string }; + + // The number of units of the product to deliver to the customer. + quantity: Integer; + + // The unit in which the product is measured (liters, kilograms, packages, etc.) + unit: string; + + // The price of the product; this is the total price for quantity times unit of this product. + price: Amount; + + // An optional base64-encoded product image + image: ImageDataUrl; + + // a list of taxes paid by the merchant for this product. Can be empty. + taxes: Tax[]; + + // time indicating when this product should be delivered + delivery_date?: Timestamp; + } + interface Merchant { + // label for a location with the business address of the merchant + address: Location; + + // the merchant's legal name of business + name: string; + + // label for a location that denotes the jurisdiction for disputes. + // Some of the typical fields for a location (such as a street address) may be absent. + jurisdiction: Location; + } + + interface VersionResponse { + // libtool-style representation of the Merchant protocol version, see + // https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning + // The format is "current:revision:age". + version: string; + + // Name of the protocol. + name: "taler-merchant"; + + // Currency supported by this backend. + currency: string; + + } + interface Location { + // Nation with its own government. + country?: string; + + // Identifies a subdivision of a country such as state, region, county. + country_subdivision?: string; + + // Identifies a subdivision within a country sub-division. + district?: string; + + // Name of a built-up area, with defined boundaries, and a local government. + town?: string; + + // Specific location name within the town. + town_location?: string; + + // Identifier consisting of a group of letters and/or numbers that + // is added to a postal address to assist the sorting of mail. + post_code?: string; + + // Name of a street or thoroughfare. + street?: string; + + // Name of the building or house. + building_name?: string; + + // Number that identifies the position of a building on a street. + building_number?: string; + + // Free-form address lines, should not exceed 7 elements. + address_lines?: string[]; + } + namespace Instances { + + //POST /private/instances/$INSTANCE/auth + interface InstanceAuthConfigurationMessage { + // Type of authentication. + // "external": The mechant backend does not do + // any authentication checks. Instead an API + // gateway must do the authentication. + // "token": The merchant checks an auth token. + // See "token" for details. + method: "external" | "token"; + + // For method "external", this field is mandatory. + // The token MUST begin with the string "secret-token:". + // After the auth token has been set (with method "token"), + // the value must be provided in a "Authorization: Bearer $token" + // header. + token?: string; + + } + //POST /private/instances + interface InstanceConfigurationMessage { + // The URI where the wallet will send coins. A merchant may have + // multiple accounts, thus this is an array. Note that by + // removing URIs from this list the respective account is set to + // inactive and thus unavailable for new contracts, but preserved + // in the database as existing offers and contracts may still refer + // to it. + payto_uris: string[]; + + // Name of the merchant instance to create (will become $INSTANCE). + id: string; + + // Merchant name corresponding to this instance. + name: string; + + // "Authentication" header required to authorize management access the instance. + // Optional, if not given authentication will be disabled for + // this instance (hopefully authentication checks are still + // done by some reverse proxy). + auth: InstanceAuthConfigurationMessage; + + // The merchant's physical address (to be put into contracts). + address: Location; + + // The jurisdiction under which the merchant conducts its business + // (to be put into contracts). + jurisdiction: Location; + + // Maximum wire fee this instance is willing to pay. + // Can be overridden by the frontend on a per-order basis. + default_max_wire_fee: Amount; + + // Default factor for wire fee amortization calculations. + // Can be overridden by the frontend on a per-order basis. + default_wire_fee_amortization: Integer; + + // Maximum deposit fee (sum over all coins) this instance is willing to pay. + // Can be overridden by the frontend on a per-order basis. + default_max_deposit_fee: Amount; + + // If the frontend does NOT specify an execution date, how long should + // we tell the exchange to wait to aggregate transactions before + // executing the wire transfer? This delay is added to the current + // time when we generate the advisory execution time for the exchange. + default_wire_transfer_delay: RelativeTime; + + // If the frontend does NOT specify a payment deadline, how long should + // offers we make be valid by default? + default_pay_delay: RelativeTime; + + } + + // PATCH /private/instances/$INSTANCE + interface InstanceReconfigurationMessage { + // The URI where the wallet will send coins. A merchant may have + // multiple accounts, thus this is an array. Note that by + // removing URIs from this list + payto_uris: string[]; + + // Merchant name corresponding to this instance. + name: string; + + // The merchant's physical address (to be put into contracts). + address: Location; + + // The jurisdiction under which the merchant conducts its business + // (to be put into contracts). + jurisdiction: Location; + + // Maximum wire fee this instance is willing to pay. + // Can be overridden by the frontend on a per-order basis. + default_max_wire_fee: Amount; + + // Default factor for wire fee amortization calculations. + // Can be overridden by the frontend on a per-order basis. + default_wire_fee_amortization: Integer; + + // Maximum deposit fee (sum over all coins) this instance is willing to pay. + // Can be overridden by the frontend on a per-order basis. + default_max_deposit_fee: Amount; + + // If the frontend does NOT specify an execution date, how long should + // we tell the exchange to wait to aggregate transactions before + // executing the wire transfer? This delay is added to the current + // time when we generate the advisory execution time for the exchange. + default_wire_transfer_delay: RelativeTime; + + // If the frontend does NOT specify a payment deadline, how long should + // offers we make be valid by default? + default_pay_delay: RelativeTime; + + } + + // GET /private/instances + interface InstancesResponse { + // List of instances that are present in the backend (see Instance) + instances: Instance[]; + } + + interface Instance { + // Merchant name corresponding to this instance. + name: string; + + deleted?: boolean; + + // Merchant instance this response is about ($INSTANCE) + id: string; + + // Public key of the merchant/instance, in Crockford Base32 encoding. + merchant_pub: EddsaPublicKey; + + // List of the payment targets supported by this instance. Clients can + // specify the desired payment target in /order requests. Note that + // front-ends do not have to support wallets selecting payment targets. + payment_targets: string[]; + + } + + //GET /private/instances/$INSTANCE + interface QueryInstancesResponse { + // The URI where the wallet will send coins. A merchant may have + // multiple accounts, thus this is an array. + accounts: MerchantAccount[]; + + // Merchant name corresponding to this instance. + name: string; + + // Public key of the merchant/instance, in Crockford Base32 encoding. + merchant_pub: EddsaPublicKey; + + // The merchant's physical address (to be put into contracts). + address: Location; + + // The jurisdiction under which the merchant conducts its business + // (to be put into contracts). + jurisdiction: Location; + + // Maximum wire fee this instance is willing to pay. + // Can be overridden by the frontend on a per-order basis. + default_max_wire_fee: Amount; + + // Default factor for wire fee amortization calculations. + // Can be overridden by the frontend on a per-order basis. + default_wire_fee_amortization: Integer; + + // Maximum deposit fee (sum over all coins) this instance is willing to pay. + // Can be overridden by the frontend on a per-order basis. + default_max_deposit_fee: Amount; + + // If the frontend does NOT specify an execution date, how long should + // we tell the exchange to wait to aggregate transactions before + // executing the wire transfer? This delay is added to the current + // time when we generate the advisory execution time for the exchange. + default_wire_transfer_delay: RelativeTime; + + // If the frontend does NOT specify a payment deadline, how long should + // offers we make be valid by default? + default_pay_delay: RelativeTime; + + // Authentication configuration. + // Does not contain the token when token auth is configured. + auth: { + method: "external" | "token"; + }; + } + + interface MerchantAccount { + + // payto:// URI of the account. + payto_uri: string; + + // Hash over the wire details (including over the salt) + h_wire: HashCode; + + // salt used to compute h_wire + salt: HashCode; + + // true if this account is active, + // false if it is historic. + active: boolean; + } + + // DELETE /private/instances/$INSTANCE + + + } + + namespace Products { + // POST /private/products + interface ProductAddDetail { + + // product ID to use. + product_id: string; + + // Human-readable product description. + description: string; + + // Map from IETF BCP 47 language tags to localized descriptions + description_i18n: { [lang_tag: string]: string }; + + // unit in which the product is measured (liters, kilograms, packages, etc.) + unit: string; + + // The price for one unit of the product. Zero is used + // to imply that this product is not sold separately, or + // that the price is not fixed, and must be supplied by the + // front-end. If non-zero, this price MUST include applicable + // taxes. + price: Amount; + + // An optional base64-encoded product image + image: ImageDataUrl; + + // a list of taxes paid by the merchant for one unit of this product + taxes: Tax[]; + + // Number of units of the product in stock in sum in total, + // including all existing sales ever. Given in product-specific + // units. + // A value of -1 indicates "infinite" (i.e. for "electronic" books). + total_stock: Integer; + + // Identifies where the product is in stock. + address: Location; + + // Identifies when we expect the next restocking to happen. + next_restock?: Timestamp; + + } + // PATCH /private/products/$PRODUCT_ID + interface ProductPatchDetail { + + // Human-readable product description. + description: string; + + // Map from IETF BCP 47 language tags to localized descriptions + description_i18n: { [lang_tag: string]: string }; + + // unit in which the product is measured (liters, kilograms, packages, etc.) + unit: string; + + // The price for one unit of the product. Zero is used + // to imply that this product is not sold separately, or + // that the price is not fixed, and must be supplied by the + // front-end. If non-zero, this price MUST include applicable + // taxes. + price: Amount; + + // An optional base64-encoded product image + image: ImageDataUrl; + + // a list of taxes paid by the merchant for one unit of this product + taxes: Tax[]; + + // Number of units of the product in stock in sum in total, + // including all existing sales ever. Given in product-specific + // units. + // A value of -1 indicates "infinite" (i.e. for "electronic" books). + total_stock: Integer; + + // Number of units of the product that were lost (spoiled, stolen, etc.) + total_lost: Integer; + + // Identifies where the product is in stock. + address: Location; + + // Identifies when we expect the next restocking to happen. + next_restock?: Timestamp; + + } + + // GET /private/products + interface InventorySummaryResponse { + // List of products that are present in the inventory + products: InventoryEntry[]; + } + interface InventoryEntry { + // Product identifier, as found in the product. + product_id: string; + + } + + // GET /private/products/$PRODUCT_ID + interface ProductDetail { + + // Human-readable product description. + description: string; + + // Map from IETF BCP 47 language tags to localized descriptions + description_i18n: { [lang_tag: string]: string }; + + // unit in which the product is measured (liters, kilograms, packages, etc.) + unit: string; + + // The price for one unit of the product. Zero is used + // to imply that this product is not sold separately, or + // that the price is not fixed, and must be supplied by the + // front-end. If non-zero, this price MUST include applicable + // taxes. + price: Amount; + + // An optional base64-encoded product image + image: ImageDataUrl; + + // a list of taxes paid by the merchant for one unit of this product + taxes: Tax[]; + + // Number of units of the product in stock in sum in total, + // including all existing sales ever. Given in product-specific + // units. + // A value of -1 indicates "infinite" (i.e. for "electronic" books). + total_stock: Integer; + + // Number of units of the product that have already been sold. + total_sold: Integer; + + // Number of units of the product that were lost (spoiled, stolen, etc.) + total_lost: Integer; + + // Identifies where the product is in stock. + address: Location; + + // Identifies when we expect the next restocking to happen. + next_restock?: Timestamp; + + } + + // POST /private/products/$PRODUCT_ID/lock + interface LockRequest { + + // UUID that identifies the frontend performing the lock + // It is suggested that clients use a timeflake for this, + // see https://github.com/anthonynsimon/timeflake + lock_uuid: UUID; + + // How long does the frontend intend to hold the lock + duration: RelativeTime; + + // How many units should be locked? + quantity: Integer; + + } + + // DELETE /private/products/$PRODUCT_ID + + } + + namespace Orders { + + type MerchantOrderStatusResponse = CheckPaymentPaidResponse | + CheckPaymentClaimedResponse | + CheckPaymentUnpaidResponse; + interface CheckPaymentPaidResponse { + // The customer paid for this contract. + order_status: "paid"; + + // Was the payment refunded (even partially)? + refunded: boolean; + + // True if there are any approved refunds that the wallet has + // not yet obtained. + refund_pending: boolean; + + // Did the exchange wire us the funds? + wired: boolean; + + // Total amount the exchange deposited into our bank account + // for this contract, excluding fees. + deposit_total: Amount; + + // Numeric error code indicating errors the exchange + // encountered tracking the wire transfer for this purchase (before + // we even got to specific coin issues). + // 0 if there were no issues. + exchange_ec: number; + + // HTTP status code returned by the exchange when we asked for + // information to track the wire transfer for this purchase. + // 0 if there were no issues. + exchange_hc: number; + + // Total amount that was refunded, 0 if refunded is false. + refund_amount: Amount; + + // Contract terms. + contract_terms: ContractTerms; + + // The wire transfer status from the exchange for this order if + // available, otherwise empty array. + wire_details: TransactionWireTransfer[]; + + // Reports about trouble obtaining wire transfer details, + // empty array if no trouble were encountered. + wire_reports: TransactionWireReport[]; + + // The refund details for this order. One entry per + // refunded coin; empty array if there are no refunds. + refund_details: RefundDetails[]; + + // Status URL, can be used as a redirect target for the browser + // to show the order QR code / trigger the wallet. + order_status_url: string; + } + interface CheckPaymentClaimedResponse { + // A wallet claimed the order, but did not yet pay for the contract. + order_status: "claimed"; + + // Contract terms. + contract_terms: ContractTerms; + + } + interface CheckPaymentUnpaidResponse { + // The order was neither claimed nor paid. + order_status: "unpaid"; + + // when was the order created + creation_time: Timestamp; + + // Order summary text. + summary: string; + + // Total amount of the order (to be paid by the customer). + total_amount: Amount; + + // URI that the wallet must process to complete the payment. + taler_pay_uri: string; + + // Alternative order ID which was paid for already in the same session. + // Only given if the same product was purchased before in the same session. + already_paid_order_id?: string; + + // Fulfillment URL of an already paid order. Only given if under this + // session an already paid order with a fulfillment URL exists. + already_paid_fulfillment_url?: string; + + // Status URL, can be used as a redirect target for the browser + // to show the order QR code / trigger the wallet. + order_status_url: string; + + // We do we NOT return the contract terms here because they may not + // exist in case the wallet did not yet claim them. + } + interface RefundDetails { + // Reason given for the refund. + reason: string; + + // When was the refund approved. + timestamp: Timestamp; + + // Total amount that was refunded (minus a refund fee). + amount: Amount; + } + interface TransactionWireTransfer { + // Responsible exchange. + exchange_url: string; + + // 32-byte wire transfer identifier. + wtid: Base32; + + // Execution time of the wire transfer. + execution_time: Timestamp; + + // Total amount that has been wire transferred + // to the merchant. + amount: Amount; + + // Was this transfer confirmed by the merchant via the + // POST /transfers API, or is it merely claimed by the exchange? + confirmed: boolean; + } + interface TransactionWireReport { + // Numerical error code. + code: number; + + // Human-readable error description. + hint: string; + + // Numerical error code from the exchange. + exchange_ec: number; + + // HTTP status code received from the exchange. + exchange_hc: number; + + // Public key of the coin for which we got the exchange error. + coin_pub: CoinPublicKey; + } + + interface OrderHistory { + // timestamp-sorted array of all orders matching the query. + // The order of the sorting depends on the sign of delta. + orders: OrderHistoryEntry[]; + } + interface OrderHistoryEntry { + + // order ID of the transaction related to this entry. + order_id: string; + + // row ID of the order in the database + row_id: number; + + // when the order was created + timestamp: Timestamp; + + // the amount of money the order is for + amount: Amount; + + // the summary of the order + summary: string; + + // whether some part of the order is refundable, + // that is the refund deadline has not yet expired + // and the total amount refunded so far is below + // the value of the original transaction. + refundable: boolean; + + // whether the order has been paid or not + paid: boolean; + } + + interface PostOrderRequest { + // The order must at least contain the minimal + // order detail, but can override all + order: Order; + + // if set, the backend will then set the refund deadline to the current + // time plus the specified delay. If it's not set, refunds will not be + // possible. + refund_delay?: RelativeTime; + + // specifies the payment target preferred by the client. Can be used + // to select among the various (active) wire methods supported by the instance. + payment_target?: string; + + // specifies that some products are to be included in the + // order from the inventory. For these inventory management + // is performed (so the products must be in stock) and + // details are completed from the product data of the backend. + inventory_products?: MinimalInventoryProduct[]; + + // Specifies a lock identifier that was used to + // lock a product in the inventory. Only useful if + // manage_inventory is set. Used in case a frontend + // reserved quantities of the individual products while + // the shopping card was being built. Multiple UUIDs can + // be used in case different UUIDs were used for different + // products (i.e. in case the user started with multiple + // shopping sessions that were combined during checkout). + lock_uuids?: UUID[]; + + // Should a token for claiming the order be generated? + // False can make sense if the ORDER_ID is sufficiently + // high entropy to prevent adversarial claims (like it is + // if the backend auto-generates one). Default is 'true'. + create_token?: boolean; + + } + type Order = MinimalOrderDetail | ContractTerms; + + interface MinimalOrderDetail { + // Amount to be paid by the customer + amount: Amount; + + // Short summary of the order + summary: string; + + // URL that will show that the order was successful after + // it has been paid for. Optional. When POSTing to the + // merchant, the placeholder "${ORDER_ID}" will be + // replaced with the actual order ID (useful if the + // order ID is generated server-side and needs to be + // in the URL). + fulfillment_url?: string; + } + + interface MinimalInventoryProduct { + // Which product is requested (here mandatory!) + product_id: string; + + // How many units of the product are requested + quantity: Integer; + } + interface PostOrderResponse { + // Order ID of the response that was just created + order_id: string; + + // Token that authorizes the wallet to claim the order. + // Provided only if "create_token" was set to 'true' + // in the request. + token?: ClaimToken; + } + interface OutOfStockResponse { + + // Product ID of an out-of-stock item + product_id: string; + + // Requested quantity + requested_quantity: Integer; + + // Available quantity (must be below requested_quanitity) + available_quantity: Integer; + + // When do we expect the product to be again in stock? + // Optional, not given if unknown. + restock_expected?: Timestamp; + } + + interface ForgetRequest { + + // Array of valid JSON paths to forgettable fields in the order's + // contract terms. + fields: string[]; + } + interface RefundRequest { + // Amount to be refunded + refund: Amount; + + // Human-readable refund justification + reason: string; + } + interface MerchantRefundResponse { + + // URL (handled by the backend) that the wallet should access to + // trigger refund processing. + // taler://refund/... + taler_refund_uri: string; + + // Contract hash that a client may need to authenticate an + // HTTP request to obtain the above URI in a wallet-friendly way. + h_contract: HashCode; + } + + } + + namespace Tips { + + // GET /private/reserves + interface TippingReserveStatus { + // Array of all known reserves (possibly empty!) + reserves: ReserveStatusEntry[]; + } + interface ReserveStatusEntry { + // Public key of the reserve + reserve_pub: EddsaPublicKey; + + // Timestamp when it was established + creation_time: Timestamp; + + // Timestamp when it expires + expiration_time: Timestamp; + + // Initial amount as per reserve creation call + merchant_initial_amount: Amount; + + // Initial amount as per exchange, 0 if exchange did + // not confirm reserve creation yet. + exchange_initial_amount: Amount; + + // Amount picked up so far. + pickup_amount: Amount; + + // Amount approved for tips that exceeds the pickup_amount. + committed_amount: Amount; + + // Is this reserve active (false if it was deleted but not purged) + active: boolean; + } + + interface ReserveCreateRequest { + // Amount that the merchant promises to put into the reserve + initial_balance: Amount; + + // Exchange the merchant intends to use for tipping + exchange_url: string; + + // Desired wire method, for example "iban" or "x-taler-bank" + wire_method: string; + } + interface ReserveCreateConfirmation { + // Public key identifying the reserve + reserve_pub: EddsaPublicKey; + + // Wire account of the exchange where to transfer the funds + payto_uri: string; + } + interface TipCreateRequest { + // Amount that the customer should be tipped + amount: Amount; + + // Justification for giving the tip + justification: string; + + // URL that the user should be directed to after tipping, + // will be included in the tip_token. + next_url: string; + } + interface TipCreateConfirmation { + // Unique tip identifier for the tip that was created. + tip_id: HashCode; + + // taler://tip URI for the tip + taler_tip_uri: string; + + // URL that will directly trigger processing + // the tip when the browser is redirected to it + tip_status_url: string; + + // when does the tip expire + tip_expiration: Timestamp; + } + + interface ReserveDetail { + // Timestamp when it was established. + creation_time: Timestamp; + + // Timestamp when it expires. + expiration_time: Timestamp; + + // Initial amount as per reserve creation call. + merchant_initial_amount: Amount; + + // Initial amount as per exchange, 0 if exchange did + // not confirm reserve creation yet. + exchange_initial_amount: Amount; + + // Amount picked up so far. + pickup_amount: Amount; + + // Amount approved for tips that exceeds the pickup_amount. + committed_amount: Amount; + + // Array of all tips created by this reserves (possibly empty!). + // Only present if asked for explicitly. + tips?: TipStatusEntry[]; + + // Is this reserve active (false if it was deleted but not purged)? + active: boolean; + + // URI to use to fill the reserve, can be NULL + // if the reserve is inactive or was already filled + payto_uri: string; + + // URL of the exchange hosting the reserve, + // NULL if the reserve is inactive + exchange_url: string; + + } + + interface TipStatusEntry { + + // Unique identifier for the tip. + tip_id: HashCode; + + // Total amount of the tip that can be withdrawn. + total_amount: Amount; + + // Human-readable reason for why the tip was granted. + reason: string; + } + + interface TipDetails { + // Amount that we authorized for this tip. + total_authorized: Amount; + + // Amount that was picked up by the user already. + total_picked_up: Amount; + + // Human-readable reason given when authorizing the tip. + reason: string; + + // Timestamp indicating when the tip is set to expire (may be in the past). + expiration: Timestamp; + + // Reserve public key from which the tip is funded. + reserve_pub: EddsaPublicKey; + + // Array showing the pickup operations of the wallet (possibly empty!). + // Only present if asked for explicitly. + pickups?: PickupDetail[]; + } + interface PickupDetail { + // Unique identifier for the pickup operation. + pickup_id: HashCode; + + // Number of planchets involved. + num_planchets: Integer; + + // Total amount requested for this pickup_id. + requested_amount: Amount; + } + + } + + namespace Transfers { + + interface TransferList { + // list of all the transfers that fit the filter that we know + transfers: TransferDetails[]; + } + interface TransferDetails { + // how much was wired to the merchant (minus fees) + credit_amount: Amount; + + // raw wire transfer identifier identifying the wire transfer (a base32-encoded value) + wtid: string; + + // target account that received the wire transfer + payto_uri: string; + + // base URL of the exchange that made the wire transfer + exchange_url: string; + + // Serial number identifying the transfer in the merchant backend. + // Used for filgering via offset. + transfer_serial_id: number; + + // Time of the execution of the wire transfer by the exchange, according to the exchange + // Only provided if we did get an answer from the exchange. + execution_time?: Timestamp; + + // True if we checked the exchange's answer and are happy with it. + // False if we have an answer and are unhappy, missing if we + // do not have an answer from the exchange. + verified?: boolean; + + // True if the merchant uses the POST /transfers API to confirm + // that this wire transfer took place (and it is thus not + // something merely claimed by the exchange). + confirmed?: boolean; + } + + interface TransferInformation { + // how much was wired to the merchant (minus fees) + credit_amount: Amount; + + // raw wire transfer identifier identifying the wire transfer (a base32-encoded value) + wtid: WireTransferIdentifierRawP; + + // target account that received the wire transfer + payto_uri: string; + + // base URL of the exchange that made the wire transfer + exchange_url: string; + } + interface MerchantTrackTransferResponse { + // Total amount transferred + total: Amount; + + // Applicable wire fee that was charged + wire_fee: Amount; + + // Time of the execution of the wire transfer by the exchange, according to the exchange + execution_time: Timestamp; + + // details about the deposits + deposits_sums: MerchantTrackTransferDetail[]; + } + interface MerchantTrackTransferDetail { + // Business activity associated with the wire transferred amount + // deposit_value. + order_id: string; + + // The total amount the exchange paid back for order_id. + deposit_value: Amount; + + // applicable fees for the deposit + deposit_fee: Amount; + } + + type ExchangeConflictDetails = WireFeeConflictDetails | TrackTransferConflictDetails + // Note: this is not the full 'proof' of missbehavior, as + // the bogus message from the exchange with a signature + // over the 'different' wire fee is missing. + // + // This information is NOT provided by the current implementation, + // because this would be quite expensive to generate and is + // hardly needed _here_. Once we add automated reports for + // the Taler auditor, we need to generate this data anyway + // and should probably return it here as well. + interface WireFeeConflictDetails { + // Numerical error code: + code: "TALER_EC_MERCHANT_PRIVATE_POST_TRANSFERS_BAD_WIRE_FEE"; + + // Text describing the issue for humans. + hint: string; + + + // Wire fee (wrongly) charged by the exchange, breaking the + // contract affirmed by the exchange_sig. + wire_fee: Amount; + + // Timestamp of the wire transfer + execution_time: Timestamp; + + // The expected wire fee (as signed by the exchange) + expected_wire_fee: Amount; + + // Expected closing fee (needed to verify signature) + expected_closing_fee: Amount; + + // Start date of the expected fee structure + start_date: Timestamp; + + // End date of the expected fee structure + end_date: Timestamp; + + // Signature of the exchange affirming the expected fee structure + master_sig: EddsaSignature; + + // Master public key of the exchange + master_pub: EddsaPublicKey; + } + interface TrackTransferConflictDetails { + // Numerical error code + code: "TALER_EC_MERCHANT_PRIVATE_POST_TRANSFERS_CONFLICTING_REPORTS"; + + // Text describing the issue for humans. + hint: string; + + // Offset in the exchange_transfer where the + // exchange's response fails to match the exchange_deposit_proof. + conflict_offset: number; + + // The response from the exchange which tells us when the + // coin was returned to us, except that it does not match + // the expected value of the coin. + // + // This field is NOT provided by the current implementation, + // because this would be quite expensive to generate and is + // hardly needed _here_. Once we add automated reports for + // the Taler auditor, we need to generate this data anyway + // and should probably return it here as well. + // exchange_transfer?: TrackTransferResponse; + + // Public key of the exchange used to sign the response to + // our deposit request. + deposit_exchange_pub: EddsaPublicKey; + + // Signature of the exchange signing the (conflicting) response. + // Signs over a struct TALER_DepositConfirmationPS. + deposit_exchange_sig: EddsaSignature; + + // Hash of the merchant's bank account the wire transfer went to + h_wire: HashCode; + + // Hash of the contract terms with the conflicting deposit. + h_contract_terms: HashCode; + + // At what time the exchange received the deposit. Needed + // to verify the \exchange_sig\. + deposit_timestamp: Timestamp; + + // At what time the refund possibility expired (needed to verify exchange_sig). + refund_deadline: Timestamp; + + // Public key of the coin for which we have conflicting information. + coin_pub: EddsaPublicKey; + + // Amount the exchange counted the coin for in the transfer. + amount_with_fee: Amount; + + // Expected value of the coin. + coin_value: Amount; + + // Expected deposit fee of the coin. + coin_fee: Amount; + + // Expected deposit fee of the coin. + deposit_fee: Amount; + + } + + // interface TrackTransferProof { + // // signature from the exchange made with purpose + // // TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT + // exchange_sig: EddsaSignature; + + // // public EdDSA key of the exchange that was used to generate the signature. + // // Should match one of the exchange's signing keys from /keys. Again given + // // explicitly as the client might otherwise be confused by clock skew as to + // // which signing key was used. + // exchange_pub: EddsaSignature; + + // // hash of the wire details (identical for all deposits) + // // Needed to check the exchange_sig + // h_wire: HashCode; + // } + + } + + + interface ContractTerms { + // Human-readable description of the whole purchase + summary: string; + + // Map from IETF BCP 47 language tags to localized summaries + summary_i18n?: { [lang_tag: string]: string }; + + // Unique, free-form identifier for the proposal. + // Must be unique within a merchant instance. + // For merchants that do not store proposals in their DB + // before the customer paid for them, the order_id can be used + // by the frontend to restore a proposal from the information + // encoded in it (such as a short product identifier and timestamp). + order_id: string; + + // Total price for the transaction. + // The exchange will subtract deposit fees from that amount + // before transferring it to the merchant. + amount: Amount; + + // The URL for this purchase. Every time is is visited, the merchant + // will send back to the customer the same proposal. Clearly, this URL + // can be bookmarked and shared by users. + fulfillment_url?: string; + + // Maximum total deposit fee accepted by the merchant for this contract + max_fee: Amount; + + // Maximum wire fee accepted by the merchant (customer share to be + // divided by the 'wire_fee_amortization' factor, and further reduced + // if deposit fees are below 'max_fee'). Default if missing is zero. + max_wire_fee: Amount; + + // Over how many customer transactions does the merchant expect to + // amortize wire fees on average? If the exchange's wire fee is + // above 'max_wire_fee', the difference is divided by this number + // to compute the expected customer's contribution to the wire fee. + // The customer's contribution may further be reduced by the difference + // between the 'max_fee' and the sum of the actual deposit fees. + // Optional, default value if missing is 1. 0 and negative values are + // invalid and also interpreted as 1. + wire_fee_amortization: number; + + // List of products that are part of the purchase (see Product). + products: Product[]; + + // Time when this contract was generated + timestamp: Timestamp; + + // After this deadline has passed, no refunds will be accepted. + refund_deadline: Timestamp; + + // After this deadline, the merchant won't accept payments for the contact + pay_deadline: Timestamp; + + // Transfer deadline for the exchange. Must be in the + // deposit permissions of coins used to pay for this order. + wire_transfer_deadline: Timestamp; + + // Merchant's public key used to sign this proposal; this information + // is typically added by the backend Note that this can be an ephemeral key. + merchant_pub: EddsaPublicKey; + + // Base URL of the (public!) merchant backend API. + // Must be an absolute URL that ends with a slash. + merchant_base_url: string; + + // More info about the merchant, see below + merchant: Merchant; + + // The hash of the merchant instance's wire details. + h_wire: HashCode; + + // Wire transfer method identifier for the wire method associated with h_wire. + // The wallet may only select exchanges via a matching auditor if the + // exchange also supports this wire method. + // The wire transfer fees must be added based on this wire transfer method. + wire_method: string; + + // Any exchanges audited by these auditors are accepted by the merchant. + auditors: Auditor[]; + + // Exchanges that the merchant accepts even if it does not accept any auditors that audit them. + exchanges: Exchange[]; + + // Delivery location for (all!) products. + delivery_location?: Location; + + // Time indicating when the order should be delivered. + // May be overwritten by individual products. + delivery_date?: Timestamp; + + // Nonce generated by the wallet and echoed by the merchant + // in this field when the proposal is generated. + nonce: string; + + // Specifies for how long the wallet should try to get an + // automatic refund for the purchase. If this field is + // present, the wallet should wait for a few seconds after + // the purchase and then automatically attempt to obtain + // a refund. The wallet should probe until "delay" + // after the payment was successful (i.e. via long polling + // or via explicit requests with exponential back-off). + // + // In particular, if the wallet is offline + // at that time, it MUST repeat the request until it gets + // one response from the merchant after the delay has expired. + // If the refund is granted, the wallet MUST automatically + // recover the payment. This is used in case a merchant + // knows that it might be unable to satisfy the contract and + // desires for the wallet to attempt to get the refund without any + // customer interaction. Note that it is NOT an error if the + // merchant does not grant a refund. + auto_refund?: RelativeTime; + + // Extra data that is only interpreted by the merchant frontend. + // Useful when the merchant needs to store extra information on a + // contract without storing it separately in their database. + extra?: any; + } + +} diff --git a/packages/backend/src/hooks/async.ts b/packages/backend/src/hooks/async.ts new file mode 100644 index 0000000..fd55004 --- /dev/null +++ b/packages/backend/src/hooks/async.ts @@ -0,0 +1,76 @@ +/* + 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 { useState } from "preact/hooks"; +import { cancelPendingRequest } from "./backend"; + +export interface Options { + slowTolerance: number, +} + +export interface AsyncOperationApi<T> { + request: (...a: any) => void, + cancel: () => void, + data: T | undefined, + isSlow: boolean, + isLoading: boolean, + error: string | undefined +} + +export function useAsync<T>(fn?: (...args: any) => Promise<T>, { slowTolerance: tooLong }: Options = { slowTolerance: 1000 }): AsyncOperationApi<T> { + const [data, setData] = useState<T | undefined>(undefined); + const [isLoading, setLoading] = useState<boolean>(false); + const [error, setError] = useState<any>(undefined); + const [isSlow, setSlow] = useState(false) + + const request = async (...args: any) => { + if (!fn) return; + setLoading(true); + + const handler = setTimeout(() => { + setSlow(true) + }, tooLong) + + try { + const result = await fn(...args); + setData(result); + } catch (error) { + setError(error); + } + setLoading(false); + setSlow(false) + clearTimeout(handler) + }; + + function cancel() { + cancelPendingRequest() + setLoading(false); + setSlow(false) + } + + return { + request, + cancel, + data, + isSlow, + isLoading, + error + }; +} diff --git a/packages/backend/src/hooks/backend.ts b/packages/backend/src/hooks/backend.ts new file mode 100644 index 0000000..96b8f71 --- /dev/null +++ b/packages/backend/src/hooks/backend.ts @@ -0,0 +1,262 @@ +/* + 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 { mutate, cache } from 'swr'; +import axios, { AxiosError, AxiosResponse } from 'axios' +import { MerchantBackend } from '../declaration'; +import { useBackendContext } from '../context/backend'; +import { useEffect, useState } from 'preact/hooks'; +import { DEFAULT_REQUEST_TIMEOUT } from '../utils/constants'; + +export function mutateAll(re: RegExp, value?: unknown): Array<Promise<any>> { + return cache.keys().filter(key => { + return re.test(key) + }).map(key => { + return mutate(key, value) + }) +} + +export type HttpResponse<T> = HttpResponseOk<T> | HttpResponseLoading<T> | HttpError; +export type HttpResponsePaginated<T> = HttpResponseOkPaginated<T> | HttpResponseLoading<T> | HttpError; + +export interface RequestInfo { + url: string; + hasToken: boolean; + params: unknown; + data: unknown; +} + +interface HttpResponseLoading<T> { + ok?: false; + loading: true; + clientError?: false; + serverError?: false; + + data?: T; +} +export interface HttpResponseOk<T> { + ok: true; + loading?: false; + clientError?: false; + serverError?: false; + + data: T; + info?: RequestInfo; +} + +export type HttpResponseOkPaginated<T> = HttpResponseOk<T> & WithPagination + +export interface WithPagination { + loadMore: () => void; + loadMorePrev: () => void; + isReachingEnd?: boolean; + isReachingStart?: boolean; +} + +export type HttpError = HttpResponseClientError | HttpResponseServerError | HttpResponseUnexpectedError; +export interface SwrError { + info: unknown, + status: number, + message: string, +} +export interface HttpResponseServerError { + ok?: false; + loading?: false; + clientError?: false; + serverError: true; + + error?: MerchantBackend.ErrorDetail; + status: number; + message: string; + info?: RequestInfo; +} +interface HttpResponseClientError { + ok?: false; + loading?: false; + clientError: true; + serverError?: false; + + info?: RequestInfo; + isUnauthorized: boolean; + isNotfound: boolean; + status: number; + error?: MerchantBackend.ErrorDetail; + message: string; + +} + +interface HttpResponseUnexpectedError { + ok?: false; + loading?: false; + clientError?: false; + serverError?: false; + + info?: RequestInfo; + status?: number; + error: unknown; + message: string; +} + +type Methods = 'get' | 'post' | 'patch' | 'delete' | 'put'; + +interface RequestOptions { + method?: Methods; + token?: string; + data?: unknown; + params?: unknown; +} + +function buildRequestOk<T>(res: AxiosResponse<T>, url: string, hasToken: boolean): HttpResponseOk<T> { + return { + ok: true, data: res.data, info: { + params: res.config.params, + data: res.config.data, + url, + hasToken, + } + } +} + +// function buildResponse<T>(data?: T, error?: MerchantBackend.ErrorDetail, isValidating?: boolean): HttpResponse<T> { +// if (isValidating) return {loading: true} +// if (error) return buildRequestFailed() +// } + +function buildRequestFailed(ex: AxiosError<MerchantBackend.ErrorDetail>, url: string, hasToken: boolean): HttpResponseClientError | HttpResponseServerError | HttpResponseUnexpectedError { + const status = ex.response?.status + + const info: RequestInfo = { + data: ex.request?.data, + params: ex.request?.params, + url, + hasToken, + }; + + if (status && status >= 400 && status < 500) { + const error: HttpResponseClientError = { + clientError: true, + isNotfound: status === 404, + isUnauthorized: status === 401, + status, + info, + message: ex.response?.data?.hint || ex.message, + error: ex.response?.data + } + return error + } + if (status && status >= 500 && status < 600) { + const error: HttpResponseServerError = { + serverError: true, + status, + info, + message: `${ex.response?.data?.hint} (code ${ex.response?.data?.code})` || ex.message, + error: ex.response?.data + } + return error; + } + + const error: HttpResponseUnexpectedError = { + info, + status, + error: ex, + message: ex.message + } + + return error +} + + +const CancelToken = axios.CancelToken; +let source = CancelToken.source(); + +export function cancelPendingRequest() { + source.cancel('canceled by the user') + source = CancelToken.source() +} + +let removeAxiosCancelToken = false +/** + * Jest mocking seems to break when using the cancelToken property. + * Using this workaround when testing while finding the correct solution + */ +export function setAxiosRequestAsTestingEnvironment() { + removeAxiosCancelToken = true +} + +export async function request<T>(url: string, options: RequestOptions = {}): Promise<HttpResponseOk<T>> { + const headers = options.token ? { Authorization: `Bearer ${options.token}` } : undefined + + try { + const res = await axios({ + url, + responseType: 'json', + headers, + cancelToken: !removeAxiosCancelToken? source.token : undefined, + method: options.method || 'get', + data: options.data, + params: options.params, + timeout: DEFAULT_REQUEST_TIMEOUT * 1000, + }) + return buildRequestOk<T>(res, url, !!options.token) + } catch (e) { + const error = buildRequestFailed(e, url, !!options.token) + throw error + } + +} + +export function fetcher<T>(url: string, token: string, backend: string): Promise<HttpResponseOk<T>> { + return request<T>(`${backend}${url}`, { token }) +} + +export function useBackendInstancesTestForAdmin(): HttpResponse<MerchantBackend.Instances.InstancesResponse> { + const { url, token } = useBackendContext() + + type Type = MerchantBackend.Instances.InstancesResponse; + + const [result, setResult] = useState<HttpResponse<Type>>({ loading: true }) + + useEffect(() => { + request<Type>(`${url}/management/instances`, { token }) + .then(data => setResult(data)) + .catch(error => setResult(error)) + }, [url, token]) + + + return result +} + + +export function useBackendConfig(): HttpResponse<MerchantBackend.VersionResponse> { + const { url, token } = useBackendContext() + + type Type = MerchantBackend.VersionResponse; + + const [result, setResult] = useState<HttpResponse<Type>>({ loading: true }) + + useEffect(() => { + request<Type>(`${url}/config`, { token }) + .then(data => setResult(data)) + .catch(error => setResult(error)) + }, [url, token]) + + return result +} diff --git a/packages/backend/src/hooks/index.ts b/packages/backend/src/hooks/index.ts new file mode 100644 index 0000000..19d672a --- /dev/null +++ b/packages/backend/src/hooks/index.ts @@ -0,0 +1,110 @@ +/* + 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 { StateUpdater, useCallback, useState } from "preact/hooks"; +import { ValueOrFunction } from '../utils/types'; + + +const calculateRootPath = () => { + const rootPath = typeof window !== undefined ? window.location.origin + window.location.pathname : '/' + return rootPath +} + +export function useBackendURL(url?: string): [string, boolean, StateUpdater<string>, () => void] { + const [value, setter] = useNotNullLocalStorage('backend-url', url || calculateRootPath()) + const [triedToLog, setTriedToLog] = useLocalStorage('tried-login') + + const checkedSetter = (v: ValueOrFunction<string>) => { + setTriedToLog('yes') + return setter(p => (v instanceof Function ? v(p) : v).replace(/\/$/, '')) + } + + const resetBackend = () => { + setTriedToLog(undefined) + } + return [value, !!triedToLog, checkedSetter, resetBackend] +} + +export function useBackendDefaultToken(): [string | undefined, StateUpdater<string | undefined>] { + return useLocalStorage('backend-token') +} + +export function useBackendInstanceToken(id: string): [string | undefined, StateUpdater<string | undefined>] { + const [token, setToken] = useLocalStorage(`backend-token-${id}`) + const [defaultToken, defaultSetToken] = useBackendDefaultToken() + + // instance named 'default' use the default token + if (id === 'default') { + return [defaultToken, defaultSetToken] + } + + return [token, setToken] +} + +export function useLang(initial?: string): [string, StateUpdater<string>] { + const browserLang = typeof window !== "undefined" ? navigator.language || (navigator as any).userLanguage : undefined; + const defaultLang = (browserLang || initial || 'en').substring(0, 2) + return useNotNullLocalStorage('lang-preference', defaultLang) +} + +export function useLocalStorage(key: string, initialValue?: string): [string | undefined, StateUpdater<string | undefined>] { + const [storedValue, setStoredValue] = useState<string | undefined>((): string | undefined => { + return typeof window !== "undefined" ? window.localStorage.getItem(key) || initialValue : initialValue; + }); + + const setValue = (value?: string | ((val?: string) => string | undefined)) => { + setStoredValue(p => { + const toStore = value instanceof Function ? value(p) : value + if (typeof window !== "undefined") { + if (!toStore) { + window.localStorage.removeItem(key) + } else { + window.localStorage.setItem(key, toStore); + } + } + return toStore + }) + }; + + return [storedValue, setValue]; +} + +export function useNotNullLocalStorage(key: string, initialValue: string): [string, StateUpdater<string>] { + const [storedValue, setStoredValue] = useState<string>((): string => { + return typeof window !== "undefined" ? window.localStorage.getItem(key) || initialValue : initialValue; + }); + + const setValue = (value: string | ((val: string) => string)) => { + const valueToStore = value instanceof Function ? value(storedValue) : value; + setStoredValue(valueToStore); + if (typeof window !== "undefined") { + if (!valueToStore) { + window.localStorage.removeItem(key) + } else { + window.localStorage.setItem(key, valueToStore); + } + } + }; + + return [storedValue, setValue]; +} + + diff --git a/packages/backend/src/hooks/instance.ts b/packages/backend/src/hooks/instance.ts new file mode 100644 index 0000000..14ab8de --- /dev/null +++ b/packages/backend/src/hooks/instance.ts @@ -0,0 +1,187 @@ +/* + 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 { MerchantBackend } from '../declaration'; +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 { + updateInstance: (data: MerchantBackend.Instances.InstanceReconfigurationMessage) => Promise<void>; + deleteInstance: () => Promise<void>; + clearToken: () => Promise<void>; + setNewToken: (token: string) => Promise<void>; +} + +export function useManagementAPI(instanceId: string) : InstanceAPI { + const { url, token } = useBackendContext() + + const updateInstance = async (instance: MerchantBackend.Instances.InstanceReconfigurationMessage): Promise<void> => { + await request(`${url}/management/instances/${instanceId}`, { + method: 'patch', + token, + data: instance + }) + + mutate([`/private/`, token, url], null) + }; + + const deleteInstance = async (): Promise<void> => { + await request(`${url}/management/instances/${instanceId}`, { + method: 'delete', + token, + }) + + mutate([`/private/`, token, url], null) + } + + const clearToken = async (): Promise<void> => { + await request(`${url}/management/instances/${instanceId}/auth`, { + method: 'post', + token, + data: { method: 'external' } + }) + + mutate([`/private/`, token, url], null) + } + + const setNewToken = async (newToken: string): Promise<void> => { + await request(`${url}/management/instances/${instanceId}/auth`, { + method: 'post', + token, + data: { method: 'token', token: newToken } + }) + + mutate([`/private/`, token, url], null) + } + + return { updateInstance, deleteInstance, setNewToken, clearToken } +} + +export function useInstanceAPI(): InstanceAPI { + const { url: baseUrl, token: adminToken } = useBackendContext() + const { token: instanceToken, id, admin } = useInstanceContext() + + const { url, token } = !admin ? { + url: baseUrl, token: adminToken + } : { + url: `${baseUrl}/instances/${id}`, token: instanceToken + }; + + const updateInstance = async (instance: MerchantBackend.Instances.InstanceReconfigurationMessage): Promise<void> => { + await request(`${url}/private/`, { + method: 'patch', + token, + data: instance + }) + + if (adminToken) mutate(['/private/instances', adminToken, baseUrl], null) + mutate([`/private/`, token, url], null) + }; + + const deleteInstance = async (): Promise<void> => { + await request(`${url}/private/`, { + method: 'delete', + token: adminToken, + }) + + if (adminToken) mutate(['/private/instances', adminToken, baseUrl], null) + mutate([`/private/`, token, url], null) + } + + const clearToken = async (): Promise<void> => { + await request(`${url}/private/auth`, { + method: 'post', + token, + data: { method: 'external' } + }) + + mutate([`/private/`, token, url], null) + } + + const setNewToken = async (newToken: string): Promise<void> => { + await request(`${url}/private/auth`, { + method: 'post', + token, + data: { method: 'token', token: newToken } + }) + + mutate([`/private/`, token, url], null) + } + + return { updateInstance, deleteInstance, setNewToken, clearToken } +} + + +export function useInstanceDetails(): HttpResponse<MerchantBackend.Instances.QueryInstancesResponse> { + const { url: baseUrl, token: baseToken } = useBackendContext(); + const { token: instanceToken, id, admin } = useInstanceContext(); + + const { url, token } = !admin ? { + url: baseUrl, token: baseToken + } : { + url: `${baseUrl}/instances/${id}`, token: instanceToken + } + + const { data, error, isValidating } = useSWR<HttpResponseOk<MerchantBackend.Instances.QueryInstancesResponse>, HttpError>([`/private/`, token, url], fetcher, { + refreshInterval:0, + refreshWhenHidden: false, + revalidateOnFocus: false, + revalidateOnReconnect: false, + refreshWhenOffline: false, + errorRetryCount: 0, + errorRetryInterval: 1, + shouldRetryOnError: false, + }) + + if (isValidating) return {loading:true, data: data?.data} + if (data) return data + if (error) return error + return {loading: true} +} + +export function useManagedInstanceDetails(instanceId: string): HttpResponse<MerchantBackend.Instances.QueryInstancesResponse> { + const { url, token } = useBackendContext(); + + const { data, error, isValidating } = useSWR<HttpResponseOk<MerchantBackend.Instances.QueryInstancesResponse>, HttpError>([`/management/instances/${instanceId}`, token, url], fetcher, { + refreshInterval:0, + refreshWhenHidden: false, + revalidateOnFocus: false, + revalidateOnReconnect: false, + refreshWhenOffline: false, + errorRetryCount: 0, + errorRetryInterval: 1, + shouldRetryOnError: false, + }) + + if (isValidating) return {loading:true, data: data?.data} + if (data) return data + if (error) return error + return {loading: true} +} + +export function useBackendInstances(): HttpResponse<MerchantBackend.Instances.InstancesResponse> { + const { url } = useBackendContext() + const { token } = useInstanceContext(); + + const { data, error, isValidating } = useSWR<HttpResponseOk<MerchantBackend.Instances.InstancesResponse>, HttpError>(['/management/instances', token, url], fetcher) + + if (isValidating) return {loading:true, data: data?.data} + if (data) return data + if (error) return error + return {loading: true} +} diff --git a/packages/backend/src/hooks/listener.ts b/packages/backend/src/hooks/listener.ts new file mode 100644 index 0000000..231ed6c --- /dev/null +++ b/packages/backend/src/hooks/listener.ts @@ -0,0 +1,68 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +import { useState } from "preact/hooks"; + +/** + * returns subscriber and activator + * subscriber will receive a method (listener) that will be call when the activator runs. + * the result of calling the listener will be sent to @action + * + * @param action from <T> to <R> + * @returns activator and subscriber, undefined activator means that there is not subscriber + */ + +export function useListener<T, R = any>(action: (r: T) => Promise<R>): [undefined | (() => Promise<R>), (listener?: () => T) => void] { + type RunnerHandler = { toBeRan?: () => Promise<R>; }; + const [state, setState] = useState<RunnerHandler>({}); + + /** + * subscriber will receive a method that will be call when the activator runs + * + * @param listener function to be run when the activator runs + */ + const subscriber = (listener?: () => T) => { + if (listener) { + setState({ + toBeRan: () => { + const whatWeGetFromTheListener = listener(); + return action(whatWeGetFromTheListener); + } + }); + } else { + setState({ + toBeRan: undefined + }) + } + }; + + /** + * activator will call runner if there is someone subscribed + */ + const activator = state.toBeRan ? async () => { + if (state.toBeRan) { + return state.toBeRan(); + } + return Promise.reject(); + } : undefined; + + return [activator, subscriber]; +} diff --git a/packages/backend/src/hooks/notification.ts b/packages/backend/src/hooks/notification.ts new file mode 100644 index 0000000..d1dfbff --- /dev/null +++ b/packages/backend/src/hooks/notification.ts @@ -0,0 +1,43 @@ +/* + 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 { useCallback, useState } from "preact/hooks"; +import { Notification } from '../utils/types'; + +interface Result { + notification?: Notification; + pushNotification: (n: Notification) => void; + removeNotification: () => void; +} + +export function useNotification(): Result { + const [notification, setNotifications] = useState<Notification|undefined>(undefined) + + const pushNotification = useCallback((n: Notification): void => { + setNotifications(n) + },[]) + + const removeNotification = useCallback(() => { + setNotifications(undefined) + },[]) + + return { notification, pushNotification, removeNotification } +} diff --git a/packages/backend/src/hooks/notifications.ts b/packages/backend/src/hooks/notifications.ts new file mode 100644 index 0000000..1c0c373 --- /dev/null +++ b/packages/backend/src/hooks/notifications.ts @@ -0,0 +1,48 @@ +/* + 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 { useState } from "preact/hooks"; +import { Notification } from '../utils/types'; + +interface Result { + notifications: Notification[]; + pushNotification: (n: Notification) => void; + removeNotification: (n: Notification) => void; +} + +type NotificationWithDate = Notification & { since: Date } + +export function useNotifications(initial: Notification[] = [], timeout = 3000): Result { + const [notifications, setNotifications] = useState<(NotificationWithDate)[]>(initial.map(i => ({...i, since: new Date() }))) + + const pushNotification = (n: Notification): void => { + const entry = { ...n, since: new Date() } + setNotifications(ns => [...ns, entry]) + if (n.type !== 'ERROR') setTimeout(() => { + setNotifications(ns => ns.filter(x => x.since !== entry.since)) + }, timeout) + } + + const removeNotification = (notif: Notification) => { + setNotifications((ns: NotificationWithDate[]) => ns.filter(n => n !== notif)) + } + return { notifications, pushNotification, removeNotification } +} diff --git a/packages/backend/src/hooks/order.ts b/packages/backend/src/hooks/order.ts new file mode 100644 index 0000000..a0d7916 --- /dev/null +++ b/packages/backend/src/hooks/order.ts @@ -0,0 +1,217 @@ +/* + 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 { useEffect, useState } from 'preact/hooks'; +import useSWR from 'swr'; +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'; + +export interface OrderAPI { + //FIXME: add OutOfStockResponse on 410 + createOrder: (data: MerchantBackend.Orders.PostOrderRequest) => Promise<HttpResponseOk<MerchantBackend.Orders.PostOrderResponse>>; + forgetOrder: (id: string, data: MerchantBackend.Orders.ForgetRequest) => Promise<HttpResponseOk<void>>; + refundOrder: (id: string, data: MerchantBackend.Orders.RefundRequest) => Promise<HttpResponseOk<MerchantBackend.Orders.MerchantRefundResponse>>; + deleteOrder: (id: string) => Promise<HttpResponseOk<void>>; + getPaymentURL: (id: string) => Promise<HttpResponseOk<string>>; +} + +type YesOrNo = 'yes' | 'no'; + + +export function orderFetcher<T>(url: string, token: string, backend: string, paid?: YesOrNo, refunded?: YesOrNo, wired?: YesOrNo, searchDate?: Date, delta?: number): Promise<HttpResponseOk<T>> { + const date_ms = delta && delta < 0 && searchDate ? searchDate.getTime() + 1 : searchDate?.getTime() + const params: any = {} + if (paid !== undefined) params.paid = paid + if (delta !== undefined) params.delta = delta + if (refunded !== undefined) params.refunded = refunded + if (wired !== undefined) params.wired = wired + if (date_ms !== undefined) params.date_ms = date_ms + return request<T>(`${backend}${url}`, { token, params }) +} + + +export function useOrderAPI(): OrderAPI { + const { url: baseUrl, token: adminToken } = useBackendContext() + const { token: instanceToken, id, admin } = useInstanceContext() + + const { url, token } = !admin ? { + url: baseUrl, token: adminToken + } : { + url: `${baseUrl}/instances/${id}`, token: instanceToken + } + + const createOrder = async (data: MerchantBackend.Orders.PostOrderRequest): Promise<HttpResponseOk<MerchantBackend.Orders.PostOrderResponse>> => { + const res = await request<MerchantBackend.Orders.PostOrderResponse>(`${url}/private/orders`, { + method: 'post', + token, + data + }) + await mutateAll(/@"\/private\/orders"@/) + return res + } + const refundOrder = async (orderId: string, data: MerchantBackend.Orders.RefundRequest): Promise<HttpResponseOk<MerchantBackend.Orders.MerchantRefundResponse>> => { + mutateAll(/@"\/private\/orders"@/) + return request<MerchantBackend.Orders.MerchantRefundResponse>(`${url}/private/orders/${orderId}/refund`, { + method: 'post', + token, + data + }) + + // return res + } + + const forgetOrder = async (orderId: string, data: MerchantBackend.Orders.ForgetRequest): Promise<HttpResponseOk<void>> => { + mutateAll(/@"\/private\/orders"@/) + return request(`${url}/private/orders/${orderId}/forget`, { + method: 'patch', + token, + data + }) + + } + const deleteOrder = async (orderId: string): Promise<HttpResponseOk<void>> => { + mutateAll(/@"\/private\/orders"@/) + return request(`${url}/private/orders/${orderId}`, { + method: 'delete', + token + }) + } + + const getPaymentURL = async (orderId: string): Promise<HttpResponseOk<string>> => { + return request<MerchantBackend.Orders.MerchantOrderStatusResponse>(`${url}/private/orders/${orderId}`, { + method: 'get', + token + }).then((res) => { + const url = res.data.order_status === "unpaid" ? res.data.taler_pay_uri : res.data.contract_terms.fulfillment_url + const response: HttpResponseOk<string> = res as any + response.data = url || '' + return response + }) + } + + return { createOrder, forgetOrder, deleteOrder, refundOrder, getPaymentURL } +} + +export function useOrderDetails(oderId: string): HttpResponse<MerchantBackend.Orders.MerchantOrderStatusResponse> { + const { url: baseUrl, token: baseToken } = useBackendContext(); + const { token: instanceToken, id, admin } = useInstanceContext(); + + const { url, token } = !admin ? { + url: baseUrl, token: baseToken + } : { + url: `${baseUrl}/instances/${id}`, token: instanceToken + }; + + const { data, error, isValidating } = useSWR<HttpResponseOk<MerchantBackend.Orders.MerchantOrderStatusResponse>, HttpError>([`/private/orders/${oderId}`, token, url], fetcher, { + refreshInterval:0, + refreshWhenHidden: false, + revalidateOnFocus: false, + revalidateOnReconnect: false, + refreshWhenOffline: false, + }) + + if (isValidating) return { loading: true, data: data?.data } + if (data) return data + if (error) return error + return { loading: true } +} + +export interface InstanceOrderFilter { + paid?: YesOrNo; + refunded?: YesOrNo; + wired?: YesOrNo; + date?: Date; +} + +export function useInstanceOrders(args?: InstanceOrderFilter, updateFilter?: (d: Date) => void): HttpResponsePaginated<MerchantBackend.Orders.OrderHistory> { + const { url: baseUrl, token: baseToken } = useBackendContext(); + const { token: instanceToken, id, admin } = useInstanceContext(); + + const { url, token } = !admin ? { + url: baseUrl, token: baseToken + } : { + url: `${baseUrl}/instances/${id}`, token: instanceToken + } + + const [pageBefore, setPageBefore] = useState(1) + const [pageAfter, setPageAfter] = useState(1) + + const totalAfter = pageAfter * PAGE_SIZE; + const totalBefore = args?.date ? pageBefore * PAGE_SIZE : 0; + + /** + * FIXME: this can be cleaned up a little + * + * the logic of double query should be inside the orderFetch so from the hook perspective and cache + * is just one query and one error status + */ + const { data: beforeData, error: beforeError, isValidating: loadingBefore } = useSWR<HttpResponseOk<MerchantBackend.Orders.OrderHistory>, HttpError>( + [`/private/orders`, token, url, args?.paid, args?.refunded, args?.wired, args?.date, totalBefore], + orderFetcher, + ) + const { data: afterData, error: afterError, isValidating: loadingAfter } = useSWR<HttpResponseOk<MerchantBackend.Orders.OrderHistory>, HttpError>( + [`/private/orders`, token, url, args?.paid, args?.refunded, args?.wired, args?.date, -totalAfter], + orderFetcher, + ) + + //this will save last result + const [lastBefore, setLastBefore] = useState<HttpResponse<MerchantBackend.Orders.OrderHistory>>({ loading: true }) + const [lastAfter, setLastAfter] = useState<HttpResponse<MerchantBackend.Orders.OrderHistory>>({ loading: true }) + useEffect(() => { + if (afterData) setLastAfter(afterData) + if (beforeData) setLastBefore(beforeData) + }, [afterData, beforeData]) + + // this has problems when there are some ids missing + + if (beforeError) return beforeError + if (afterError) return afterError + + + const pagination = { + isReachingEnd: afterData && afterData.data.orders.length < totalAfter, + isReachingStart: (!args?.date) || (beforeData && beforeData.data.orders.length < totalBefore), + loadMore: () => { + if (!afterData) return + if (afterData.data.orders.length < MAX_RESULT_SIZE) { + setPageAfter(pageAfter + 1) + } else { + const from = afterData.data.orders[afterData.data.orders.length - 1].timestamp.t_ms + if (from && updateFilter) updateFilter(new Date(from)) + } + }, + loadMorePrev: () => { + if (!beforeData) return + if (beforeData.data.orders.length < MAX_RESULT_SIZE) { + setPageBefore(pageBefore + 1) + } else if (beforeData) { + const from = beforeData.data.orders[beforeData.data.orders.length - 1].timestamp.t_ms + if (from && updateFilter) updateFilter(new Date(from)) + } + }, + } + + const orders = !beforeData || !afterData ? [] : (beforeData || lastBefore).data.orders.slice().reverse().concat((afterData || lastAfter).data.orders) + if (loadingAfter || loadingBefore) return { loading: true, data: { orders } } + if (beforeData && afterData) { + return { ok: true, data: { orders }, ...pagination } + } + return { loading: true } + +} + diff --git a/packages/backend/src/hooks/product.ts b/packages/backend/src/hooks/product.ts new file mode 100644 index 0000000..edba27b --- /dev/null +++ b/packages/backend/src/hooks/product.ts @@ -0,0 +1,199 @@ +/* + 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 { useEffect } from 'preact/hooks'; +import useSWR, { trigger, useSWRInfinite, cache, mutate } from 'swr'; +import { useBackendContext } from '../context/backend'; +// import { useFetchContext } from '../context/fetch'; +import { useInstanceContext } from '../context/instance'; +import { MerchantBackend, WithId } from '../declaration'; +import { fetcher, HttpError, HttpResponse, HttpResponseOk, mutateAll, request } from './backend'; + +export interface ProductAPI { + createProduct: (data: MerchantBackend.Products.ProductAddDetail) => Promise<void>; + updateProduct: (id: string, data: MerchantBackend.Products.ProductPatchDetail) => Promise<void>; + deleteProduct: (id: string) => Promise<void>; + lockProduct: (id: string, data: MerchantBackend.Products.LockRequest) => Promise<void>; +} + + +export function useProductAPI(): ProductAPI { + const { url: baseUrl, token: adminToken } = useBackendContext(); + const { token: instanceToken, id, admin } = useInstanceContext(); + + const { url, token } = !admin ? { + url: baseUrl, token: adminToken + } : { + url: `${baseUrl}/instances/${id}`, token: instanceToken + }; + + + const createProduct = async (data: MerchantBackend.Products.ProductAddDetail): Promise<void> => { + await request(`${url}/private/products`, { + method: 'post', + token, + data + }); + + await mutateAll(/@"\/private\/products"@/, null); + }; + + const updateProduct = async (productId: string, data: MerchantBackend.Products.ProductPatchDetail): Promise<void> => { + const r = await request(`${url}/private/products/${productId}`, { + method: 'patch', + token, + data + }); + + /** + * There is some inconsistency in how the cache is evicted. + * I'm keeping this for later inspection + */ + + // -- Clear all cache + // -- This seems to work always but is bad + + // const keys = [...cache.keys()] + // console.log(keys) + // cache.clear() + // await Promise.all(keys.map(k => trigger(k))) + + // -- From the keys to the cache trigger + // -- An intermediate step + + // const keys = [ + // [`/private/products`, token, url], + // [`/private/products/${productId}`, token, url], + // ] + // cache.clear() + // const f: string[][] = keys.map(k => cache.serializeKey(k)) + // console.log(f) + // const m = flat(f) + // console.log(m) + // await Promise.all(m.map(k => trigger(k, true))) + + // await Promise.all(keys.map(k => mutate(k))) + + // -- This is how is supposed to be use + + // await mutate([`/private/products`, token, url]) + // await mutate([`/private/products/${productId}`, token, url]) + + // await mutateAll(/@"\/private\/products"@/); + await mutateAll(/@"\/private\/products\/.*"@/); + // return true + // return r + + // -- FIXME: why this un-break the tests? + return Promise.resolve() + }; + + const deleteProduct = async (productId: string): Promise<void> => { + await request(`${url}/private/products/${productId}`, { + method: 'delete', + token, + }); + + await mutateAll(/@"\/private\/products"@/); + }; + + const lockProduct = async (productId: string, data: MerchantBackend.Products.LockRequest): Promise<void> => { + await request(`${url}/private/products/${productId}/lock`, { + method: 'post', + token, + data + }); + + await mutateAll(/@"\/private\/products"@/); + }; + + return { createProduct, updateProduct, deleteProduct, lockProduct }; +} + + +export function useInstanceProducts(): HttpResponse<(MerchantBackend.Products.ProductDetail & WithId)[]> { + const { url: baseUrl, token: baseToken } = useBackendContext(); + const { token: instanceToken, id, admin } = useInstanceContext(); + // const { useSWR, useSWRInfinite } = useFetchContext(); + + const { url, token } = !admin ? { + url: baseUrl, token: baseToken + } : { + url: `${baseUrl}/instances/${id}`, token: instanceToken + }; + + const { data: list, error: listError, isValidating: listLoading } = useSWR<HttpResponseOk<MerchantBackend.Products.InventorySummaryResponse>, HttpError>([`/private/products`, token, url], fetcher, { + refreshInterval: 0, + refreshWhenHidden: false, + revalidateOnFocus: false, + revalidateOnReconnect: false, + refreshWhenOffline: false, + }); + + 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, { + revalidateAll: true, + }) + + useEffect(() => { + if (list?.data && list.data.products.length > 0) { + setSize(list.data.products.length) + } + }, [list?.data.products.length, listLoading]) + + + if (listLoading) return { loading: true, data: [] } + if (listError) return listError + if (productError) return productError + if (list?.data && list.data.products.length === 0) { + return { ok: true, data: [] } + } + if (products) { + const dataWithId = products.map((d) => { + //take the id from the queried url + return ({ ...d.data, id: d.info?.url.replace(/.*\/private\/products\//, '') || '' }) + }) + return { ok: true, data: dataWithId } + } + return { loading: true } +} + +export function useProductDetails(productId: string): HttpResponse<MerchantBackend.Products.ProductDetail> { + const { url: baseUrl, token: baseToken } = useBackendContext(); + const { token: instanceToken, id, admin } = useInstanceContext(); + + const { url, token } = !admin ? { + url: baseUrl, token: baseToken + } : { + url: `${baseUrl}/instances/${id}`, token: instanceToken + }; + + const { data, error, isValidating } = useSWR<HttpResponseOk<MerchantBackend.Products.ProductDetail>, HttpError>( + [`/private/products/${productId}`, token, url], fetcher, { + refreshInterval: 0, + refreshWhenHidden: false, + revalidateOnFocus: false, + revalidateOnReconnect: false, + refreshWhenOffline: false, + } + ) + + if (isValidating) return { loading: true, data: data?.data } + if (data) return data + if (error) return error + return { loading: true } +} diff --git a/packages/backend/src/hooks/tips.ts b/packages/backend/src/hooks/tips.ts new file mode 100644 index 0000000..345e1fa --- /dev/null +++ b/packages/backend/src/hooks/tips.ts @@ -0,0 +1,159 @@ +/* + 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 useSWR from 'swr'; +import { useBackendContext } from '../context/backend'; +import { useInstanceContext } from '../context/instance'; +import { MerchantBackend } from '../declaration'; +import { fetcher, HttpError, HttpResponse, HttpResponseOk, mutateAll, request } from './backend'; + + +export function useReservesAPI(): ReserveMutateAPI { + const { url: baseUrl, token: adminToken } = useBackendContext(); + const { token: instanceToken, id, admin } = useInstanceContext(); + + const { url, token } = !admin ? { + url: baseUrl, token: adminToken + } : { + url: `${baseUrl}/instances/${id}`, token: instanceToken + }; + + const createReserve = async (data: MerchantBackend.Tips.ReserveCreateRequest): Promise<HttpResponseOk<MerchantBackend.Tips.ReserveCreateConfirmation>> => { + const res = await request<MerchantBackend.Tips.ReserveCreateConfirmation>(`${url}/private/reserves`, { + method: 'post', + token, + data + }); + + await mutateAll(/@"\/private\/reserves"@/); + + return res + }; + + const authorizeTipReserve = async (pub: string, data: MerchantBackend.Tips.TipCreateRequest): Promise<HttpResponseOk<MerchantBackend.Tips.TipCreateConfirmation>> => { + const res = await request<MerchantBackend.Tips.TipCreateConfirmation>(`${url}/private/reserves/${pub}/authorize-tip`, { + method: 'post', + token, + data + }); + await mutateAll(/@"\/private\/reserves"@/); + + return res + }; + + const authorizeTip = async (data: MerchantBackend.Tips.TipCreateRequest): Promise<HttpResponseOk<MerchantBackend.Tips.TipCreateConfirmation>> => { + const res = await request<MerchantBackend.Tips.TipCreateConfirmation>(`${url}/private/tips`, { + method: 'post', + token, + data + }); + + await mutateAll(/@"\/private\/reserves"@/); + + return res + }; + + const deleteReserve = async (pub: string): Promise<HttpResponse<void>> => { + const res = await request<void>(`${url}/private/reserves/${pub}`, { + method: 'delete', + token, + }); + + await mutateAll(/@"\/private\/reserves"@/); + + return res + }; + + + return { createReserve, authorizeTip, authorizeTipReserve, deleteReserve }; +} + +export interface ReserveMutateAPI { + createReserve: (data: MerchantBackend.Tips.ReserveCreateRequest) => Promise<HttpResponseOk<MerchantBackend.Tips.ReserveCreateConfirmation>>; + authorizeTipReserve: (id: string, data: MerchantBackend.Tips.TipCreateRequest) => Promise<HttpResponseOk<MerchantBackend.Tips.TipCreateConfirmation>>; + authorizeTip: (data: MerchantBackend.Tips.TipCreateRequest) => Promise<HttpResponseOk<MerchantBackend.Tips.TipCreateConfirmation>>; + deleteReserve: (id: string) => Promise<HttpResponse<void>>; +} + +export function useInstanceTips(): HttpResponse<MerchantBackend.Tips.TippingReserveStatus> { + const { url: baseUrl, token: baseToken } = useBackendContext(); + const { token: instanceToken, id, admin } = useInstanceContext(); + + const { url, token } = !admin ? { + url: baseUrl, token: baseToken + } : { + url: `${baseUrl}/instances/${id}`, token: instanceToken + } + + const { data, error, isValidating } = useSWR<HttpResponseOk<MerchantBackend.Tips.TippingReserveStatus>, HttpError>([`/private/reserves`, token, url], fetcher) + + if (isValidating) return { loading: true, data: data?.data } + if (data) return data + if (error) return error + return { loading: true } +} + + +export function useReserveDetails(reserveId: string): HttpResponse<MerchantBackend.Tips.ReserveDetail> { + const { url: baseUrl } = useBackendContext(); + const { token, id: instanceId, admin } = useInstanceContext(); + + const url = !admin ? baseUrl : `${baseUrl}/instances/${instanceId}` + + const { data, error, isValidating } = useSWR<HttpResponseOk<MerchantBackend.Tips.ReserveDetail>, HttpError>([`/private/reserves/${reserveId}`, token, url], reserveDetailFetcher, { + refreshInterval:0, + refreshWhenHidden: false, + revalidateOnFocus: false, + revalidateOnReconnect: false, + refreshWhenOffline: false, + }) + + if (isValidating) return { loading: true, data: data?.data } + if (data) return data + if (error) return error + return { loading: true } +} + +export function useTipDetails(tipId: string): HttpResponse<MerchantBackend.Tips.TipDetails> { + const { url: baseUrl } = useBackendContext(); + const { token, id: instanceId, admin } = useInstanceContext(); + + const url = !admin ? baseUrl : `${baseUrl}/instances/${instanceId}` + + const { data, error, isValidating } = useSWR<HttpResponseOk<MerchantBackend.Tips.TipDetails>, HttpError>([`/private/tips/${tipId}`, token, url], tipsDetailFetcher, { + refreshInterval:0, + refreshWhenHidden: false, + revalidateOnFocus: false, + revalidateOnReconnect: false, + refreshWhenOffline: false, + }) + + if (isValidating) return { loading: true, data: data?.data } + if (data) return data + if (error) return error + return { loading: true } +} + +export function reserveDetailFetcher<T>(url: string, token: string, backend: string): Promise<HttpResponseOk<T>> { + return request<T>(`${backend}${url}`, { token, params: { + tips: 'yes' + } }) +} + +export function tipsDetailFetcher<T>(url: string, token: string, backend: string): Promise<HttpResponseOk<T>> { + return request<T>(`${backend}${url}`, { token, params: { + pickups: 'yes' + } }) +} diff --git a/packages/backend/src/hooks/transfer.ts b/packages/backend/src/hooks/transfer.ts new file mode 100644 index 0000000..02e041a --- /dev/null +++ b/packages/backend/src/hooks/transfer.ts @@ -0,0 +1,150 @@ +/* + 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 { MerchantBackend } from '../declaration'; +import { useBackendContext } from '../context/backend'; +import { request, mutateAll, HttpResponse, HttpError, HttpResponseOk, HttpResponsePaginated } from './backend'; +import useSWR from 'swr'; +import { useInstanceContext } from '../context/instance'; +import { MAX_RESULT_SIZE, PAGE_SIZE } from '../utils/constants'; +import { useEffect, useState } from 'preact/hooks'; + +async function transferFetcher<T>(url: string, token: string, backend: string, payto_uri?: string, verified?: string, position?: string, delta?: number): Promise<HttpResponseOk<T>> { + const params: any = {} + if (payto_uri !== undefined) params.payto_uri = payto_uri + if (verified !== undefined) params.verified = verified + if (delta !== undefined) { + // if (delta > 0) { + // params.after = searchDate?.getTime() + // } else { + // params.before = searchDate?.getTime() + // } + params.limit = delta + } + if (position !== undefined) params.offset = position + + return request<T>(`${backend}${url}`, { token, params }) +} + +export function useTransferAPI(): TransferAPI { + const { url: baseUrl, token: adminToken } = useBackendContext(); + const { token: instanceToken, id, admin } = useInstanceContext(); + + const { url, token } = !admin ? { + url: baseUrl, token: adminToken + } : { + url: `${baseUrl}/instances/${id}`, token: instanceToken + }; + + const informTransfer = async (data: MerchantBackend.Transfers.TransferInformation): Promise<HttpResponseOk<MerchantBackend.Transfers.MerchantTrackTransferResponse>> => { + mutateAll(/@"\/private\/transfers"@/); + + return request<MerchantBackend.Transfers.MerchantTrackTransferResponse>(`${url}/private/transfers`, { + method: 'post', + token, + data + }); + }; + + return { informTransfer }; +} + +export interface TransferAPI { + informTransfer: (data: MerchantBackend.Transfers.TransferInformation) => Promise<HttpResponseOk<MerchantBackend.Transfers.MerchantTrackTransferResponse>>; +} + +export interface InstanceTransferFilter { + payto_uri?: string; + verified?: 'yes' | 'no'; + position?: string; +} + + +export function useInstanceTransfers(args?: InstanceTransferFilter, updatePosition?: (id: string) => void): HttpResponsePaginated<MerchantBackend.Transfers.TransferList> { + const { url: baseUrl, token: baseToken } = useBackendContext(); + const { token: instanceToken, id, admin } = useInstanceContext(); + + const { url, token } = !admin ? { + url: baseUrl, token: baseToken + } : { + url: `${baseUrl}/instances/${id}`, token: instanceToken + } + + const [pageBefore, setPageBefore] = useState(1) + const [pageAfter, setPageAfter] = useState(1) + + const totalAfter = pageAfter * PAGE_SIZE; + const totalBefore = args?.position !== undefined ? pageBefore * PAGE_SIZE : 0; + + /** + * FIXME: this can be cleaned up a little + * + * the logic of double query should be inside the orderFetch so from the hook perspective and cache + * is just one query and one error status + */ + const { data: beforeData, error: beforeError, isValidating: loadingBefore } = useSWR<HttpResponseOk<MerchantBackend.Transfers.TransferList>, HttpError>( + [`/private/transfers`, token, url, args?.payto_uri, args?.verified, args?.position, totalBefore], + transferFetcher, + ) + const { data: afterData, error: afterError, isValidating: loadingAfter } = useSWR<HttpResponseOk<MerchantBackend.Transfers.TransferList>, HttpError>( + [`/private/transfers`, token, url, args?.payto_uri, args?.verified, args?.position, -totalAfter], + transferFetcher, + ) + + //this will save last result + const [lastBefore, setLastBefore] = useState<HttpResponse<MerchantBackend.Transfers.TransferList>>({ loading: true }) + const [lastAfter, setLastAfter] = useState<HttpResponse<MerchantBackend.Transfers.TransferList>>({ loading: true }) + useEffect(() => { + if (afterData) setLastAfter(afterData) + if (beforeData) setLastBefore(beforeData) + }, [afterData, beforeData]) + + // this has problems when there are some ids missing + + if (beforeError) return beforeError + if (afterError) return afterError + + const pagination = { + isReachingEnd: afterData && afterData.data.transfers.length < totalAfter, + isReachingStart: (!args?.position) || (beforeData && beforeData.data.transfers.length < totalBefore), + loadMore: () => { + if (!afterData) return + if (afterData.data.transfers.length < MAX_RESULT_SIZE) { + setPageAfter(pageAfter + 1) + } else { + const from = ""+afterData.data.transfers[afterData.data.transfers.length - 1].transfer_serial_id + if (from && updatePosition) updatePosition(from) + } + }, + loadMorePrev: () => { + if (!beforeData) return + if (beforeData.data.transfers.length < MAX_RESULT_SIZE) { + setPageBefore(pageBefore + 1) + } else if (beforeData) { + const from = ""+beforeData.data.transfers[beforeData.data.transfers.length - 1].transfer_serial_id + if (from && updatePosition) updatePosition(from) + } + }, + } + + const transfers = !beforeData || !afterData ? [] : (beforeData || lastBefore).data.transfers.slice().reverse().concat((afterData || lastAfter).data.transfers) + if (loadingAfter || loadingBefore) return { loading: true, data: { transfers } } + if (beforeData && afterData) { + return { ok: true, data: { transfers }, ...pagination } + } + return { loading: true } +} + + diff --git a/packages/backend/src/i18n/de.po b/packages/backend/src/i18n/de.po new file mode 100644 index 0000000..6b35bd0 --- /dev/null +++ b/packages/backend/src/i18n/de.po @@ -0,0 +1,1057 @@ +# 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:118 +#: src/InstanceRoutes.tsx:299 +#, c-format +msgid "Access denied" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:51 src/InstanceRoutes.tsx:118 +#: src/InstanceRoutes.tsx:300 +#, 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:109 +#, c-format +msgid "HTTP status #%1$s: Server reported a problem" +msgstr "" + +#: src/InstanceRoutes.tsx:110 +#, c-format +msgid "Got message: \"%1$s\" from: %2$s" +msgstr "" + +#: src/InstanceRoutes.tsx:127 +#, c-format +msgid "No default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:128 +#, c-format +msgid "" +"in order to use merchant backoffice, you should create the default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:288 +#, c-format +msgid "Server reported a problem: HTTP status #%1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:289 +#, 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:115 +#: src/paths/instance/orders/create/CreatePage.tsx:325 +#: 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/transfers/create/CreatePage.tsx:89 +#: src/paths/instance/update/UpdatePage.tsx:134 +#, 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 +#: src/paths/instance/transfers/list/Table.tsx:140 +#, 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/InputLocation.tsx:28 +#, c-format +msgid "Country" +msgstr "" + +#: src/components/form/InputLocation.tsx:30 +#: src/paths/admin/create/CreatePage.tsx:99 +#: src/paths/instance/transfers/list/Table.tsx:124 +#: src/paths/instance/update/UpdatePage.tsx:118 +#, c-format +msgid "Address" +msgstr "" + +#: src/components/form/InputLocation.tsx:34 +#, c-format +msgid "Building number" +msgstr "" + +#: src/components/form/InputLocation.tsx:35 +#, c-format +msgid "Building name" +msgstr "" + +#: src/components/form/InputLocation.tsx:36 +#, c-format +msgid "Street" +msgstr "" + +#: src/components/form/InputLocation.tsx:37 +#, c-format +msgid "Post code" +msgstr "" + +#: src/components/form/InputLocation.tsx:38 +#, c-format +msgid "Town location" +msgstr "" + +#: src/components/form/InputLocation.tsx:39 +#, c-format +msgid "Town" +msgstr "" + +#: src/components/form/InputLocation.tsx:40 +#, c-format +msgid "District" +msgstr "" + +#: src/components/form/InputLocation.tsx:41 +#, c-format +msgid "Country subdivision" +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:87 src/paths/admin/list/Table.tsx:110 +#: src/paths/instance/details/DetailPage.tsx:76 +#: src/paths/instance/update/UpdatePage.tsx:106 +#, 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:252 +#: src/paths/instance/orders/create/CreatePage.tsx:273 +#, 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:114 +#: src/paths/instance/orders/create/CreatePage.tsx:324 +#: 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/transfers/create/CreatePage.tsx:88 +#: src/paths/instance/update/UpdatePage.tsx:133 +#, c-format +msgid "Cancel" +msgstr "" + +#: src/components/form/InputStock.tsx:91 +#, c-format +msgid "Manage stock" +msgstr "" + +#: src/components/form/InputStock.tsx:93 +#, c-format +msgid "Infinite" +msgstr "" + +#: src/components/form/InputStock.tsx:105 +#, c-format +msgid "lost cannot be greater that current + incoming (max %1$s)" +msgstr "" + +#: src/components/form/InputStock.tsx:111 +#, c-format +msgid "current stock will change from %1$s to %2$s" +msgstr "" + +#: src/components/form/InputStock.tsx:112 +#, c-format +msgid "current stock will stay at %1$s" +msgstr "" + +#: src/components/form/InputStock.tsx:129 +#: src/paths/instance/products/list/Table.tsx:204 +#, c-format +msgid "Incoming" +msgstr "" + +#: src/components/form/InputStock.tsx:130 +#: src/paths/instance/products/list/Table.tsx:205 +#, c-format +msgid "Lost" +msgstr "" + +#: src/components/form/InputStock.tsx:142 +#, c-format +msgid "Current" +msgstr "" + +#: src/components/form/InputStock.tsx:145 +#, c-format +msgid "without stock" +msgstr "" + +#: src/components/form/InputStock.tsx:150 +#, c-format +msgid "Next restock" +msgstr "" + +#: src/components/form/InputStock.tsx:152 +#, c-format +msgid "Delivery address" +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 +#: src/paths/instance/transfers/create/CreatePage.tsx:84 +#, 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:258 +#: 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:65 +#, 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:85 src/paths/admin/list/Table.tsx:109 +#: src/paths/instance/transfers/list/Table.tsx:122 +#, 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:89 +#: src/paths/instance/update/UpdatePage.tsx:108 +#, c-format +msgid "Auth token" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:91 +#: src/paths/instance/details/DetailPage.tsx:77 +#: src/paths/instance/update/UpdatePage.tsx:110 +#, c-format +msgid "Account address" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:93 +#: src/paths/instance/update/UpdatePage.tsx:112 +#, c-format +msgid "Default max deposit fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:95 +#: src/paths/instance/update/UpdatePage.tsx:114 +#, c-format +msgid "Default max wire fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:97 +#: src/paths/instance/update/UpdatePage.tsx:116 +#, c-format +msgid "Default wire fee amortization" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:103 +#: src/paths/instance/update/UpdatePage.tsx:122 +#, c-format +msgid "Jurisdiction" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:107 +#: src/paths/instance/update/UpdatePage.tsx:126 +#, c-format +msgid "Default pay delay" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:109 +#: src/paths/instance/update/UpdatePage.tsx:128 +#, 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 +#: src/paths/instance/transfers/list/Table.tsx:71 +#, 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:237 +#, c-format +msgid "Inventory products" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:286 +#, c-format +msgid "Total price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:287 +#, c-format +msgid "Total tax" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:289 +#: src/paths/instance/orders/create/CreatePage.tsx:297 +#, c-format +msgid "Order price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:295 +#, c-format +msgid "Net" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:300 +#: 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:302 +#, c-format +msgid "Payments options" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:303 +#, c-format +msgid "Auto refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:304 +#, c-format +msgid "Refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:305 +#, c-format +msgid "Pay deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:307 +#, c-format +msgid "Delivery date" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:308 +#, c-format +msgid "Location" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:312 +#, c-format +msgid "Max fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:313 +#, c-format +msgid "Max wire fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:314 +#, c-format +msgid "Wire fee amortization" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:315 +#, c-format +msgid "Fullfilment url" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:318 +#, 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/create/CreatePage.tsx:50 +#: src/paths/instance/transfers/create/CreatePage.tsx:54 +#: src/paths/instance/transfers/create/CreatePage.tsx:55 +#: src/paths/instance/transfers/create/CreatePage.tsx:56 +#, c-format +msgid "cannot be empty" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:51 +#, c-format +msgid "check the id, doest look valid" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:52 +#, c-format +msgid "should have 52 characters, current %1$s" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:57 +#, c-format +msgid "URL doesn't have the right format" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:74 +#, c-format +msgid "Transfer ID" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:76 +#, c-format +msgid "Account Address" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:82 +#: src/paths/instance/transfers/list/Table.tsx:125 +#, c-format +msgid "Exchange URL" +msgstr "" + +#: src/paths/instance/transfers/create/index.tsx:49 +#, c-format +msgid "could not inform transfer" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:118 +#, c-format +msgid "load newer transfers" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:123 +#, c-format +msgid "Credit" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:126 +#, c-format +msgid "Confirmed" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:127 +#: src/paths/instance/transfers/list/index.tsx:60 +#, c-format +msgid "Verified" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:128 +#, c-format +msgid "Executed at" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "yes" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "no" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:140 +#, c-format +msgid "unknown" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:145 +#, c-format +msgid "load older transfers" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:154 +#, c-format +msgid "There is no transfer yet, add more pressing the + sign" +msgstr "" diff --git a/packages/backend/src/i18n/en.po b/packages/backend/src/i18n/en.po new file mode 100644 index 0000000..6b35bd0 --- /dev/null +++ b/packages/backend/src/i18n/en.po @@ -0,0 +1,1057 @@ +# 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:118 +#: src/InstanceRoutes.tsx:299 +#, c-format +msgid "Access denied" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:51 src/InstanceRoutes.tsx:118 +#: src/InstanceRoutes.tsx:300 +#, 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:109 +#, c-format +msgid "HTTP status #%1$s: Server reported a problem" +msgstr "" + +#: src/InstanceRoutes.tsx:110 +#, c-format +msgid "Got message: \"%1$s\" from: %2$s" +msgstr "" + +#: src/InstanceRoutes.tsx:127 +#, c-format +msgid "No default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:128 +#, c-format +msgid "" +"in order to use merchant backoffice, you should create the default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:288 +#, c-format +msgid "Server reported a problem: HTTP status #%1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:289 +#, 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:115 +#: src/paths/instance/orders/create/CreatePage.tsx:325 +#: 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/transfers/create/CreatePage.tsx:89 +#: src/paths/instance/update/UpdatePage.tsx:134 +#, 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 +#: src/paths/instance/transfers/list/Table.tsx:140 +#, 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/InputLocation.tsx:28 +#, c-format +msgid "Country" +msgstr "" + +#: src/components/form/InputLocation.tsx:30 +#: src/paths/admin/create/CreatePage.tsx:99 +#: src/paths/instance/transfers/list/Table.tsx:124 +#: src/paths/instance/update/UpdatePage.tsx:118 +#, c-format +msgid "Address" +msgstr "" + +#: src/components/form/InputLocation.tsx:34 +#, c-format +msgid "Building number" +msgstr "" + +#: src/components/form/InputLocation.tsx:35 +#, c-format +msgid "Building name" +msgstr "" + +#: src/components/form/InputLocation.tsx:36 +#, c-format +msgid "Street" +msgstr "" + +#: src/components/form/InputLocation.tsx:37 +#, c-format +msgid "Post code" +msgstr "" + +#: src/components/form/InputLocation.tsx:38 +#, c-format +msgid "Town location" +msgstr "" + +#: src/components/form/InputLocation.tsx:39 +#, c-format +msgid "Town" +msgstr "" + +#: src/components/form/InputLocation.tsx:40 +#, c-format +msgid "District" +msgstr "" + +#: src/components/form/InputLocation.tsx:41 +#, c-format +msgid "Country subdivision" +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:87 src/paths/admin/list/Table.tsx:110 +#: src/paths/instance/details/DetailPage.tsx:76 +#: src/paths/instance/update/UpdatePage.tsx:106 +#, 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:252 +#: src/paths/instance/orders/create/CreatePage.tsx:273 +#, 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:114 +#: src/paths/instance/orders/create/CreatePage.tsx:324 +#: 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/transfers/create/CreatePage.tsx:88 +#: src/paths/instance/update/UpdatePage.tsx:133 +#, c-format +msgid "Cancel" +msgstr "" + +#: src/components/form/InputStock.tsx:91 +#, c-format +msgid "Manage stock" +msgstr "" + +#: src/components/form/InputStock.tsx:93 +#, c-format +msgid "Infinite" +msgstr "" + +#: src/components/form/InputStock.tsx:105 +#, c-format +msgid "lost cannot be greater that current + incoming (max %1$s)" +msgstr "" + +#: src/components/form/InputStock.tsx:111 +#, c-format +msgid "current stock will change from %1$s to %2$s" +msgstr "" + +#: src/components/form/InputStock.tsx:112 +#, c-format +msgid "current stock will stay at %1$s" +msgstr "" + +#: src/components/form/InputStock.tsx:129 +#: src/paths/instance/products/list/Table.tsx:204 +#, c-format +msgid "Incoming" +msgstr "" + +#: src/components/form/InputStock.tsx:130 +#: src/paths/instance/products/list/Table.tsx:205 +#, c-format +msgid "Lost" +msgstr "" + +#: src/components/form/InputStock.tsx:142 +#, c-format +msgid "Current" +msgstr "" + +#: src/components/form/InputStock.tsx:145 +#, c-format +msgid "without stock" +msgstr "" + +#: src/components/form/InputStock.tsx:150 +#, c-format +msgid "Next restock" +msgstr "" + +#: src/components/form/InputStock.tsx:152 +#, c-format +msgid "Delivery address" +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 +#: src/paths/instance/transfers/create/CreatePage.tsx:84 +#, 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:258 +#: 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:65 +#, 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:85 src/paths/admin/list/Table.tsx:109 +#: src/paths/instance/transfers/list/Table.tsx:122 +#, 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:89 +#: src/paths/instance/update/UpdatePage.tsx:108 +#, c-format +msgid "Auth token" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:91 +#: src/paths/instance/details/DetailPage.tsx:77 +#: src/paths/instance/update/UpdatePage.tsx:110 +#, c-format +msgid "Account address" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:93 +#: src/paths/instance/update/UpdatePage.tsx:112 +#, c-format +msgid "Default max deposit fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:95 +#: src/paths/instance/update/UpdatePage.tsx:114 +#, c-format +msgid "Default max wire fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:97 +#: src/paths/instance/update/UpdatePage.tsx:116 +#, c-format +msgid "Default wire fee amortization" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:103 +#: src/paths/instance/update/UpdatePage.tsx:122 +#, c-format +msgid "Jurisdiction" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:107 +#: src/paths/instance/update/UpdatePage.tsx:126 +#, c-format +msgid "Default pay delay" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:109 +#: src/paths/instance/update/UpdatePage.tsx:128 +#, 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 +#: src/paths/instance/transfers/list/Table.tsx:71 +#, 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:237 +#, c-format +msgid "Inventory products" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:286 +#, c-format +msgid "Total price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:287 +#, c-format +msgid "Total tax" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:289 +#: src/paths/instance/orders/create/CreatePage.tsx:297 +#, c-format +msgid "Order price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:295 +#, c-format +msgid "Net" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:300 +#: 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:302 +#, c-format +msgid "Payments options" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:303 +#, c-format +msgid "Auto refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:304 +#, c-format +msgid "Refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:305 +#, c-format +msgid "Pay deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:307 +#, c-format +msgid "Delivery date" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:308 +#, c-format +msgid "Location" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:312 +#, c-format +msgid "Max fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:313 +#, c-format +msgid "Max wire fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:314 +#, c-format +msgid "Wire fee amortization" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:315 +#, c-format +msgid "Fullfilment url" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:318 +#, 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/create/CreatePage.tsx:50 +#: src/paths/instance/transfers/create/CreatePage.tsx:54 +#: src/paths/instance/transfers/create/CreatePage.tsx:55 +#: src/paths/instance/transfers/create/CreatePage.tsx:56 +#, c-format +msgid "cannot be empty" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:51 +#, c-format +msgid "check the id, doest look valid" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:52 +#, c-format +msgid "should have 52 characters, current %1$s" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:57 +#, c-format +msgid "URL doesn't have the right format" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:74 +#, c-format +msgid "Transfer ID" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:76 +#, c-format +msgid "Account Address" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:82 +#: src/paths/instance/transfers/list/Table.tsx:125 +#, c-format +msgid "Exchange URL" +msgstr "" + +#: src/paths/instance/transfers/create/index.tsx:49 +#, c-format +msgid "could not inform transfer" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:118 +#, c-format +msgid "load newer transfers" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:123 +#, c-format +msgid "Credit" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:126 +#, c-format +msgid "Confirmed" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:127 +#: src/paths/instance/transfers/list/index.tsx:60 +#, c-format +msgid "Verified" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:128 +#, c-format +msgid "Executed at" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "yes" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "no" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:140 +#, c-format +msgid "unknown" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:145 +#, c-format +msgid "load older transfers" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:154 +#, c-format +msgid "There is no transfer yet, add more pressing the + sign" +msgstr "" diff --git a/packages/backend/src/i18n/es.po b/packages/backend/src/i18n/es.po new file mode 100644 index 0000000..9075d46 --- /dev/null +++ b/packages/backend/src/i18n/es.po @@ -0,0 +1,1065 @@ +# 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:118 +#: src/InstanceRoutes.tsx:299 +#, c-format +msgid "Access denied" +msgstr "Acceso denegado" + +#: src/ApplicationReadyRoutes.tsx:51 src/InstanceRoutes.tsx:118 +#: src/InstanceRoutes.tsx:300 +#, 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:109 +#, c-format +msgid "HTTP status #%1$s: Server reported a problem" +msgstr "HTTP status #%1$s: Servidor reporto un problema" + +#: src/InstanceRoutes.tsx:110 +#, fuzzy, c-format +msgid "Got message: \"%1$s\" from: %2$s" +msgstr "Recivimos el mensaje %1$s desde %2$s" + +#: src/InstanceRoutes.tsx:127 +#, c-format +msgid "No default instance" +msgstr "Sin instancia default" + +#: src/InstanceRoutes.tsx:128 +#, 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:288 +#, c-format +msgid "Server reported a problem: HTTP status #%1$s" +msgstr "Servidir reporto un problema: HTTP status #%1$s" + +#: src/InstanceRoutes.tsx:289 +#, 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:115 +#: src/paths/instance/orders/create/CreatePage.tsx:325 +#: 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/transfers/create/CreatePage.tsx:89 +#: src/paths/instance/update/UpdatePage.tsx:134 +#, 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 +#: src/paths/instance/transfers/list/Table.tsx:140 +#, 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/InputLocation.tsx:28 +#, c-format +msgid "Country" +msgstr "PaÃs" + +#: src/components/form/InputLocation.tsx:30 +#: src/paths/admin/create/CreatePage.tsx:99 +#: src/paths/instance/transfers/list/Table.tsx:124 +#: src/paths/instance/update/UpdatePage.tsx:118 +#, c-format +msgid "Address" +msgstr "Dirección" + +#: src/components/form/InputLocation.tsx:34 +#, c-format +msgid "Building number" +msgstr "Número de edificio" + +#: src/components/form/InputLocation.tsx:35 +#, c-format +msgid "Building name" +msgstr "Nombre de edificio" + +#: src/components/form/InputLocation.tsx:36 +#, c-format +msgid "Street" +msgstr "Calle" + +#: src/components/form/InputLocation.tsx:37 +#, c-format +msgid "Post code" +msgstr "Código postal" + +#: src/components/form/InputLocation.tsx:38 +#, fuzzy, c-format +msgid "Town location" +msgstr "Ubicación de ciudad" + +#: src/components/form/InputLocation.tsx:39 +#, c-format +msgid "Town" +msgstr "Ciudad" + +#: src/components/form/InputLocation.tsx:40 +#, c-format +msgid "District" +msgstr "Distrito" + +#: src/components/form/InputLocation.tsx:41 +#, c-format +msgid "Country subdivision" +msgstr "Provincia" + +#: 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:87 src/paths/admin/list/Table.tsx:110 +#: src/paths/instance/details/DetailPage.tsx:76 +#: src/paths/instance/update/UpdatePage.tsx:106 +#, 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:252 +#: src/paths/instance/orders/create/CreatePage.tsx:273 +#, 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:114 +#: src/paths/instance/orders/create/CreatePage.tsx:324 +#: 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/transfers/create/CreatePage.tsx:88 +#: src/paths/instance/update/UpdatePage.tsx:133 +#, c-format +msgid "Cancel" +msgstr "Cancelar" + +#: src/components/form/InputStock.tsx:91 +#, c-format +msgid "Manage stock" +msgstr "Administrar stock" + +#: src/components/form/InputStock.tsx:93 +#, c-format +msgid "Infinite" +msgstr "Inifinito" + +#: src/components/form/InputStock.tsx:105 +#, 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:111 +#, 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:112 +#, c-format +msgid "current stock will stay at %1$s" +msgstr "stock actual seguirá en %1$s" + +#: src/components/form/InputStock.tsx:129 +#: src/paths/instance/products/list/Table.tsx:204 +#, c-format +msgid "Incoming" +msgstr "Ingresando" + +#: src/components/form/InputStock.tsx:130 +#: src/paths/instance/products/list/Table.tsx:205 +#, c-format +msgid "Lost" +msgstr "Perdido" + +#: src/components/form/InputStock.tsx:142 +#, c-format +msgid "Current" +msgstr "Actual" + +#: src/components/form/InputStock.tsx:145 +#, c-format +msgid "without stock" +msgstr "sin stock" + +#: src/components/form/InputStock.tsx:150 +#, c-format +msgid "Next restock" +msgstr "Próximo reabastecimiento" + +#: src/components/form/InputStock.tsx:152 +#, c-format +msgid "Delivery address" +msgstr "Dirección de entrega" + +#: 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 +#: src/paths/instance/transfers/create/CreatePage.tsx:84 +#, 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:258 +#: 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:65 +#, 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:85 src/paths/admin/list/Table.tsx:109 +#: src/paths/instance/transfers/list/Table.tsx:122 +#, 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:89 +#: src/paths/instance/update/UpdatePage.tsx:108 +#, c-format +msgid "Auth token" +msgstr "Token de autorización" + +#: src/paths/admin/create/CreatePage.tsx:91 +#: src/paths/instance/details/DetailPage.tsx:77 +#: src/paths/instance/update/UpdatePage.tsx:110 +#, c-format +msgid "Account address" +msgstr "Dirección de cuenta" + +#: src/paths/admin/create/CreatePage.tsx:93 +#: src/paths/instance/update/UpdatePage.tsx:112 +#, c-format +msgid "Default max deposit fee" +msgstr "Impuesto máximo de deposito por omisión" + +#: src/paths/admin/create/CreatePage.tsx:95 +#: src/paths/instance/update/UpdatePage.tsx:114 +#, c-format +msgid "Default max wire fee" +msgstr "Impuesto máximo de transferencia por omisión" + +#: src/paths/admin/create/CreatePage.tsx:97 +#: src/paths/instance/update/UpdatePage.tsx:116 +#, c-format +msgid "Default wire fee amortization" +msgstr "Amortización de impuesto de transferencia por omisión" + +#: src/paths/admin/create/CreatePage.tsx:103 +#: src/paths/instance/update/UpdatePage.tsx:122 +#, c-format +msgid "Jurisdiction" +msgstr "Jurisdicción" + +#: src/paths/admin/create/CreatePage.tsx:107 +#: src/paths/instance/update/UpdatePage.tsx:126 +#, c-format +msgid "Default pay delay" +msgstr "Retrazo de pago por omisión" + +#: src/paths/admin/create/CreatePage.tsx:109 +#: src/paths/instance/update/UpdatePage.tsx:128 +#, 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 +#: src/paths/instance/transfers/list/Table.tsx:71 +#, 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:237 +#, c-format +msgid "Inventory products" +msgstr "Productos de inventario" + +#: src/paths/instance/orders/create/CreatePage.tsx:286 +#, c-format +msgid "Total price" +msgstr "Precio total" + +#: src/paths/instance/orders/create/CreatePage.tsx:287 +#, c-format +msgid "Total tax" +msgstr "Impuesto total" + +#: src/paths/instance/orders/create/CreatePage.tsx:289 +#: src/paths/instance/orders/create/CreatePage.tsx:297 +#, c-format +msgid "Order price" +msgstr "Precio de la orden" + +#: src/paths/instance/orders/create/CreatePage.tsx:295 +#, fuzzy, c-format +msgid "Net" +msgstr "Neto" + +#: src/paths/instance/orders/create/CreatePage.tsx:300 +#: 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:302 +#, c-format +msgid "Payments options" +msgstr "Opciones de pago" + +#: src/paths/instance/orders/create/CreatePage.tsx:303 +#, c-format +msgid "Auto refund deadline" +msgstr "Plazo de reembolso automático" + +#: src/paths/instance/orders/create/CreatePage.tsx:304 +#, c-format +msgid "Refund deadline" +msgstr "Plazo de reembolso" + +#: src/paths/instance/orders/create/CreatePage.tsx:305 +#, c-format +msgid "Pay deadline" +msgstr "Plazo de pago" + +#: src/paths/instance/orders/create/CreatePage.tsx:307 +#, c-format +msgid "Delivery date" +msgstr "Fecha de entrega" + +#: src/paths/instance/orders/create/CreatePage.tsx:308 +#, fuzzy, c-format +msgid "Location" +msgstr "Ubicación" + +#: src/paths/instance/orders/create/CreatePage.tsx:312 +#, c-format +msgid "Max fee" +msgstr "Impuesto máximo" + +#: src/paths/instance/orders/create/CreatePage.tsx:313 +#, c-format +msgid "Max wire fee" +msgstr "Impuesto de transferencia máximo" + +#: src/paths/instance/orders/create/CreatePage.tsx:314 +#, c-format +msgid "Wire fee amortization" +msgstr "Amortización de impuesto de transferencia" + +#: src/paths/instance/orders/create/CreatePage.tsx:315 +#, c-format +msgid "Fullfilment url" +msgstr "URL de completitud" + +#: src/paths/instance/orders/create/CreatePage.tsx:318 +#, 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/create/CreatePage.tsx:50 +#: src/paths/instance/transfers/create/CreatePage.tsx:54 +#: src/paths/instance/transfers/create/CreatePage.tsx:55 +#: src/paths/instance/transfers/create/CreatePage.tsx:56 +#, c-format +msgid "cannot be empty" +msgstr "no puede ser vacÃo" + +#: src/paths/instance/transfers/create/CreatePage.tsx:51 +#, c-format +msgid "check the id, doest look valid" +msgstr "verificar el id, no parece válido" + +#: src/paths/instance/transfers/create/CreatePage.tsx:52 +#, c-format +msgid "should have 52 characters, current %1$s" +msgstr "deberÃa tener 52 caracteres, actualmente %1$s" + +#: src/paths/instance/transfers/create/CreatePage.tsx:57 +#, c-format +msgid "URL doesn't have the right format" +msgstr "La URL no tiene el formato correcto" + +#: src/paths/instance/transfers/create/CreatePage.tsx:74 +#, fuzzy, c-format +msgid "Transfer ID" +msgstr "Transferencias" + +#: src/paths/instance/transfers/create/CreatePage.tsx:76 +#, fuzzy, c-format +msgid "Account Address" +msgstr "Dirección de cuenta" + +#: src/paths/instance/transfers/create/CreatePage.tsx:82 +#: src/paths/instance/transfers/list/Table.tsx:125 +#, c-format +msgid "Exchange URL" +msgstr "URL del Exchange" + +#: src/paths/instance/transfers/create/index.tsx:49 +#, fuzzy, c-format +msgid "could not inform transfer" +msgstr "no se pudo crear la instancia" + +#: src/paths/instance/transfers/list/Table.tsx:118 +#, fuzzy, c-format +msgid "load newer transfers" +msgstr "cargar nuevas ordenes" + +#: src/paths/instance/transfers/list/Table.tsx:123 +#, c-format +msgid "Credit" +msgstr "Crédito" + +#: src/paths/instance/transfers/list/Table.tsx:126 +#, fuzzy, c-format +msgid "Confirmed" +msgstr "Confirmar" + +#: src/paths/instance/transfers/list/Table.tsx:127 +#: src/paths/instance/transfers/list/index.tsx:60 +#, c-format +msgid "Verified" +msgstr "Verificado" + +#: src/paths/instance/transfers/list/Table.tsx:128 +#, fuzzy, c-format +msgid "Executed at" +msgstr "creado" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "yes" +msgstr "si" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "no" +msgstr "no" + +#: src/paths/instance/transfers/list/Table.tsx:140 +#, c-format +msgid "unknown" +msgstr "desconocido" + +#: src/paths/instance/transfers/list/Table.tsx:145 +#, fuzzy, c-format +msgid "load older transfers" +msgstr "cargar viejas transferencias" + +#: src/paths/instance/transfers/list/Table.tsx:154 +#, 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/backend/src/i18n/fr.po b/packages/backend/src/i18n/fr.po new file mode 100644 index 0000000..6b35bd0 --- /dev/null +++ b/packages/backend/src/i18n/fr.po @@ -0,0 +1,1057 @@ +# 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:118 +#: src/InstanceRoutes.tsx:299 +#, c-format +msgid "Access denied" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:51 src/InstanceRoutes.tsx:118 +#: src/InstanceRoutes.tsx:300 +#, 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:109 +#, c-format +msgid "HTTP status #%1$s: Server reported a problem" +msgstr "" + +#: src/InstanceRoutes.tsx:110 +#, c-format +msgid "Got message: \"%1$s\" from: %2$s" +msgstr "" + +#: src/InstanceRoutes.tsx:127 +#, c-format +msgid "No default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:128 +#, c-format +msgid "" +"in order to use merchant backoffice, you should create the default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:288 +#, c-format +msgid "Server reported a problem: HTTP status #%1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:289 +#, 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:115 +#: src/paths/instance/orders/create/CreatePage.tsx:325 +#: 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/transfers/create/CreatePage.tsx:89 +#: src/paths/instance/update/UpdatePage.tsx:134 +#, 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 +#: src/paths/instance/transfers/list/Table.tsx:140 +#, 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/InputLocation.tsx:28 +#, c-format +msgid "Country" +msgstr "" + +#: src/components/form/InputLocation.tsx:30 +#: src/paths/admin/create/CreatePage.tsx:99 +#: src/paths/instance/transfers/list/Table.tsx:124 +#: src/paths/instance/update/UpdatePage.tsx:118 +#, c-format +msgid "Address" +msgstr "" + +#: src/components/form/InputLocation.tsx:34 +#, c-format +msgid "Building number" +msgstr "" + +#: src/components/form/InputLocation.tsx:35 +#, c-format +msgid "Building name" +msgstr "" + +#: src/components/form/InputLocation.tsx:36 +#, c-format +msgid "Street" +msgstr "" + +#: src/components/form/InputLocation.tsx:37 +#, c-format +msgid "Post code" +msgstr "" + +#: src/components/form/InputLocation.tsx:38 +#, c-format +msgid "Town location" +msgstr "" + +#: src/components/form/InputLocation.tsx:39 +#, c-format +msgid "Town" +msgstr "" + +#: src/components/form/InputLocation.tsx:40 +#, c-format +msgid "District" +msgstr "" + +#: src/components/form/InputLocation.tsx:41 +#, c-format +msgid "Country subdivision" +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:87 src/paths/admin/list/Table.tsx:110 +#: src/paths/instance/details/DetailPage.tsx:76 +#: src/paths/instance/update/UpdatePage.tsx:106 +#, 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:252 +#: src/paths/instance/orders/create/CreatePage.tsx:273 +#, 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:114 +#: src/paths/instance/orders/create/CreatePage.tsx:324 +#: 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/transfers/create/CreatePage.tsx:88 +#: src/paths/instance/update/UpdatePage.tsx:133 +#, c-format +msgid "Cancel" +msgstr "" + +#: src/components/form/InputStock.tsx:91 +#, c-format +msgid "Manage stock" +msgstr "" + +#: src/components/form/InputStock.tsx:93 +#, c-format +msgid "Infinite" +msgstr "" + +#: src/components/form/InputStock.tsx:105 +#, c-format +msgid "lost cannot be greater that current + incoming (max %1$s)" +msgstr "" + +#: src/components/form/InputStock.tsx:111 +#, c-format +msgid "current stock will change from %1$s to %2$s" +msgstr "" + +#: src/components/form/InputStock.tsx:112 +#, c-format +msgid "current stock will stay at %1$s" +msgstr "" + +#: src/components/form/InputStock.tsx:129 +#: src/paths/instance/products/list/Table.tsx:204 +#, c-format +msgid "Incoming" +msgstr "" + +#: src/components/form/InputStock.tsx:130 +#: src/paths/instance/products/list/Table.tsx:205 +#, c-format +msgid "Lost" +msgstr "" + +#: src/components/form/InputStock.tsx:142 +#, c-format +msgid "Current" +msgstr "" + +#: src/components/form/InputStock.tsx:145 +#, c-format +msgid "without stock" +msgstr "" + +#: src/components/form/InputStock.tsx:150 +#, c-format +msgid "Next restock" +msgstr "" + +#: src/components/form/InputStock.tsx:152 +#, c-format +msgid "Delivery address" +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 +#: src/paths/instance/transfers/create/CreatePage.tsx:84 +#, 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:258 +#: 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:65 +#, 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:85 src/paths/admin/list/Table.tsx:109 +#: src/paths/instance/transfers/list/Table.tsx:122 +#, 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:89 +#: src/paths/instance/update/UpdatePage.tsx:108 +#, c-format +msgid "Auth token" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:91 +#: src/paths/instance/details/DetailPage.tsx:77 +#: src/paths/instance/update/UpdatePage.tsx:110 +#, c-format +msgid "Account address" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:93 +#: src/paths/instance/update/UpdatePage.tsx:112 +#, c-format +msgid "Default max deposit fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:95 +#: src/paths/instance/update/UpdatePage.tsx:114 +#, c-format +msgid "Default max wire fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:97 +#: src/paths/instance/update/UpdatePage.tsx:116 +#, c-format +msgid "Default wire fee amortization" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:103 +#: src/paths/instance/update/UpdatePage.tsx:122 +#, c-format +msgid "Jurisdiction" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:107 +#: src/paths/instance/update/UpdatePage.tsx:126 +#, c-format +msgid "Default pay delay" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:109 +#: src/paths/instance/update/UpdatePage.tsx:128 +#, 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 +#: src/paths/instance/transfers/list/Table.tsx:71 +#, 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:237 +#, c-format +msgid "Inventory products" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:286 +#, c-format +msgid "Total price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:287 +#, c-format +msgid "Total tax" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:289 +#: src/paths/instance/orders/create/CreatePage.tsx:297 +#, c-format +msgid "Order price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:295 +#, c-format +msgid "Net" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:300 +#: 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:302 +#, c-format +msgid "Payments options" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:303 +#, c-format +msgid "Auto refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:304 +#, c-format +msgid "Refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:305 +#, c-format +msgid "Pay deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:307 +#, c-format +msgid "Delivery date" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:308 +#, c-format +msgid "Location" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:312 +#, c-format +msgid "Max fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:313 +#, c-format +msgid "Max wire fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:314 +#, c-format +msgid "Wire fee amortization" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:315 +#, c-format +msgid "Fullfilment url" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:318 +#, 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/create/CreatePage.tsx:50 +#: src/paths/instance/transfers/create/CreatePage.tsx:54 +#: src/paths/instance/transfers/create/CreatePage.tsx:55 +#: src/paths/instance/transfers/create/CreatePage.tsx:56 +#, c-format +msgid "cannot be empty" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:51 +#, c-format +msgid "check the id, doest look valid" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:52 +#, c-format +msgid "should have 52 characters, current %1$s" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:57 +#, c-format +msgid "URL doesn't have the right format" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:74 +#, c-format +msgid "Transfer ID" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:76 +#, c-format +msgid "Account Address" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:82 +#: src/paths/instance/transfers/list/Table.tsx:125 +#, c-format +msgid "Exchange URL" +msgstr "" + +#: src/paths/instance/transfers/create/index.tsx:49 +#, c-format +msgid "could not inform transfer" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:118 +#, c-format +msgid "load newer transfers" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:123 +#, c-format +msgid "Credit" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:126 +#, c-format +msgid "Confirmed" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:127 +#: src/paths/instance/transfers/list/index.tsx:60 +#, c-format +msgid "Verified" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:128 +#, c-format +msgid "Executed at" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "yes" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "no" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:140 +#, c-format +msgid "unknown" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:145 +#, c-format +msgid "load older transfers" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:154 +#, c-format +msgid "There is no transfer yet, add more pressing the + sign" +msgstr "" diff --git a/packages/backend/src/i18n/index.tsx b/packages/backend/src/i18n/index.tsx new file mode 100644 index 0000000..63c8e19 --- /dev/null +++ b/packages/backend/src/i18n/index.tsx @@ -0,0 +1,203 @@ +/* + 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 { 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); + if (!s) return s + 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(); + 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 <Fragment>{result}</Fragment>; +} + +/** + * 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 <Fragment>{result}</Fragment>; +} + +/** + * 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 <Fragment>{result}</Fragment>; + +} diff --git a/packages/backend/src/i18n/it.po b/packages/backend/src/i18n/it.po new file mode 100644 index 0000000..6b35bd0 --- /dev/null +++ b/packages/backend/src/i18n/it.po @@ -0,0 +1,1057 @@ +# 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:118 +#: src/InstanceRoutes.tsx:299 +#, c-format +msgid "Access denied" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:51 src/InstanceRoutes.tsx:118 +#: src/InstanceRoutes.tsx:300 +#, 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:109 +#, c-format +msgid "HTTP status #%1$s: Server reported a problem" +msgstr "" + +#: src/InstanceRoutes.tsx:110 +#, c-format +msgid "Got message: \"%1$s\" from: %2$s" +msgstr "" + +#: src/InstanceRoutes.tsx:127 +#, c-format +msgid "No default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:128 +#, c-format +msgid "" +"in order to use merchant backoffice, you should create the default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:288 +#, c-format +msgid "Server reported a problem: HTTP status #%1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:289 +#, 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:115 +#: src/paths/instance/orders/create/CreatePage.tsx:325 +#: 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/transfers/create/CreatePage.tsx:89 +#: src/paths/instance/update/UpdatePage.tsx:134 +#, 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 +#: src/paths/instance/transfers/list/Table.tsx:140 +#, 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/InputLocation.tsx:28 +#, c-format +msgid "Country" +msgstr "" + +#: src/components/form/InputLocation.tsx:30 +#: src/paths/admin/create/CreatePage.tsx:99 +#: src/paths/instance/transfers/list/Table.tsx:124 +#: src/paths/instance/update/UpdatePage.tsx:118 +#, c-format +msgid "Address" +msgstr "" + +#: src/components/form/InputLocation.tsx:34 +#, c-format +msgid "Building number" +msgstr "" + +#: src/components/form/InputLocation.tsx:35 +#, c-format +msgid "Building name" +msgstr "" + +#: src/components/form/InputLocation.tsx:36 +#, c-format +msgid "Street" +msgstr "" + +#: src/components/form/InputLocation.tsx:37 +#, c-format +msgid "Post code" +msgstr "" + +#: src/components/form/InputLocation.tsx:38 +#, c-format +msgid "Town location" +msgstr "" + +#: src/components/form/InputLocation.tsx:39 +#, c-format +msgid "Town" +msgstr "" + +#: src/components/form/InputLocation.tsx:40 +#, c-format +msgid "District" +msgstr "" + +#: src/components/form/InputLocation.tsx:41 +#, c-format +msgid "Country subdivision" +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:87 src/paths/admin/list/Table.tsx:110 +#: src/paths/instance/details/DetailPage.tsx:76 +#: src/paths/instance/update/UpdatePage.tsx:106 +#, 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:252 +#: src/paths/instance/orders/create/CreatePage.tsx:273 +#, 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:114 +#: src/paths/instance/orders/create/CreatePage.tsx:324 +#: 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/transfers/create/CreatePage.tsx:88 +#: src/paths/instance/update/UpdatePage.tsx:133 +#, c-format +msgid "Cancel" +msgstr "" + +#: src/components/form/InputStock.tsx:91 +#, c-format +msgid "Manage stock" +msgstr "" + +#: src/components/form/InputStock.tsx:93 +#, c-format +msgid "Infinite" +msgstr "" + +#: src/components/form/InputStock.tsx:105 +#, c-format +msgid "lost cannot be greater that current + incoming (max %1$s)" +msgstr "" + +#: src/components/form/InputStock.tsx:111 +#, c-format +msgid "current stock will change from %1$s to %2$s" +msgstr "" + +#: src/components/form/InputStock.tsx:112 +#, c-format +msgid "current stock will stay at %1$s" +msgstr "" + +#: src/components/form/InputStock.tsx:129 +#: src/paths/instance/products/list/Table.tsx:204 +#, c-format +msgid "Incoming" +msgstr "" + +#: src/components/form/InputStock.tsx:130 +#: src/paths/instance/products/list/Table.tsx:205 +#, c-format +msgid "Lost" +msgstr "" + +#: src/components/form/InputStock.tsx:142 +#, c-format +msgid "Current" +msgstr "" + +#: src/components/form/InputStock.tsx:145 +#, c-format +msgid "without stock" +msgstr "" + +#: src/components/form/InputStock.tsx:150 +#, c-format +msgid "Next restock" +msgstr "" + +#: src/components/form/InputStock.tsx:152 +#, c-format +msgid "Delivery address" +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 +#: src/paths/instance/transfers/create/CreatePage.tsx:84 +#, 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:258 +#: 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:65 +#, 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:85 src/paths/admin/list/Table.tsx:109 +#: src/paths/instance/transfers/list/Table.tsx:122 +#, 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:89 +#: src/paths/instance/update/UpdatePage.tsx:108 +#, c-format +msgid "Auth token" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:91 +#: src/paths/instance/details/DetailPage.tsx:77 +#: src/paths/instance/update/UpdatePage.tsx:110 +#, c-format +msgid "Account address" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:93 +#: src/paths/instance/update/UpdatePage.tsx:112 +#, c-format +msgid "Default max deposit fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:95 +#: src/paths/instance/update/UpdatePage.tsx:114 +#, c-format +msgid "Default max wire fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:97 +#: src/paths/instance/update/UpdatePage.tsx:116 +#, c-format +msgid "Default wire fee amortization" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:103 +#: src/paths/instance/update/UpdatePage.tsx:122 +#, c-format +msgid "Jurisdiction" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:107 +#: src/paths/instance/update/UpdatePage.tsx:126 +#, c-format +msgid "Default pay delay" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:109 +#: src/paths/instance/update/UpdatePage.tsx:128 +#, 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 +#: src/paths/instance/transfers/list/Table.tsx:71 +#, 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:237 +#, c-format +msgid "Inventory products" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:286 +#, c-format +msgid "Total price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:287 +#, c-format +msgid "Total tax" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:289 +#: src/paths/instance/orders/create/CreatePage.tsx:297 +#, c-format +msgid "Order price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:295 +#, c-format +msgid "Net" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:300 +#: 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:302 +#, c-format +msgid "Payments options" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:303 +#, c-format +msgid "Auto refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:304 +#, c-format +msgid "Refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:305 +#, c-format +msgid "Pay deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:307 +#, c-format +msgid "Delivery date" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:308 +#, c-format +msgid "Location" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:312 +#, c-format +msgid "Max fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:313 +#, c-format +msgid "Max wire fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:314 +#, c-format +msgid "Wire fee amortization" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:315 +#, c-format +msgid "Fullfilment url" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:318 +#, 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/create/CreatePage.tsx:50 +#: src/paths/instance/transfers/create/CreatePage.tsx:54 +#: src/paths/instance/transfers/create/CreatePage.tsx:55 +#: src/paths/instance/transfers/create/CreatePage.tsx:56 +#, c-format +msgid "cannot be empty" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:51 +#, c-format +msgid "check the id, doest look valid" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:52 +#, c-format +msgid "should have 52 characters, current %1$s" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:57 +#, c-format +msgid "URL doesn't have the right format" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:74 +#, c-format +msgid "Transfer ID" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:76 +#, c-format +msgid "Account Address" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:82 +#: src/paths/instance/transfers/list/Table.tsx:125 +#, c-format +msgid "Exchange URL" +msgstr "" + +#: src/paths/instance/transfers/create/index.tsx:49 +#, c-format +msgid "could not inform transfer" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:118 +#, c-format +msgid "load newer transfers" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:123 +#, c-format +msgid "Credit" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:126 +#, c-format +msgid "Confirmed" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:127 +#: src/paths/instance/transfers/list/index.tsx:60 +#, c-format +msgid "Verified" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:128 +#, c-format +msgid "Executed at" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "yes" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "no" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:140 +#, c-format +msgid "unknown" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:145 +#, c-format +msgid "load older transfers" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:154 +#, c-format +msgid "There is no transfer yet, add more pressing the + sign" +msgstr "" diff --git a/packages/backend/src/i18n/poheader b/packages/backend/src/i18n/poheader new file mode 100644 index 0000000..ee3fcd7 --- /dev/null +++ b/packages/backend/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/backend/src/i18n/strings-prelude b/packages/backend/src/i18n/strings-prelude new file mode 100644 index 0000000..cca13af --- /dev/null +++ b/packages/backend/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/backend/src/i18n/strings.ts b/packages/backend/src/i18n/strings.ts new file mode 100644 index 0000000..63e9694 --- /dev/null +++ b/packages/backend/src/i18n/strings.ts @@ -0,0 +1,3445 @@ +/* + 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": [ + "" + ], + "Country": [ + "" + ], + "Address": [ + "" + ], + "Building number": [ + "" + ], + "Building name": [ + "" + ], + "Street": [ + "" + ], + "Post code": [ + "" + ], + "Town location": [ + "" + ], + "Town": [ + "" + ], + "District": [ + "" + ], + "Country subdivision": [ + "" + ], + "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": [ + "" + ], + "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": [ + "" + ], + "cannot be empty": [ + "" + ], + "check the id, doest look valid": [ + "" + ], + "should have 52 characters, current %1$s": [ + "" + ], + "URL doesn't have the right format": [ + "" + ], + "Transfer ID": [ + "" + ], + "Account Address": [ + "" + ], + "Exchange URL": [ + "" + ], + "could not inform transfer": [ + "" + ], + "load newer transfers": [ + "" + ], + "Credit": [ + "" + ], + "Confirmed": [ + "" + ], + "Verified": [ + "" + ], + "Executed at": [ + "" + ], + "yes": [ + "" + ], + "no": [ + "" + ], + "unknown": [ + "" + ], + "load older transfers": [ + "" + ], + "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": [ + "" + ], + "Country": [ + "" + ], + "Address": [ + "" + ], + "Building number": [ + "" + ], + "Building name": [ + "" + ], + "Street": [ + "" + ], + "Post code": [ + "" + ], + "Town location": [ + "" + ], + "Town": [ + "" + ], + "District": [ + "" + ], + "Country subdivision": [ + "" + ], + "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": [ + "" + ], + "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": [ + "" + ], + "cannot be empty": [ + "" + ], + "check the id, doest look valid": [ + "" + ], + "should have 52 characters, current %1$s": [ + "" + ], + "URL doesn't have the right format": [ + "" + ], + "Transfer ID": [ + "" + ], + "Account Address": [ + "" + ], + "Exchange URL": [ + "" + ], + "could not inform transfer": [ + "" + ], + "load newer transfers": [ + "" + ], + "Credit": [ + "" + ], + "Confirmed": [ + "" + ], + "Verified": [ + "" + ], + "Executed at": [ + "" + ], + "yes": [ + "" + ], + "no": [ + "" + ], + "unknown": [ + "" + ], + "load older transfers": [ + "" + ], + "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" + ], + "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" + ], + "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" + ], + "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 +" + ], + "cannot be empty": [ + "no puede ser vacÃo" + ], + "check the id, doest look valid": [ + "verificar el id, no parece válido" + ], + "should have 52 characters, current %1$s": [ + "deberÃa tener 52 caracteres, actualmente %1$s" + ], + "URL doesn't have the right format": [ + "La URL no tiene el formato correcto" + ], + "Transfer ID": [ + "Transferencias" + ], + "Account Address": [ + "Dirección de cuenta" + ], + "Exchange URL": [ + "URL del Exchange" + ], + "could not inform transfer": [ + "no se pudo crear la instancia" + ], + "load newer transfers": [ + "cargar nuevas ordenes" + ], + "Credit": [ + "Crédito" + ], + "Confirmed": [ + "Confirmar" + ], + "Verified": [ + "Verificado" + ], + "Executed at": [ + "creado" + ], + "yes": [ + "si" + ], + "no": [ + "no" + ], + "unknown": [ + "desconocido" + ], + "load older transfers": [ + "cargar viejas transferencias" + ], + "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": [ + "" + ], + "Country": [ + "" + ], + "Address": [ + "" + ], + "Building number": [ + "" + ], + "Building name": [ + "" + ], + "Street": [ + "" + ], + "Post code": [ + "" + ], + "Town location": [ + "" + ], + "Town": [ + "" + ], + "District": [ + "" + ], + "Country subdivision": [ + "" + ], + "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": [ + "" + ], + "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": [ + "" + ], + "cannot be empty": [ + "" + ], + "check the id, doest look valid": [ + "" + ], + "should have 52 characters, current %1$s": [ + "" + ], + "URL doesn't have the right format": [ + "" + ], + "Transfer ID": [ + "" + ], + "Account Address": [ + "" + ], + "Exchange URL": [ + "" + ], + "could not inform transfer": [ + "" + ], + "load newer transfers": [ + "" + ], + "Credit": [ + "" + ], + "Confirmed": [ + "" + ], + "Verified": [ + "" + ], + "Executed at": [ + "" + ], + "yes": [ + "" + ], + "no": [ + "" + ], + "unknown": [ + "" + ], + "load older transfers": [ + "" + ], + "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": [ + "" + ], + "Country": [ + "" + ], + "Address": [ + "" + ], + "Building number": [ + "" + ], + "Building name": [ + "" + ], + "Street": [ + "" + ], + "Post code": [ + "" + ], + "Town location": [ + "" + ], + "Town": [ + "" + ], + "District": [ + "" + ], + "Country subdivision": [ + "" + ], + "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": [ + "" + ], + "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": [ + "" + ], + "cannot be empty": [ + "" + ], + "check the id, doest look valid": [ + "" + ], + "should have 52 characters, current %1$s": [ + "" + ], + "URL doesn't have the right format": [ + "" + ], + "Transfer ID": [ + "" + ], + "Account Address": [ + "" + ], + "Exchange URL": [ + "" + ], + "could not inform transfer": [ + "" + ], + "load newer transfers": [ + "" + ], + "Credit": [ + "" + ], + "Confirmed": [ + "" + ], + "Verified": [ + "" + ], + "Executed at": [ + "" + ], + "yes": [ + "" + ], + "no": [ + "" + ], + "unknown": [ + "" + ], + "load older transfers": [ + "" + ], + "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": [ + "" + ], + "Country": [ + "" + ], + "Address": [ + "" + ], + "Building number": [ + "" + ], + "Building name": [ + "" + ], + "Street": [ + "" + ], + "Post code": [ + "" + ], + "Town location": [ + "" + ], + "Town": [ + "" + ], + "District": [ + "" + ], + "Country subdivision": [ + "" + ], + "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": [ + "" + ], + "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": [ + "" + ], + "cannot be empty": [ + "" + ], + "check the id, doest look valid": [ + "" + ], + "should have 52 characters, current %1$s": [ + "" + ], + "URL doesn't have the right format": [ + "" + ], + "Transfer ID": [ + "" + ], + "Account Address": [ + "" + ], + "Exchange URL": [ + "" + ], + "could not inform transfer": [ + "" + ], + "load newer transfers": [ + "" + ], + "Credit": [ + "" + ], + "Confirmed": [ + "" + ], + "Verified": [ + "" + ], + "Executed at": [ + "" + ], + "yes": [ + "" + ], + "no": [ + "" + ], + "unknown": [ + "" + ], + "load older transfers": [ + "" + ], + "There is no transfer yet, add more pressing the + sign": [ + "" + ] + } + } +}; + diff --git a/packages/backend/src/i18n/sv.po b/packages/backend/src/i18n/sv.po new file mode 100644 index 0000000..6b35bd0 --- /dev/null +++ b/packages/backend/src/i18n/sv.po @@ -0,0 +1,1057 @@ +# 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:118 +#: src/InstanceRoutes.tsx:299 +#, c-format +msgid "Access denied" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:51 src/InstanceRoutes.tsx:118 +#: src/InstanceRoutes.tsx:300 +#, 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:109 +#, c-format +msgid "HTTP status #%1$s: Server reported a problem" +msgstr "" + +#: src/InstanceRoutes.tsx:110 +#, c-format +msgid "Got message: \"%1$s\" from: %2$s" +msgstr "" + +#: src/InstanceRoutes.tsx:127 +#, c-format +msgid "No default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:128 +#, c-format +msgid "" +"in order to use merchant backoffice, you should create the default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:288 +#, c-format +msgid "Server reported a problem: HTTP status #%1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:289 +#, 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:115 +#: src/paths/instance/orders/create/CreatePage.tsx:325 +#: 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/transfers/create/CreatePage.tsx:89 +#: src/paths/instance/update/UpdatePage.tsx:134 +#, 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 +#: src/paths/instance/transfers/list/Table.tsx:140 +#, 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/InputLocation.tsx:28 +#, c-format +msgid "Country" +msgstr "" + +#: src/components/form/InputLocation.tsx:30 +#: src/paths/admin/create/CreatePage.tsx:99 +#: src/paths/instance/transfers/list/Table.tsx:124 +#: src/paths/instance/update/UpdatePage.tsx:118 +#, c-format +msgid "Address" +msgstr "" + +#: src/components/form/InputLocation.tsx:34 +#, c-format +msgid "Building number" +msgstr "" + +#: src/components/form/InputLocation.tsx:35 +#, c-format +msgid "Building name" +msgstr "" + +#: src/components/form/InputLocation.tsx:36 +#, c-format +msgid "Street" +msgstr "" + +#: src/components/form/InputLocation.tsx:37 +#, c-format +msgid "Post code" +msgstr "" + +#: src/components/form/InputLocation.tsx:38 +#, c-format +msgid "Town location" +msgstr "" + +#: src/components/form/InputLocation.tsx:39 +#, c-format +msgid "Town" +msgstr "" + +#: src/components/form/InputLocation.tsx:40 +#, c-format +msgid "District" +msgstr "" + +#: src/components/form/InputLocation.tsx:41 +#, c-format +msgid "Country subdivision" +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:87 src/paths/admin/list/Table.tsx:110 +#: src/paths/instance/details/DetailPage.tsx:76 +#: src/paths/instance/update/UpdatePage.tsx:106 +#, 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:252 +#: src/paths/instance/orders/create/CreatePage.tsx:273 +#, 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:114 +#: src/paths/instance/orders/create/CreatePage.tsx:324 +#: 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/transfers/create/CreatePage.tsx:88 +#: src/paths/instance/update/UpdatePage.tsx:133 +#, c-format +msgid "Cancel" +msgstr "" + +#: src/components/form/InputStock.tsx:91 +#, c-format +msgid "Manage stock" +msgstr "" + +#: src/components/form/InputStock.tsx:93 +#, c-format +msgid "Infinite" +msgstr "" + +#: src/components/form/InputStock.tsx:105 +#, c-format +msgid "lost cannot be greater that current + incoming (max %1$s)" +msgstr "" + +#: src/components/form/InputStock.tsx:111 +#, c-format +msgid "current stock will change from %1$s to %2$s" +msgstr "" + +#: src/components/form/InputStock.tsx:112 +#, c-format +msgid "current stock will stay at %1$s" +msgstr "" + +#: src/components/form/InputStock.tsx:129 +#: src/paths/instance/products/list/Table.tsx:204 +#, c-format +msgid "Incoming" +msgstr "" + +#: src/components/form/InputStock.tsx:130 +#: src/paths/instance/products/list/Table.tsx:205 +#, c-format +msgid "Lost" +msgstr "" + +#: src/components/form/InputStock.tsx:142 +#, c-format +msgid "Current" +msgstr "" + +#: src/components/form/InputStock.tsx:145 +#, c-format +msgid "without stock" +msgstr "" + +#: src/components/form/InputStock.tsx:150 +#, c-format +msgid "Next restock" +msgstr "" + +#: src/components/form/InputStock.tsx:152 +#, c-format +msgid "Delivery address" +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 +#: src/paths/instance/transfers/create/CreatePage.tsx:84 +#, 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:258 +#: 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:65 +#, 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:85 src/paths/admin/list/Table.tsx:109 +#: src/paths/instance/transfers/list/Table.tsx:122 +#, 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:89 +#: src/paths/instance/update/UpdatePage.tsx:108 +#, c-format +msgid "Auth token" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:91 +#: src/paths/instance/details/DetailPage.tsx:77 +#: src/paths/instance/update/UpdatePage.tsx:110 +#, c-format +msgid "Account address" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:93 +#: src/paths/instance/update/UpdatePage.tsx:112 +#, c-format +msgid "Default max deposit fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:95 +#: src/paths/instance/update/UpdatePage.tsx:114 +#, c-format +msgid "Default max wire fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:97 +#: src/paths/instance/update/UpdatePage.tsx:116 +#, c-format +msgid "Default wire fee amortization" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:103 +#: src/paths/instance/update/UpdatePage.tsx:122 +#, c-format +msgid "Jurisdiction" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:107 +#: src/paths/instance/update/UpdatePage.tsx:126 +#, c-format +msgid "Default pay delay" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:109 +#: src/paths/instance/update/UpdatePage.tsx:128 +#, 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 +#: src/paths/instance/transfers/list/Table.tsx:71 +#, 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:237 +#, c-format +msgid "Inventory products" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:286 +#, c-format +msgid "Total price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:287 +#, c-format +msgid "Total tax" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:289 +#: src/paths/instance/orders/create/CreatePage.tsx:297 +#, c-format +msgid "Order price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:295 +#, c-format +msgid "Net" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:300 +#: 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:302 +#, c-format +msgid "Payments options" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:303 +#, c-format +msgid "Auto refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:304 +#, c-format +msgid "Refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:305 +#, c-format +msgid "Pay deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:307 +#, c-format +msgid "Delivery date" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:308 +#, c-format +msgid "Location" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:312 +#, c-format +msgid "Max fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:313 +#, c-format +msgid "Max wire fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:314 +#, c-format +msgid "Wire fee amortization" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:315 +#, c-format +msgid "Fullfilment url" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:318 +#, 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/create/CreatePage.tsx:50 +#: src/paths/instance/transfers/create/CreatePage.tsx:54 +#: src/paths/instance/transfers/create/CreatePage.tsx:55 +#: src/paths/instance/transfers/create/CreatePage.tsx:56 +#, c-format +msgid "cannot be empty" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:51 +#, c-format +msgid "check the id, doest look valid" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:52 +#, c-format +msgid "should have 52 characters, current %1$s" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:57 +#, c-format +msgid "URL doesn't have the right format" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:74 +#, c-format +msgid "Transfer ID" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:76 +#, c-format +msgid "Account Address" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:82 +#: src/paths/instance/transfers/list/Table.tsx:125 +#, c-format +msgid "Exchange URL" +msgstr "" + +#: src/paths/instance/transfers/create/index.tsx:49 +#, c-format +msgid "could not inform transfer" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:118 +#, c-format +msgid "load newer transfers" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:123 +#, c-format +msgid "Credit" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:126 +#, c-format +msgid "Confirmed" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:127 +#: src/paths/instance/transfers/list/index.tsx:60 +#, c-format +msgid "Verified" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:128 +#, c-format +msgid "Executed at" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "yes" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "no" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:140 +#, c-format +msgid "unknown" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:145 +#, c-format +msgid "load older transfers" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:154 +#, c-format +msgid "There is no transfer yet, add more pressing the + sign" +msgstr "" diff --git a/packages/backend/src/i18n/taler-merchant-backoffice.pot b/packages/backend/src/i18n/taler-merchant-backoffice.pot new file mode 100644 index 0000000..21fd863 --- /dev/null +++ b/packages/backend/src/i18n/taler-merchant-backoffice.pot @@ -0,0 +1,1054 @@ +# 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:118 +#: src/InstanceRoutes.tsx:299 +#, c-format +msgid "Access denied" +msgstr "" + +#: src/ApplicationReadyRoutes.tsx:51 src/InstanceRoutes.tsx:118 +#: src/InstanceRoutes.tsx:300 +#, 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:109 +#, c-format +msgid "HTTP status #%1$s: Server reported a problem" +msgstr "" + +#: src/InstanceRoutes.tsx:110 +#, c-format +msgid "Got message: \"%1$s\" from: %2$s" +msgstr "" + +#: src/InstanceRoutes.tsx:127 +#, c-format +msgid "No default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:128 +#, c-format +msgid "" +"in order to use merchant backoffice, you should create the default instance" +msgstr "" + +#: src/InstanceRoutes.tsx:288 +#, c-format +msgid "Server reported a problem: HTTP status #%1$s" +msgstr "" + +#: src/InstanceRoutes.tsx:289 +#, 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:115 +#: src/paths/instance/orders/create/CreatePage.tsx:325 +#: 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/transfers/create/CreatePage.tsx:89 +#: src/paths/instance/update/UpdatePage.tsx:134 +#, 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 +#: src/paths/instance/transfers/list/Table.tsx:140 +#, 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/InputLocation.tsx:28 +#, c-format +msgid "Country" +msgstr "" + +#: src/components/form/InputLocation.tsx:30 +#: src/paths/admin/create/CreatePage.tsx:99 +#: src/paths/instance/transfers/list/Table.tsx:124 +#: src/paths/instance/update/UpdatePage.tsx:118 +#, c-format +msgid "Address" +msgstr "" + +#: src/components/form/InputLocation.tsx:34 +#, c-format +msgid "Building number" +msgstr "" + +#: src/components/form/InputLocation.tsx:35 +#, c-format +msgid "Building name" +msgstr "" + +#: src/components/form/InputLocation.tsx:36 +#, c-format +msgid "Street" +msgstr "" + +#: src/components/form/InputLocation.tsx:37 +#, c-format +msgid "Post code" +msgstr "" + +#: src/components/form/InputLocation.tsx:38 +#, c-format +msgid "Town location" +msgstr "" + +#: src/components/form/InputLocation.tsx:39 +#, c-format +msgid "Town" +msgstr "" + +#: src/components/form/InputLocation.tsx:40 +#, c-format +msgid "District" +msgstr "" + +#: src/components/form/InputLocation.tsx:41 +#, c-format +msgid "Country subdivision" +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:87 src/paths/admin/list/Table.tsx:110 +#: src/paths/instance/details/DetailPage.tsx:76 +#: src/paths/instance/update/UpdatePage.tsx:106 +#, 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:252 +#: src/paths/instance/orders/create/CreatePage.tsx:273 +#, 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:114 +#: src/paths/instance/orders/create/CreatePage.tsx:324 +#: 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/transfers/create/CreatePage.tsx:88 +#: src/paths/instance/update/UpdatePage.tsx:133 +#, c-format +msgid "Cancel" +msgstr "" + +#: src/components/form/InputStock.tsx:91 +#, c-format +msgid "Manage stock" +msgstr "" + +#: src/components/form/InputStock.tsx:93 +#, c-format +msgid "Infinite" +msgstr "" + +#: src/components/form/InputStock.tsx:105 +#, c-format +msgid "lost cannot be greater that current + incoming (max %1$s)" +msgstr "" + +#: src/components/form/InputStock.tsx:111 +#, c-format +msgid "current stock will change from %1$s to %2$s" +msgstr "" + +#: src/components/form/InputStock.tsx:112 +#, c-format +msgid "current stock will stay at %1$s" +msgstr "" + +#: src/components/form/InputStock.tsx:129 +#: src/paths/instance/products/list/Table.tsx:204 +#, c-format +msgid "Incoming" +msgstr "" + +#: src/components/form/InputStock.tsx:130 +#: src/paths/instance/products/list/Table.tsx:205 +#, c-format +msgid "Lost" +msgstr "" + +#: src/components/form/InputStock.tsx:142 +#, c-format +msgid "Current" +msgstr "" + +#: src/components/form/InputStock.tsx:145 +#, c-format +msgid "without stock" +msgstr "" + +#: src/components/form/InputStock.tsx:150 +#, c-format +msgid "Next restock" +msgstr "" + +#: src/components/form/InputStock.tsx:152 +#, c-format +msgid "Delivery address" +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 +#: src/paths/instance/transfers/create/CreatePage.tsx:84 +#, 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:258 +#: 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:65 +#, 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:85 src/paths/admin/list/Table.tsx:109 +#: src/paths/instance/transfers/list/Table.tsx:122 +#, 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:89 +#: src/paths/instance/update/UpdatePage.tsx:108 +#, c-format +msgid "Auth token" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:91 +#: src/paths/instance/details/DetailPage.tsx:77 +#: src/paths/instance/update/UpdatePage.tsx:110 +#, c-format +msgid "Account address" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:93 +#: src/paths/instance/update/UpdatePage.tsx:112 +#, c-format +msgid "Default max deposit fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:95 +#: src/paths/instance/update/UpdatePage.tsx:114 +#, c-format +msgid "Default max wire fee" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:97 +#: src/paths/instance/update/UpdatePage.tsx:116 +#, c-format +msgid "Default wire fee amortization" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:103 +#: src/paths/instance/update/UpdatePage.tsx:122 +#, c-format +msgid "Jurisdiction" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:107 +#: src/paths/instance/update/UpdatePage.tsx:126 +#, c-format +msgid "Default pay delay" +msgstr "" + +#: src/paths/admin/create/CreatePage.tsx:109 +#: src/paths/instance/update/UpdatePage.tsx:128 +#, 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 +#: src/paths/instance/transfers/list/Table.tsx:71 +#, 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:237 +#, c-format +msgid "Inventory products" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:286 +#, c-format +msgid "Total price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:287 +#, c-format +msgid "Total tax" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:289 +#: src/paths/instance/orders/create/CreatePage.tsx:297 +#, c-format +msgid "Order price" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:295 +#, c-format +msgid "Net" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:300 +#: 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:302 +#, c-format +msgid "Payments options" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:303 +#, c-format +msgid "Auto refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:304 +#, c-format +msgid "Refund deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:305 +#, c-format +msgid "Pay deadline" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:307 +#, c-format +msgid "Delivery date" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:308 +#, c-format +msgid "Location" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:312 +#, c-format +msgid "Max fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:313 +#, c-format +msgid "Max wire fee" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:314 +#, c-format +msgid "Wire fee amortization" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:315 +#, c-format +msgid "Fullfilment url" +msgstr "" + +#: src/paths/instance/orders/create/CreatePage.tsx:318 +#, 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/create/CreatePage.tsx:50 +#: src/paths/instance/transfers/create/CreatePage.tsx:54 +#: src/paths/instance/transfers/create/CreatePage.tsx:55 +#: src/paths/instance/transfers/create/CreatePage.tsx:56 +#, c-format +msgid "cannot be empty" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:51 +#, c-format +msgid "check the id, doest look valid" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:52 +#, c-format +msgid "should have 52 characters, current %1$s" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:57 +#, c-format +msgid "URL doesn't have the right format" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:74 +#, c-format +msgid "Transfer ID" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:76 +#, c-format +msgid "Account Address" +msgstr "" + +#: src/paths/instance/transfers/create/CreatePage.tsx:82 +#: src/paths/instance/transfers/list/Table.tsx:125 +#, c-format +msgid "Exchange URL" +msgstr "" + +#: src/paths/instance/transfers/create/index.tsx:49 +#, c-format +msgid "could not inform transfer" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:118 +#, c-format +msgid "load newer transfers" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:123 +#, c-format +msgid "Credit" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:126 +#, c-format +msgid "Confirmed" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:127 +#: src/paths/instance/transfers/list/index.tsx:60 +#, c-format +msgid "Verified" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:128 +#, c-format +msgid "Executed at" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "yes" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:138 +#: src/paths/instance/transfers/list/Table.tsx:139 +#, c-format +msgid "no" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:140 +#, c-format +msgid "unknown" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:145 +#, c-format +msgid "load older transfers" +msgstr "" + +#: src/paths/instance/transfers/list/Table.tsx:154 +#, c-format +msgid "There is no transfer yet, add more pressing the + sign" +msgstr "" diff --git a/packages/backend/src/index.tsx b/packages/backend/src/index.tsx new file mode 100644 index 0000000..0babb26 --- /dev/null +++ b/packages/backend/src/index.tsx @@ -0,0 +1,67 @@ +/* + 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 { h, VNode, Fragment } from 'preact'; +import { BackendContextProvider } from './context/backend'; +import { TranslationProvider } from './context/translation'; +// import { Page as RequestPayment } from './RequestPayment'; +import "./css/pure-min.css" +import { Route, Router } from 'preact-router'; +// import OfferTip from './pages/OfferTip'; +// import {OfferRefund} from './pages/OfferRefund'; +// import DepletedTip from './pages/DepletedTip'; +// import RequestPayment from './pages/RequestPayment'; +// import ShowOrderDetails from './pages/ShowOrderDetails'; + +export default function Application(): VNode { + return ( + // <FetchContextProvider> + <BackendContextProvider> + <TranslationProvider> + <ApplicationStatusRoutes /> + </TranslationProvider> + </BackendContextProvider> + // </FetchContextProvider> + ); +} + +function Footer() { + return <div class="talerbar"> + <p>You can learn more about GNU Taler on our <a href="https://taler.net/">website</a>.<br /> + Copyright © 2014—2021 Taler Systems SA</p> + </div> +} + +function ApplicationStatusRoutes(): VNode { + return <Fragment> + <Router> + {/* <Route path="offer_tip" component={OfferTip} /> + <Route path="offer_refund" component={OfferRefund} /> + <Route path="depleted_tip" component={DepletedTip} /> + <Route path="request_payment" component={RequestPayment} /> + <Route path="show_order_details" component={ShowOrderDetails} /> */} + <Route default component={() => <div> + hello! + </div>} /> + </Router> + <Footer /> + </Fragment> +} diff --git a/packages/backend/src/pages/DepletedTip.stories.tsx b/packages/backend/src/pages/DepletedTip.stories.tsx new file mode 100644 index 0000000..c20f6dc --- /dev/null +++ b/packages/backend/src/pages/DepletedTip.stories.tsx @@ -0,0 +1,40 @@ +/* + 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 { h, VNode, FunctionalComponent } from 'preact'; +import { DepletedTip as TestedComponent } from './DepletedTip'; + + +export default { + title: 'DepletedTip', + component: TestedComponent, + argTypes: { + }, +}; + +function createExample<Props>(Component: FunctionalComponent<Props>, props: Partial<Props>) { + const r = (args: any) => <Component {...args} /> + r.args = props + return r +} + +export const Example = createExample(TestedComponent, { +}); diff --git a/packages/backend/src/pages/DepletedTip.tsx b/packages/backend/src/pages/DepletedTip.tsx new file mode 100644 index 0000000..f9cf9bb --- /dev/null +++ b/packages/backend/src/pages/DepletedTip.tsx @@ -0,0 +1,45 @@ +/* + 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 { h, render, VNode } from 'preact'; + +export function DepletedTip(): VNode { + return <div> + You have already collected this tip. + </div> +} + +export function Title(): VNode { + return <title>Status of your tip</title> +} + + +export function mountIntoBody(): void { + try { + const params = new URL(window.location.href).searchParams + render(<DepletedTip + // taler_refund_uri={params.get('taler_refund_uri') || undefined} + />, document.body); + } catch (e) { + console.error("got error", e); + document.body.innerText = `Fatal error: "${e.message}". Please report this bug at https://bugs.gnunet.org/.`; + } +} + diff --git a/packages/backend/src/pages/OfferRefund.stories.tsx b/packages/backend/src/pages/OfferRefund.stories.tsx new file mode 100644 index 0000000..f1b2f3a --- /dev/null +++ b/packages/backend/src/pages/OfferRefund.stories.tsx @@ -0,0 +1,40 @@ +/* + 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 { h, VNode, FunctionalComponent } from 'preact'; +import { OfferRefund as TestedComponent } from './OfferRefund'; + + +export default { + title: 'OfferRefund', + component: TestedComponent, + argTypes: { + }, +}; + +function createExample<Props>(Component: FunctionalComponent<Props>, props: Partial<Props>) { + const r = (args: any) => <Component {...args} /> + r.args = props + return r +} + +export const Example = createExample(TestedComponent, { +}); diff --git a/packages/backend/src/pages/OfferRefund.tsx b/packages/backend/src/pages/OfferRefund.tsx new file mode 100644 index 0000000..6c6b77e --- /dev/null +++ b/packages/backend/src/pages/OfferRefund.tsx @@ -0,0 +1,103 @@ +/* + 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 { render, h, VNode } from 'preact'; +import { useEffect } from 'preact/hooks'; + +export function OfferRefund(): VNode { + useEffect(() => { + const checkUrl = new URL("{{& order_status_url }}"); + checkUrl.searchParams.set("await_refund_obtained", "yes"); + const delayMs = 500; + function check() { + let retried = false; + function retryOnce() { + if (!retried) { + retried = true; + check(); + } + } + const req = new XMLHttpRequest(); + req.onreadystatechange = function () { + if (req.readyState === XMLHttpRequest.DONE) { + if (req.status === 200) { + try { + const resp = JSON.parse(req.responseText); + if (!resp.refund_pending) { + window.location.reload(true); + } + } catch (e) { + console.error("could not parse response:", e); + } + } + setTimeout(retryOnce, delayMs); + } + }; + req.onerror = function () { + setTimeout(retryOnce, delayMs); + } + req.open("GET", checkUrl.href); + req.send(); + } + + setTimeout(check, delayMs); + }) + return <section id="main" class="content"> + <h1 >Collect Taler refund</h1> + <div class="taler-installed-hide"> + <p> + Scan this QR code with your Taler mobile wallet: + </p> + <div class="qr"> + {/* {{{taler_refund_qrcode_svg}}} */} + </div> + <p> + <button onClick={() => { + window.location.href = '{{taler_refund_uri}}' + }}> + Or open your Taller wallet + </button> + </p> + <p> + <a href="https://wallet.taler.net/">Don't have a Taler wallet yet? Install it!</a> + </p> + </div> + <hr /> + </section> +} + +export function Title(): VNode { + return <title>Refund available for {`{order_summary}`}</title> +} + +export function mountIntoBody(): void { + try { + const params = new URL(window.location.href).searchParams + render(<OfferRefund + // taler_refund_uri={params.get('taler_refund_uri') || undefined} + />, document.body); + } catch (e) { + console.error("got error", e); + document.body.innerText = `Fatal error: "${e.message}". Please report this bug at https://bugs.gnunet.org/.`; + } +} + + + diff --git a/packages/backend/src/pages/OfferTip.stories.tsx b/packages/backend/src/pages/OfferTip.stories.tsx new file mode 100644 index 0000000..09bffb8 --- /dev/null +++ b/packages/backend/src/pages/OfferTip.stories.tsx @@ -0,0 +1,40 @@ +/* + 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 { h, VNode, FunctionalComponent } from 'preact'; +import { OfferTip as TestedComponent } from './OfferTip'; + + +export default { + title: 'OfferTip', + component: TestedComponent, + argTypes: { + }, +}; + +function createExample<Props>(Component: FunctionalComponent<Props>, props: Partial<Props>) { + const r = (args: any) => <Component {...args} /> + r.args = props + return r +} + +export const Example = createExample(TestedComponent, { +}); diff --git a/packages/backend/src/pages/OfferTip.tsx b/packages/backend/src/pages/OfferTip.tsx new file mode 100644 index 0000000..fd14354 --- /dev/null +++ b/packages/backend/src/pages/OfferTip.tsx @@ -0,0 +1,113 @@ +/* + 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 { render, h, VNode, Fragment } from 'preact'; +import { useEffect } from 'preact/hooks'; +import { styled } from "@linaria/react" +import "../css/pure-min.css" +import "../css/style.css" + +interface Props { + taler_refund_uri?: string, + tip_status_url?: string, + taler_tip_qrcode_svg?: string, +} +export function OfferTip({ taler_refund_uri, tip_status_url, taler_tip_qrcode_svg }: Props): VNode { + useEffect(() => { + const delayMs = 500; + function check() { + let retried = false; + function retryOnce() { + if (!retried) { + retried = true; + check(); + } + } + const req = new XMLHttpRequest(); + req.onreadystatechange = function () { + if (req.readyState === XMLHttpRequest.DONE) { + if (req.status === 410) { + window.location.reload(true); + } + setTimeout(retryOnce, delayMs); + } + }; + req.onerror = function () { + setTimeout(retryOnce, delayMs); + } + req.open("GET", taler_refund_uri || ''); + req.send(); + } + + setTimeout(check, delayMs); + }) + return <Fragment> + <section id="main" class="content"> + <h1>Collect Taler tip</h1> + <div class="taler-installed-hide"> + <p> + Scan this QR code with your Taler mobile wallet: + </p> + <div class="qr"> + {taler_tip_qrcode_svg} + </div> + <p> + <button onClick={() => { + window.location.href = tip_status_url || '#' + }}> + Or open your Taller wallet + </button> + </p> + <p> + <a href="https://wallet.taler.net/">Don't have a Taler wallet yet? Install it!</a> + </p> + </div> + <hr /> + </section> + <Footer /> + </Fragment> +} + +function Footer() { + return <div class="talerbar"> + <p>You can learn more about GNU Taler on our <a href="https://taler.net/">website</a>.<br /> + Copyright © 2014—2021 Taler Systems SA</p> + </div> +} + + +export function Title(): VNode { + return <title>Tip available</title> +} + +export function mountIntoBody(): void { + try { + const params = new URL(window.location.href).searchParams + render(<OfferTip + taler_refund_uri={params.get('taler_refund_uri') || undefined} + taler_tip_qrcode_svg={params.get('taler_tip_qrcode_svg') || undefined} + tip_status_url={params.get('tip_status_url') || undefined} + />, document.body); + } catch (e) { + console.error("got error", e); + document.body.innerText = `Fatal error: "${e.message}". Please report this bug at https://bugs.gnunet.org/.`; + } +} + diff --git a/packages/backend/src/pages/RequestPayment.stories.tsx b/packages/backend/src/pages/RequestPayment.stories.tsx new file mode 100644 index 0000000..1aed570 --- /dev/null +++ b/packages/backend/src/pages/RequestPayment.stories.tsx @@ -0,0 +1,40 @@ +/* + 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 { h, VNode, FunctionalComponent } from 'preact'; +import { RequestPayment as TestedComponent } from './RequestPayment'; + + +export default { + title: 'RequestPayment', + component: TestedComponent, + argTypes: { + }, +}; + +function createExample<Props>(Component: FunctionalComponent<Props>, props: Partial<Props>) { + const r = (args: any) => <Component {...args} /> + r.args = props + return r +} + +export const Example = createExample(TestedComponent, { +}); diff --git a/packages/backend/src/pages/RequestPayment.tsx b/packages/backend/src/pages/RequestPayment.tsx new file mode 100644 index 0000000..d1fb8d4 --- /dev/null +++ b/packages/backend/src/pages/RequestPayment.tsx @@ -0,0 +1,125 @@ +/* + 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 { h, render, VNode } from 'preact'; +import { useEffect } from 'preact/hooks'; + +export function RequestPayment(): VNode { + useEffect(() => { + const longpollDelayMs = 60000; + const checkUrl = new URL("{{& order_status_url }}"); + checkUrl.searchParams.set("timeout_ms", longpollDelayMs.toString()); + function check() { + let retried = false; + function retryOnce() { + if (!retried) { + retried = true; + check(); + } + } + const req = new XMLHttpRequest(); + req.onreadystatechange = function () { + if (req.readyState === XMLHttpRequest.DONE) { + if (req.status === 200) { + try { + const resp = JSON.parse(req.responseText); + if (resp.fulfillment_url) { + window.location.replace(resp.fulfillment_url); + } + } catch (e) { + console.error("could not parse response:", e); + } + } + if (req.status === 202) { + try { + const resp = JSON.parse(req.responseText); + if (resp.fulfillment_url) { + window.location.replace(resp.fulfillment_url); + } + } catch (e) { + console.error("could not parse response:", e); + } + } + if (req.status === 402) { + try { + const resp = JSON.parse(req.responseText); + if (resp.already_paid_order_id && resp.fulfillment_url) { + window.location.replace(resp.fulfillment_url); + } + } catch (e) { + console.error("could not parse response:", e); + } + } + setTimeout(retryOnce, 500); + } + }; + req.onerror = function () { + setTimeout(retryOnce, 500); + } + req.ontimeout = function () { + setTimeout(retryOnce, 500); + } + req.timeout = longpollDelayMs; + req.open("GET", checkUrl.href); + req.send(); + } + setTimeout(check, 500); + }) + return <section id="main" class="content"> + <h1>Pay with Taler</h1> + <div class="taler-installed-hide"> + <p> + Scan this QR code with your mobile wallet: + </p> + <div class="qr"> + {/* {{{taler_pay_qrcode_svg}}} */} + </div> + <p> + <button onClick={() => { + window.location.href = '{{taler_refund_uri}}' + }}> + Or open your Taller wallet + </button> + </p> + <p> + <a href="https://wallet.taler.net/">Don't have a Taler wallet yet? Install it!</a> + </p> + </div> + <hr /> + </section> + +} +export function Title(): VNode { + return <title>Payment requested for {`{order_summary}`}</title> +} + +export function mountIntoBody(): void { + try { + const params = new URL(window.location.href).searchParams + render(<RequestPayment + // taler_refund_uri={params.get('taler_refund_uri') || undefined} + />, document.body); + } catch (e) { + console.error("got error", e); + document.body.innerText = `Fatal error: "${e.message}". Please report this bug at https://bugs.gnunet.org/.`; + } +} + + diff --git a/packages/backend/src/pages/ShowOrderDetails.stories.tsx b/packages/backend/src/pages/ShowOrderDetails.stories.tsx new file mode 100644 index 0000000..88fa393 --- /dev/null +++ b/packages/backend/src/pages/ShowOrderDetails.stories.tsx @@ -0,0 +1,40 @@ +/* + 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 { h, VNode, FunctionalComponent } from 'preact'; +import { ShowOrderDetails as TestedComponent } from './ShowOrderDetails'; + + +export default { + title: 'ShowOrderDetails', + component: TestedComponent, + argTypes: { + }, +}; + +function createExample<Props>(Component: FunctionalComponent<Props>, props: Partial<Props>) { + const r = (args: any) => <Component {...args} /> + r.args = props + return r +} + +export const Example = createExample(TestedComponent, { +}); diff --git a/packages/backend/src/pages/ShowOrderDetails.tsx b/packages/backend/src/pages/ShowOrderDetails.tsx new file mode 100644 index 0000000..4aae556 --- /dev/null +++ b/packages/backend/src/pages/ShowOrderDetails.tsx @@ -0,0 +1,125 @@ +/* + 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 { Fragment, render, h, VNode } from 'preact'; +import { useEffect } from 'preact/hooks'; + +export function ShowOrderDetails(): VNode { + useEffect(() => { + const longpollDelayMs = 60000; + const checkUrl = new URL("{{& order_status_url }}"); + checkUrl.searchParams.set("timeout_ms", longpollDelayMs.toString()); + function check() { + let retried = false; + function retryOnce() { + + if (!retried) { + retried = true; + check(); + } + } + const req = new XMLHttpRequest(); + req.onreadystatechange = function () { + if (req.readyState === XMLHttpRequest.DONE) { + if (req.status === 200) { + try { + const resp = JSON.parse(req.responseText); + if (resp.fulfillment_url) { + window.location.replace(resp.fulfillment_url); + } + } catch (e) { + console.error("could not parse response:", e); + } + } + if (req.status === 202) { + try { + const resp = JSON.parse(req.responseText); + if (resp.fulfillment_url) { + window.location.replace(resp.fulfillment_url); + } + } catch (e) { + console.error("could not parse response:", e); + } + } + if (req.status === 402) { + try { + const resp = JSON.parse(req.responseText); + if (resp.already_paid_order_id && resp.fulfillment_url) { + window.location.replace(resp.fulfillment_url); + } + } catch (e) { + console.error("could not parse response:", e); + } + } + setTimeout(retryOnce, 500); + } + }; + req.onerror = function () { + setTimeout(retryOnce, 500); + } + req.ontimeout = function () { + setTimeout(retryOnce, 500); + } + req.timeout = longpollDelayMs; + req.open("GET", checkUrl.href); + req.send(); + } + setTimeout(check, 500); + }) + return <Fragment> + <h1>Order details</h1> + + <div> + This is the default status page for your order for <b>{`{ order_summary }`}</b>. + </div> + + + <h2>Refund status</h2> + <div> + The merchant has granted you refunds on the purchase of <b>{`{ refund_amount }`}</b>. + </div> + + <h2>Full contract details</h2> + + {/* <!-- FIXME #6459: expand the contract JSON in all its glory here --> */} + <pre> + {/* {{{contract_terms!stringify }}} */} + </pre> + + </Fragment> + +} + +function Title(): VNode { + return <title>Status of your order for {`{order_summary}`}</title> +} + +export function mountIntoBody(): void { + try { + const params = new URL(window.location.href).searchParams + render(<ShowOrderDetails + // taler_refund_uri={params.get('taler_refund_uri') || undefined} + />, document.body); + } catch (e) { + console.error("got error", e); + document.body.innerText = `Fatal error: "${e.message}". Please report this bug at https://bugs.gnunet.org/.`; + } +} + diff --git a/packages/backend/src/utils/amount.ts b/packages/backend/src/utils/amount.ts new file mode 100644 index 0000000..062ddaf --- /dev/null +++ b/packages/backend/src/utils/amount.ts @@ -0,0 +1,69 @@ +/* + 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 { amountFractionalBase, AmountJson, Amounts } from "@gnu-taler/taler-util"; +import { MerchantBackend } from "../declaration"; + +/** + * sums two prices, + * @param one + * @param two + * @returns + */ +const sumPrices = (one: string, two: string) => { + const [currency, valueOne] = one.split(':') + const [, valueTwo] = two.split(':') + return `${currency}:${parseInt(valueOne, 10) + parseInt(valueTwo, 10)}` +} + +/** + * merge refund with the same description and a difference less than one minute + * @param prev list of refunds that will hold the merged refunds + * @param cur new refund to add to the list + * @returns list with the new refund, may be merged with the last + */ +export function mergeRefunds(prev: MerchantBackend.Orders.RefundDetails[], cur: MerchantBackend.Orders.RefundDetails) { + let tail; + + if (prev.length === 0 || //empty list + cur.timestamp.t_ms === 'never' || //current doesnt have timestamp + (tail = prev[prev.length - 1]).timestamp.t_ms === 'never' || // last doesnt have timestamp + cur.reason !== tail.reason || //different reason + Math.abs(cur.timestamp.t_ms - tail.timestamp.t_ms) > 1000 * 60) {//more than 1 minute difference + + prev.push(cur) + return prev + } + + prev[prev.length - 1] = { + ...tail, + amount: sumPrices(tail.amount, cur.amount) + } + + return prev +} + +export const rate = (one: string, two: string) => { + const a = Amounts.parseOrThrow(one) + const b = Amounts.parseOrThrow(two) + const af = toFloat(a) + const bf = toFloat(b) + if (bf === 0) return 0 + return af / bf +} + +function toFloat(amount: AmountJson) { + return amount.value + (amount.fraction / amountFractionalBase); +} diff --git a/packages/backend/src/utils/constants.ts b/packages/backend/src/utils/constants.ts new file mode 100644 index 0000000..37c46e4 --- /dev/null +++ b/packages/backend/src/utils/constants.ts @@ -0,0 +1,47 @@ +/* + 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) +*/ + +//https://tools.ietf.org/html/rfc8905 +export const PAYTO_REGEX = /^payto:\/\/[a-zA-Z][a-zA-Z0-9-.]+(\/[a-zA-Z0-9\-\.\~\(\)@_%:!$&'*+,;=]*)*\??((amount|receiver-name|sender-name|instruction|message)=[a-zA-Z0-9\-\.\~\(\)@_%:!$'*+,;=]*&?)*$/ +export const PAYTO_WIRE_METHOD_LOOKUP = /payto:\/\/([a-zA-Z][a-zA-Z0-9-.]+)\/.*/ + +export const AMOUNT_REGEX = /^[a-zA-Z][a-zA-Z]*:[0-9][0-9,]*\.?[0-9,]*$/ + +export const INSTANCE_ID_LOOKUP = /^\/instances\/([^/]*)\/?$/ + +export const AMOUNT_ZERO_REGEX = /^[a-zA-Z][a-zA-Z]*:0$/ + +export const CROCKFORD_BASE32_REGEX = /^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]+[*~$=U]*$/ + +export const URL_REGEX = /^((https?:)(\/\/\/?)([\w]*(?::[\w]*)?@)?([\d\w\.-]+)(?::(\d+))?)\/$/ + +// how much rows we add every time user hit load more +export const PAGE_SIZE = 20 +// how bigger can be the result set +// after this threshold, load more with move the cursor +export const MAX_RESULT_SIZE = PAGE_SIZE * 2 - 1; + +// how much we will wait for all request, in seconds +export const DEFAULT_REQUEST_TIMEOUT = 10; + +export const MAX_IMAGE_SIZE = 1024 * 1024; + +export const INSTANCE_ID_REGEX = /^[a-zA-Z0-9][a-zA-Z0-9_.@-]+$/ diff --git a/packages/backend/src/utils/table.ts b/packages/backend/src/utils/table.ts new file mode 100644 index 0000000..3d713a6 --- /dev/null +++ b/packages/backend/src/utils/table.ts @@ -0,0 +1,37 @@ +/* + 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 { WithId } from "../declaration"; + +/** +* +* @author Sebastian Javier Marchano (sebasjm) +*/ + +export interface Actions<T extends WithId> { + element: T; + type: 'DELETE' | 'UPDATE'; +} + +function notEmpty<TValue>(value: TValue | null | undefined): value is TValue { + return value !== null && value !== undefined; +} + +export function buildActions<T extends WithId>(intances: T[], selected: string[], action: 'DELETE'): Actions<T>[] { + return selected.map(id => intances.find(i => i.id === id)) + .filter(notEmpty) + .map(id => ({ element: id, type: action })) +} diff --git a/packages/backend/src/utils/types.ts b/packages/backend/src/utils/types.ts new file mode 100644 index 0000000..9e49d39 --- /dev/null +++ b/packages/backend/src/utils/types.ts @@ -0,0 +1,31 @@ +/* + 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 { VNode } from "preact" + +export interface KeyValue { + [key: string]: string; +} + +export interface Notification { + message: string; + description?: string | VNode; + type: MessageType; +} + +export type ValueOrFunction<T> = T | ((p: T) => T) +export type MessageType = 'INFO' | 'WARN' | 'ERROR' | 'SUCCESS' + |