diff options
author | Florian Dold <florian@dold.me> | 2022-02-15 17:45:26 +0100 |
---|---|---|
committer | Florian Dold <florian@dold.me> | 2022-02-15 17:45:26 +0100 |
commit | 465ccdaa06d30a995235fd6438172eb125243321 (patch) | |
tree | 1d6eefefd858a491ed36353c504abeecab1f1280 | |
parent | e6c1294c910e6b54d24d62981632cf5e5f79d33f (diff) |
subcommands for i18n tooling, unique message IDs
-rw-r--r-- | packages/pogen/src/po2ts.ts | 62 | ||||
-rw-r--r-- | packages/pogen/src/pogen.ts | 21 | ||||
-rw-r--r-- | packages/pogen/src/potextract.ts | 183 | ||||
-rw-r--r-- | packages/taler-wallet-webextension/package.json | 7 | ||||
-rw-r--r-- | packages/taler-wallet-webextension/src/i18n/taler-wallet-webex.pot | 243 |
5 files changed, 291 insertions, 225 deletions
diff --git a/packages/pogen/src/po2ts.ts b/packages/pogen/src/po2ts.ts index d0f4ed34d..ac85b9b76 100644 --- a/packages/pogen/src/po2ts.ts +++ b/packages/pogen/src/po2ts.ts @@ -23,38 +23,44 @@ import * as po2json from "po2json"; import * as fs from "fs"; import * as path from "path"; -const files = fs - .readdirSync("./src/i18n") - .filter((x) => x.endsWith(".po")) - .map((x) => path.join("./src/i18n/", x)); - -if (files.length === 0) { - console.error("no .po files found in src/i18n/"); - process.exit(1); -} +export function po2ts(): void { + const files = fs + .readdirSync("./src/i18n") + .filter((x) => x.endsWith(".po")) + .map((x) => path.join("./src/i18n/", x)); -console.log(files); + if (files.length === 0) { + console.error("no .po files found in src/i18n/"); + process.exit(1); + } -const chunks: string[] = []; + console.log(files); -for (const filename of files) { - const m = filename.match(/([a-zA-Z0-9-_]+).po/); + const chunks: string[] = []; - if (!m) { - console.error("error: unexpected filename (expected <lang>.po)"); - process.exit(1); - } + for (const filename of files) { + const m = filename.match(/([a-zA-Z0-9-_]+).po/); - const lang = m[1]; - const pojson = po2json.parseFileSync(filename, { - format: "jed1.x", - fuzzy: true, - }); - const s = - "strings['" + lang + "'] = " + JSON.stringify(pojson, null, " ") + ";\n\n"; - chunks.push(s); -} + if (!m) { + console.error("error: unexpected filename (expected <lang>.po)"); + process.exit(1); + } + + const lang = m[1]; + const pojson = po2json.parseFileSync(filename, { + format: "jed1.x", + fuzzy: true, + }); + const s = + "strings['" + + lang + + "'] = " + + JSON.stringify(pojson, null, " ") + + ";\n\n"; + chunks.push(s); + } -const tsContents = chunks.join(""); + const tsContents = chunks.join(""); -fs.writeFileSync("src/i18n/strings.ts", tsContents); + fs.writeFileSync("src/i18n/strings.ts", tsContents); +} diff --git a/packages/pogen/src/pogen.ts b/packages/pogen/src/pogen.ts new file mode 100644 index 000000000..7d128ce7a --- /dev/null +++ b/packages/pogen/src/pogen.ts @@ -0,0 +1,21 @@ +import { potextract } from "./potextract.js"; + +function usage(): never { + console.log("usage: pogen <extract|merge|emit>"); + process.exit(1); +} + +export function main() { + const subcommand = process.argv[2]; + if (process.argv.includes("--help") || !subcommand) { + usage(); + } + switch (subcommand) { + case "extract": + potextract(); + break; + default: + console.error(`unknown subcommand '${subcommand}'`); + usage(); + } +} diff --git a/packages/pogen/src/potextract.ts b/packages/pogen/src/potextract.ts index 5999d9e1c..5cc085ef8 100644 --- a/packages/pogen/src/potextract.ts +++ b/packages/pogen/src/potextract.ts @@ -14,21 +14,27 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ - /** * Imports. */ import * as ts from "typescript"; +import * as fs from "fs"; +import * as os from "os"; +import path = require("path/posix"); function wordwrap(str: string, width: number = 80): string[] { var regex = ".{1," + width + "}(\\s|$)|\\S+(\\s|$)"; return str.match(RegExp(regex, "g")); } -export function processFile(sourceFile: ts.SourceFile, outChunks: string[]) { - processNode(sourceFile); +function processFile( + sourceFile: ts.SourceFile, + outChunks: string[], + knownMessageIds: Set<string>, +) { let lastTokLine = 0; let preLastTokLine = 0; + processNode(sourceFile); function getTemplate(node: ts.Node): string { switch (node.kind) { @@ -140,7 +146,8 @@ export function processFile(sourceFile: ts.SourceFile, outChunks: string[]) { outChunks.push(`#. ${cl}\n`); } } - outChunks.push(`#: ${sourceFile.fileName}:${line + 1}\n`); + const fn = path.relative(process.cwd(), sourceFile.fileName); + outChunks.push(`#: ${fn}:${line + 1}\n`); outChunks.push(`#, c-format\n`); } @@ -148,7 +155,7 @@ export function processFile(sourceFile: ts.SourceFile, outChunks: string[]) { // Do escaping, wrap break at newlines let parts = msg .match(/(.*\n|.+$)/g) - .map((x) => x.replace(/\n/g, "\\n")) + .map((x) => x.replace(/\n/g, "\\n").replace(/"/g, '\\"')) .map((p) => wordwrap(p)) .reduce((a, b) => a.concat(b)); if (parts.length == 1) { @@ -188,7 +195,7 @@ export function processFile(sourceFile: ts.SourceFile, outChunks: string[]) { } } - function trim(s) { + function trim(s: string) { return s.replace(/^[ \n\t]*/, "").replace(/[ \n\t]*$/, ""); } @@ -284,10 +291,13 @@ export function processFile(sourceFile: ts.SourceFile, outChunks: string[]) { let content = getJsxContent(node); let { line } = ts.getLineAndCharacterOfPosition(sourceFile, node.pos); let comment = getComment(node); - formatMsgComment(line, comment); - formatMsgLine("msgid", content); - outChunks.push(`msgstr ""\n`); - outChunks.push("\n"); + if (!knownMessageIds.has(content)) { + knownMessageIds.add(content); + formatMsgComment(line, comment); + formatMsgLine("msgid", content); + outChunks.push(`msgstr ""\n`); + outChunks.push("\n"); + } return; } if (arrayEq(path, ["i18n", "TranslateSwitch"])) { @@ -304,11 +314,14 @@ export function processFile(sourceFile: ts.SourceFile, outChunks: string[]) { console.error("plural form missing"); process.exit(1); } - formatMsgLine("msgid", singularForm); - formatMsgLine("msgid_plural", pluralForm); - outChunks.push(`msgstr[0] ""\n`); - outChunks.push(`msgstr[1] ""\n`); - outChunks.push(`\n`); + if (!knownMessageIds.has(singularForm)) { + knownMessageIds.add(singularForm); + formatMsgLine("msgid", singularForm); + formatMsgLine("msgid_plural", pluralForm); + outChunks.push(`msgstr[0] ""\n`); + outChunks.push(`msgstr[1] ""\n`); + outChunks.push(`\n`); + } return; } break; @@ -333,13 +346,16 @@ export function processFile(sourceFile: ts.SourceFile, outChunks: string[]) { <ts.TaggedTemplateExpression>ce.arguments[1], ); let comment = getComment(ce); - - formatMsgComment(line, comment); - formatMsgLine("msgid", t1.template); - formatMsgLine("msgid_plural", t2.template); - outChunks.push(`msgstr[0] ""\n`); - outChunks.push(`msgstr[1] ""\n`); - outChunks.push("\n"); + const msgid = t1.template; + if (!knownMessageIds.has(msgid)) { + knownMessageIds.add(msgid); + formatMsgComment(line, comment); + formatMsgLine("msgid", t1.template); + formatMsgLine("msgid_plural", t2.template); + outChunks.push(`msgstr[0] ""\n`); + outChunks.push(`msgstr[1] ""\n`); + outChunks.push("\n"); + } // Important: no processing for child i18n expressions here return; @@ -351,10 +367,14 @@ export function processFile(sourceFile: ts.SourceFile, outChunks: string[]) { if (path[0] != "i18n") { break; } - formatMsgComment(line, comment); - formatMsgLine("msgid", template); - outChunks.push(`msgstr ""\n`); - outChunks.push("\n"); + const msgid = template; + if (!knownMessageIds.has(msgid)) { + knownMessageIds.add(msgid); + formatMsgComment(line, comment); + formatMsgLine("msgid", template); + outChunks.push(`msgstr ""\n`); + outChunks.push("\n"); + } break; } } @@ -363,51 +383,48 @@ export function processFile(sourceFile: ts.SourceFile, outChunks: string[]) { } } -const configPath = ts.findConfigFile( - /*searchPath*/ "./", - ts.sys.fileExists, - "tsconfig.json", -); -if (!configPath) { - throw new Error("Could not find a valid 'tsconfig.json'."); -} - -console.log(configPath); - -const cmdline = ts.getParsedCommandLineOfConfigFile( - configPath, - {}, - { - fileExists: ts.sys.fileExists, - getCurrentDirectory: ts.sys.getCurrentDirectory, - onUnRecoverableConfigFileDiagnostic: (e) => console.log(e), - readDirectory: ts.sys.readDirectory, - readFile: ts.sys.readFile, - useCaseSensitiveFileNames: true, - }, -); - -console.log(cmdline); - -const prog = ts.createProgram({ - options: cmdline.options, - rootNames: cmdline.fileNames, -}); - -const allFiles = prog.getSourceFiles(); - -const ownFiles = allFiles.filter( - (x) => - !x.isDeclarationFile && - !prog.isSourceFileFromExternalLibrary(x) && - !prog.isSourceFileDefaultLibrary(x), -); - -console.log(ownFiles.map((x) => x.fileName)); - -const chunks = []; +export function potextract() { + const configPath = ts.findConfigFile( + /*searchPath*/ "./", + ts.sys.fileExists, + "tsconfig.json", + ); + if (!configPath) { + throw new Error("Could not find a valid 'tsconfig.json'."); + } -chunks.push(`# SOME DESCRIPTIVE TITLE. + const cmdline = ts.getParsedCommandLineOfConfigFile( + configPath, + {}, + { + fileExists: ts.sys.fileExists, + getCurrentDirectory: ts.sys.getCurrentDirectory, + onUnRecoverableConfigFileDiagnostic: (e) => console.log(e), + readDirectory: ts.sys.readDirectory, + readFile: ts.sys.readFile, + useCaseSensitiveFileNames: true, + }, + ); + + const prog = ts.createProgram({ + options: cmdline.options, + rootNames: cmdline.fileNames, + }); + + const allFiles = prog.getSourceFiles(); + + const ownFiles = allFiles.filter( + (x) => + !x.isDeclarationFile && + !prog.isSourceFileFromExternalLibrary(x) && + !prog.isSourceFileDefaultLibrary(x), + ); + + //console.log(ownFiles.map((x) => x.fileName)); + + const chunks = []; + + chunks.push(`# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. @@ -424,10 +441,26 @@ msgstr "" "Language: \\n" "MIME-Version: 1.0\\n" "Content-Type: text/plain; charset=UTF-8\\n" -"Content-Transfer-Encoding: 8bit\\n"`); +"Content-Transfer-Encoding: 8bit\\n"\n\n`); -for (const f of ownFiles) { - processFile(f, chunks); -} + const knownMessageIds = new Set<string>(); + + for (const f of ownFiles) { + processFile(f, chunks, knownMessageIds); + } + + const pot = chunks.join(""); -console.log(chunks.join("")); + //console.log(pot); + + const packageJson = JSON.parse( + fs.readFileSync("./package.json", { encoding: "utf-8" }), + ); + + const poDomain = packageJson.pogen?.domain; + if (!poDomain) { + console.error("missing 'pogen.domain' field in package.json"); + process.exit(1); + } + fs.writeFileSync(`./src/i18n/${poDomain}.pot`, pot); +} diff --git a/packages/taler-wallet-webextension/package.json b/packages/taler-wallet-webextension/package.json index 3ae98284d..4c6f2a564 100644 --- a/packages/taler-wallet-webextension/package.json +++ b/packages/taler-wallet-webextension/package.json @@ -15,7 +15,9 @@ "build-storybook": "build-storybook", "storybook": "start-storybook -s . -p 6006", "pretty": "prettier --write src", - "watch": "tsc --watch & rollup -w -c" + "watch": "tsc --watch & rollup -w -c", + "i18n:extract": "pogen extract", + "i18n:msgmerge": "pogen msgmerge" }, "dependencies": { "@gnu-taler/taler-util": "workspace:*", @@ -71,5 +73,8 @@ "**" ], "exclude": [] + }, + "pogen": { + "domain": "taler-wallet-webex" } } diff --git a/packages/taler-wallet-webextension/src/i18n/taler-wallet-webex.pot b/packages/taler-wallet-webextension/src/i18n/taler-wallet-webex.pot index 67b09de1a..70aa9c708 100644 --- a/packages/taler-wallet-webextension/src/i18n/taler-wallet-webex.pot +++ b/packages/taler-wallet-webextension/src/i18n/taler-wallet-webex.pot @@ -1,21 +1,12 @@ -# 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/> +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # #, fuzzy msgid "" msgstr "" -"Project-Id-Version: Taler Wallet\n" +"Project-Id-Version: PACKAGE VERSION\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" @@ -25,266 +16,276 @@ msgstr "" "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/util/wire.ts:37 +#: src/NavigationBar.tsx:86 #, c-format -msgid "Invalid Wire" +msgid "Balance" msgstr "" -#: src/util/wire.ts:42 src/util/wire.ts:45 +#: src/NavigationBar.tsx:87 #, c-format -msgid "Invalid Test Wire Detail" +msgid "Pending" msgstr "" -#: src/util/wire.ts:47 +#: src/NavigationBar.tsx:88 #, c-format -msgid "Test Wire Acct #%1$s on %2$s" +msgid "Backup" msgstr "" -#: src/util/wire.ts:49 +#: src/NavigationBar.tsx:89 #, c-format -msgid "Unknown Wire Detail" +msgid "Settings" msgstr "" -#: src/webex/pages/benchmark.tsx:52 +#: src/NavigationBar.tsx:90 #, c-format -msgid "Operation" +msgid "Dev" msgstr "" -#: src/webex/pages/benchmark.tsx:53 +#: src/wallet/BackupPage.tsx:127 #, c-format -msgid "time (ms/op)" +msgid "Add provider" msgstr "" -#: src/webex/pages/pay.tsx:130 +#: src/wallet/BackupPage.tsx:137 #, c-format -msgid "The merchant %1$s offers you to purchase:" +msgid "Sync all backups" msgstr "" -#: src/webex/pages/pay.tsx:136 +#: src/wallet/BackupPage.tsx:139 #, c-format -msgid "The total price is %1$s (plus %2$s fees)." +msgid "Sync now" msgstr "" -#: src/webex/pages/pay.tsx:141 +#: src/popup/BalancePage.tsx:79 #, c-format -msgid "The total price is %1$s." +msgid "You have no balance to show. Need some %1$s getting started?" msgstr "" -#: src/webex/pages/pay.tsx:163 +#: src/wallet/ProviderAddPage.tsx:145 #, c-format -msgid "Retry" +msgid "< Back" msgstr "" -#: src/webex/pages/pay.tsx:173 +#: src/wallet/ProviderAddPage.tsx:156 #, c-format -msgid "Confirm payment" +msgid "Next" msgstr "" -#: src/webex/pages/popup.tsx:153 +#: src/wallet/ProviderDetailPage.tsx:57 #, c-format -msgid "Balance" +msgid "Loading..." msgstr "" -#: src/webex/pages/popup.tsx:154 +#: src/wallet/ProviderDetailPage.tsx:64 #, c-format -msgid "History" +msgid "There was an error loading the provider detail for \"%1$s\"" msgstr "" -#: src/webex/pages/popup.tsx:155 +#: src/wallet/ProviderDetailPage.tsx:75 #, c-format -msgid "Debug" +msgid "There is not known provider with url \"%1$s\". Redirecting back..." msgstr "" -#: src/webex/pages/popup.tsx:175 +#: src/wallet/ProviderDetailPage.tsx:131 #, c-format -msgid "You have no balance to show. Need some %1$s getting started?" +msgid "Back up" msgstr "" -#: src/webex/pages/popup.tsx:238 +#: src/wallet/ProviderDetailPage.tsx:142 #, c-format -msgid "%1$s incoming" +msgid "Extend" msgstr "" -#: src/webex/pages/popup.tsx:250 +#: src/wallet/ProviderDetailPage.tsx:148 #, c-format -msgid "%1$s being spent" +msgid "" +"terms has changed, extending the service will imply accepting the new terms of " +"service" msgstr "" -#: src/webex/pages/popup.tsx:281 +#: src/wallet/ProviderDetailPage.tsx:158 #, c-format -msgid "Error: could not retrieve balance information." +msgid "old" msgstr "" -#: src/webex/pages/popup.tsx:390 +#: src/wallet/ProviderDetailPage.tsx:162 #, c-format -msgid "Invalid " +msgid "new" msgstr "" -#: src/webex/pages/popup.tsx:396 +#: src/wallet/ProviderDetailPage.tsx:169 #, c-format -msgid "Fees " +msgid "fee" msgstr "" -#: src/webex/pages/popup.tsx:434 +#: src/wallet/ProviderDetailPage.tsx:177 #, c-format -msgid "Refresh sessions has completed" +msgid "storage" msgstr "" -#: src/webex/pages/popup.tsx:451 +#: src/wallet/ProviderDetailPage.tsx:190 #, c-format -msgid "Order Refused" +msgid "< back" msgstr "" -#: src/webex/pages/popup.tsx:465 +#: src/wallet/ProviderDetailPage.tsx:194 #, c-format -msgid "Order redirected" +msgid "remove provider" msgstr "" -#: src/webex/pages/popup.tsx:482 +#: src/wallet/ProviderDetailPage.tsx:213 #, c-format -msgid "Payment aborted" +msgid "There is conflict with another backup from %1$s" msgstr "" -#: src/webex/pages/popup.tsx:512 +#: src/wallet/ProviderDetailPage.tsx:228 #, c-format -msgid "Payment Sent" +msgid "Unknown backup problem: %1$s" msgstr "" -#: src/webex/pages/popup.tsx:536 +#: src/wallet/ProviderDetailPage.tsx:247 #, c-format -msgid "Order accepted" +msgid "service paid" msgstr "" -#: src/webex/pages/popup.tsx:547 +#: src/popup/Settings.tsx:46 #, c-format -msgid "Reserve balance updated" +msgid "Permissions" msgstr "" -#: src/webex/pages/popup.tsx:559 +#: src/cta/TermsOfServiceSection.tsx:37 #, c-format -msgid "Payment refund" +msgid "Exchange doesn't have terms of service" msgstr "" -#: src/webex/pages/popup.tsx:584 +#: src/cta/TermsOfServiceSection.tsx:56 #, c-format -msgid "Withdrawn" +msgid "Review exchange terms of service" msgstr "" -#: src/webex/pages/popup.tsx:596 +#: src/cta/TermsOfServiceSection.tsx:63 #, c-format -msgid "Tip Accepted" +msgid "Review new version of terms of service" msgstr "" -#: src/webex/pages/popup.tsx:606 +#: src/cta/TermsOfServiceSection.tsx:75 #, c-format -msgid "Tip Declined" +msgid "Show terms of service" msgstr "" -#: src/webex/pages/popup.tsx:615 +#: src/cta/TermsOfServiceSection.tsx:83 #, c-format -msgid "%1$s" +msgid "I accept the exchange terms of service" msgstr "" -#: src/webex/pages/popup.tsx:707 +#: src/cta/TermsOfServiceSection.tsx:127 #, c-format -msgid "Your wallet has no events recorded." +msgid "Hide terms of service" msgstr "" -#: src/webex/pages/return-coins.tsx:124 +#: src/wallet/ExchangeAddConfirm.tsx:110 #, c-format -msgid "Wire to bank account" +msgid "Cancel" msgstr "" -#: src/webex/pages/return-coins.tsx:206 +#: src/wallet/ExchangeAddConfirm.tsx:114 #, c-format -msgid "Confirm" +msgid "Loading terms.." msgstr "" -#: src/webex/pages/return-coins.tsx:209 +#: src/wallet/ExchangeAddConfirm.tsx:121 #, c-format -msgid "Cancel" +msgid "Add exchange" msgstr "" -#: src/webex/pages/withdraw.tsx:73 +#: src/wallet/ExchangeAddConfirm.tsx:131 #, c-format -msgid "Could not get details for withdraw operation:" +msgid "Add exchange anyway" msgstr "" -#: src/webex/pages/withdraw.tsx:89 src/webex/pages/withdraw.tsx:183 +#: src/wallet/Settings.tsx:95 #, c-format -msgid "Chose different exchange provider" +msgid "Known exchanges" msgstr "" -#: src/webex/pages/withdraw.tsx:109 +#: src/wallet/Transaction.tsx:159 #, c-format -msgid "" -"Please select an exchange. You can review the details before after your " -"selection." +msgid "retry" +msgstr "" + +#: src/wallet/Transaction.tsx:163 +#, c-format +msgid "Forget" msgstr "" -#: src/webex/pages/withdraw.tsx:121 +#: src/wallet/Transaction.tsx:198 #, c-format -msgid "Select %1$s" +msgid "Confirm" msgstr "" -#: src/webex/pages/withdraw.tsx:143 +#: src/cta/Pay.tsx:211 #, c-format -msgid "Select custom exchange" +msgid "Pay with a mobile phone" msgstr "" -#: src/webex/pages/withdraw.tsx:163 +#: src/cta/Pay.tsx:211 #, c-format -msgid "You are about to withdraw %1$s from your bank account into your wallet." +msgid "Hide QR" msgstr "" -#: src/webex/pages/withdraw.tsx:174 +#: src/cta/Pay.tsx:241 #, c-format -msgid "Accept fees and withdraw" +msgid "Pay" msgstr "" -#: src/webex/pages/withdraw.tsx:192 +#: src/cta/Pay.tsx:265 #, c-format -msgid "Cancel withdraw operation" +msgid "Withdraw digital cash" msgstr "" -#: src/webex/renderHtml.tsx:249 +#: src/cta/Pay.tsx:295 #, c-format -msgid "Withdrawal fees:" +msgid "Digital cash payment" msgstr "" -#: src/webex/renderHtml.tsx:252 +#: src/cta/Withdraw.tsx:101 #, c-format -msgid "Rounding loss:" +msgid "Digital cash withdrawal" msgstr "" -#: src/webex/renderHtml.tsx:254 +#: src/cta/Withdraw.tsx:149 #, c-format -msgid "Earliest expiration (for deposit): %1$s" +msgid "Cancel exchange selection" msgstr "" -#: src/webex/renderHtml.tsx:262 +#: src/cta/Withdraw.tsx:150 #, c-format -msgid "# Coins" +msgid "Confirm exchange selection" msgstr "" -#: src/webex/renderHtml.tsx:263 +#: src/cta/Withdraw.tsx:155 #, c-format -msgid "Value" +msgid "Switch exchange" msgstr "" -#: src/webex/renderHtml.tsx:264 +#: src/cta/Withdraw.tsx:174 #, c-format -msgid "Withdraw Fee" +msgid "Confirm withdrawal" msgstr "" -#: src/webex/renderHtml.tsx:265 +#: src/cta/Withdraw.tsx:183 #, c-format -msgid "Refresh Fee" +msgid "Withdraw anyway" msgstr "" -#: src/webex/renderHtml.tsx:266 +#: src/cta/Withdraw.tsx:310 #, c-format -msgid "Deposit Fee" +msgid "missing withdraw uri" msgstr "" + +#: src/cta/Deposit.tsx:186 +#, c-format +msgid "Digital cash deposit" +msgstr "" + |