gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] 02/02: fix #7152


From: gnunet
Subject: [taler-wallet-core] 02/02: fix #7152
Date: Mon, 09 Jan 2023 12:39:04 +0100

This is an automated email from the git hooks/post-receive script.

sebasjm pushed a commit to branch master
in repository wallet-core.

commit 9b04d8bf3581d162cbd631892ca115df811c46f8
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Mon Jan 9 08:38:48 2023 -0300

    fix #7152
---
 packages/taler-wallet-webextension/package.json    |   2 +-
 .../src/components/AmountField.stories.tsx         |   2 +-
 .../src/components/AmountField.tsx                 |   3 +-
 .../src/components/BankDetailsByPaytoType.tsx      |  35 ++----
 .../src/components/Banner.tsx                      |   3 +-
 .../src/components/Checkbox.tsx                    |   5 +-
 .../src/components/CurrentAlerts.tsx               | 108 +++++++++++++++++++
 .../src/components/ErrorMessage.tsx                |   3 +-
 .../src/components/ErrorTalerOperation.tsx         |   4 +-
 .../src/components/Loading.tsx                     |  96 +++++++++++++----
 .../src/components/LoadingError.tsx                |  30 ------
 .../src/components/MultiActionButton.tsx           |   4 +-
 .../src/components/Part.tsx                        |  10 +-
 .../src/components/PaymentButtons.tsx              |  13 ++-
 .../src/components/PendingTransactions.tsx         |   2 +-
 .../src/components/SelectList.tsx                  |   3 +-
 .../ShowFullContractTermPopup.stories.tsx          |   5 +-
 .../src/components/ShowFullContractTermPopup.tsx   |  16 +--
 .../src/components/TermsOfService/index.ts         |  22 ++--
 .../src/components/TermsOfService/state.ts         |  36 +++----
 .../src/components/TermsOfService/views.tsx        |  34 +-----
 .../src/components/styled/index.tsx                |   2 +-
 .../taler-wallet-webextension/src/context/alert.ts | 118 ++++++++++++++++++++
 .../src/cta/Deposit/index.ts                       |  11 +-
 .../src/cta/Deposit/state.ts                       |  10 +-
 .../src/cta/Deposit/test.ts                        |   8 +-
 .../src/cta/Deposit/views.tsx                      |  18 +---
 .../src/cta/InvoiceCreate/index.ts                 |  14 +--
 .../src/cta/InvoiceCreate/state.ts                 |  37 +++++--
 .../src/cta/InvoiceCreate/views.tsx                |  44 +-------
 .../src/cta/InvoicePay/index.ts                    |  11 +-
 .../src/cta/InvoicePay/state.ts                    |  16 ++-
 .../src/cta/InvoicePay/views.tsx                   |  37 +------
 .../src/cta/Payment/index.ts                       |  11 +-
 .../src/cta/Payment/state.ts                       |  16 ++-
 .../src/cta/Payment/test.ts                        |   6 +-
 .../src/cta/Payment/views.tsx                      |  34 ++----
 .../src/cta/Recovery/index.ts                      |  11 +-
 .../src/cta/Recovery/state.ts                      |  23 ++--
 .../src/cta/Recovery/views.tsx                     |  16 ---
 .../src/cta/Refund/index.ts                        |  16 ++-
 .../src/cta/Refund/state.ts                        |  16 ++-
 .../src/cta/Refund/test.ts                         |   8 +-
 .../src/cta/Refund/views.tsx                       |  29 ++---
 .../taler-wallet-webextension/src/cta/Tip/index.ts |  16 ++-
 .../taler-wallet-webextension/src/cta/Tip/state.ts |  16 ++-
 .../taler-wallet-webextension/src/cta/Tip/test.ts  |   9 +-
 .../src/cta/Tip/views.tsx                          |  28 ++---
 .../src/cta/TransferCreate/index.ts                |  11 +-
 .../src/cta/TransferCreate/state.ts                |  16 ++-
 .../src/cta/TransferCreate/views.tsx               |  32 +-----
 .../src/cta/TransferPickup/index.ts                |  11 +-
 .../src/cta/TransferPickup/state.ts                |  16 ++-
 .../src/cta/TransferPickup/views.tsx               |  35 +-----
 .../src/cta/Withdraw/index.ts                      |  16 ++-
 .../src/cta/Withdraw/state.ts                      |  26 +++--
 .../src/cta/Withdraw/test.ts                       |   8 +-
 .../src/cta/Withdraw/views.tsx                     |  53 +--------
 .../src/hooks/useAsyncAsHook.ts                    |  18 +++-
 .../taler-wallet-webextension/src/hooks/useLang.ts |   1 +
 .../src/hooks/useLocalStorage.ts                   |   5 +-
 .../src/mui/Alert.stories.tsx                      |  33 ++++--
 .../taler-wallet-webextension/src/mui/Alert.tsx    |  10 +-
 .../taler-wallet-webextension/src/mui/Paper.tsx    |   3 -
 .../src/mui/colors/manipulation.ts                 |   2 +-
 .../taler-wallet-webextension/src/platform/api.ts  |   8 +-
 .../src/platform/chrome.ts                         |  60 +++++------
 .../src/platform/firefox.ts                        |   7 +-
 .../src/popup/BalancePage.tsx                      |  24 ++---
 .../src/popup/NoBalanceHelp.tsx                    |   2 +-
 .../taler-wallet-webextension/src/svg/progress.svg |  12 +++
 .../taler-wallet-webextension/src/test-utils.ts    |   5 +-
 .../src/wallet/AddBackupProvider/index.ts          |  15 ++-
 .../src/wallet/AddBackupProvider/views.tsx         |  16 +--
 .../src/wallet/Application.tsx                     |  45 ++++++--
 .../src/wallet/BackupPage.tsx                      |  19 ++--
 .../src/wallet/DepositPage/index.ts                |  10 +-
 .../src/wallet/DepositPage/state.ts                |   7 +-
 .../src/wallet/DepositPage/views.tsx               |  43 ++------
 .../src/wallet/DestinationSelection/index.ts       |  11 +-
 .../src/wallet/DestinationSelection/state.ts       |   8 +-
 .../src/wallet/DestinationSelection/views.tsx      |  29 ++---
 .../src/wallet/EmptyComponentExample/index.ts      |  11 +-
 .../src/wallet/EmptyComponentExample/views.tsx     |  12 ---
 .../src/wallet/ExchangeSelection/index.ts          |   9 +-
 .../src/wallet/ExchangeSelection/state.ts          |  10 +-
 .../src/wallet/ExchangeSelection/views.tsx         |  24 +----
 .../src/wallet/ExchangeSetUrl.tsx                  |   6 +-
 .../src/wallet/History.tsx                         |  15 ++-
 .../src/wallet/ManageAccount/index.ts              |  11 +-
 .../src/wallet/ManageAccount/state.ts              |   7 +-
 .../src/wallet/ManageAccount/views.tsx             |  21 +---
 .../src/wallet/Notifications/index.ts              |  11 +-
 .../src/wallet/Notifications/state.ts              |  11 +-
 .../src/wallet/Notifications/views.tsx             |  12 ---
 .../src/wallet/ProviderAddPage.tsx                 |  10 +-
 .../src/wallet/ProviderDetailPage.tsx              |  45 +++-----
 .../src/wallet/ReserveCreated.tsx                  |   4 +-
 .../src/wallet/Settings.tsx                        |  32 ++----
 .../src/wallet/Transaction.tsx                     | 119 ++++++++++-----------
 .../src/wallet/Welcome.tsx                         |   6 +-
 packages/taler-wallet-webextension/src/wxApi.ts    |  44 ++++++--
 .../taler-wallet-webextension/src/wxBackend.ts     |  31 ++++--
 pnpm-lock.yaml                                     |  21 ++--
 104 files changed, 1076 insertions(+), 1030 deletions(-)

diff --git a/packages/taler-wallet-webextension/package.json 
b/packages/taler-wallet-webextension/package.json
index 8a6c19406..87fb27a72 100644
--- a/packages/taler-wallet-webextension/package.json
+++ b/packages/taler-wallet-webextension/package.json
@@ -69,7 +69,7 @@
     "preact-cli": "^3.3.5",
     "preact-render-to-string": "^5.1.19",
     "rimraf": "^3.0.2",
-    "typescript": "^4.8.4"
+    "typescript": "4.9.4"
   },
   "nyc": {
     "include": [
diff --git 
a/packages/taler-wallet-webextension/src/components/AmountField.stories.tsx 
b/packages/taler-wallet-webextension/src/components/AmountField.stories.tsx
index 9a1d96014..61c4a7661 100644
--- a/packages/taler-wallet-webextension/src/components/AmountField.stories.tsx
+++ b/packages/taler-wallet-webextension/src/components/AmountField.stories.tsx
@@ -49,7 +49,7 @@ function RenderAmount(): VNode {
     <Fragment>
       <AmountField
         required
-        label={<i18n.Translate>Amount</i18n.Translate>}
+        label={i18n.str`Amount`}
         highestDenom={2000000}
         lowestDenom={0.01}
         handler={handler}
diff --git a/packages/taler-wallet-webextension/src/components/AmountField.tsx 
b/packages/taler-wallet-webextension/src/components/AmountField.tsx
index 2e8942f0d..4936e0604 100644
--- a/packages/taler-wallet-webextension/src/components/AmountField.tsx
+++ b/packages/taler-wallet-webextension/src/components/AmountField.tsx
@@ -21,6 +21,7 @@ import {
   amountMaxValue,
   Amounts,
   Result,
+  TranslatedString,
 } from "@gnu-taler/taler-util";
 import { Fragment, h, VNode } from "preact";
 import { useState } from "preact/hooks";
@@ -37,7 +38,7 @@ export function AmountField({
   highestDenom = 1,
   required,
 }: {
-  label: VNode;
+  label: TranslatedString;
   lowestDenom?: number;
   highestDenom?: number;
   required?: boolean;
diff --git 
a/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx 
b/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx
index 6f4980aff..d233547a4 100644
--- 
a/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx
+++ 
b/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx
@@ -19,6 +19,7 @@ import {
   Amounts,
   PaytoUri,
   segwitMinAmount,
+  TranslatedString,
 } from "@gnu-taler/taler-util";
 import { Fragment, h, VNode } from "preact";
 import { useEffect, useRef, useState } from "preact/hooks";
@@ -106,27 +107,18 @@ export function BankDetailsByPaytoType({
   }
 
   const accountPart = !payto.isKnown ? (
-    <Row
-      name={<i18n.Translate>Account</i18n.Translate>}
-      value={payto.targetPath}
-    />
+    <Row name={i18n.str`Account`} value={payto.targetPath} />
   ) : payto.targetType === "x-taler-bank" ? (
     <Fragment>
-      <Row
-        name={<i18n.Translate>Bank host</i18n.Translate>}
-        value={payto.host}
-      />
-      <Row
-        name={<i18n.Translate>Bank account</i18n.Translate>}
-        value={payto.account}
-      />
+      <Row name={i18n.str`Bank host`} value={payto.host} />
+      <Row name={i18n.str`Bank account`} value={payto.account} />
     </Fragment>
   ) : payto.targetType === "iban" ? (
     <Fragment>
       {payto.bic !== undefined ? (
-        <Row name={<i18n.Translate>BIC</i18n.Translate>} value={payto.bic} />
+        <Row name={i18n.str`BIC`} value={payto.bic} />
       ) : undefined}
-      <Row name={<i18n.Translate>IBAN</i18n.Translate>} value={payto.iban} />
+      <Row name={i18n.str`IBAN`} value={payto.iban} />
     </Fragment>
   ) : undefined;
 
@@ -146,19 +138,12 @@ export function BankDetailsByPaytoType({
       <table>
         {accountPart}
         <Row
-          name={<i18n.Translate>Amount</i18n.Translate>}
+          name={i18n.str`Amount`}
           value={<Amount value={amount} hideCurrency />}
         />
-        <Row
-          name={<i18n.Translate>Subject</i18n.Translate>}
-          value={subject}
-          literal
-        />
+        <Row name={i18n.str`Subject`} value={subject} literal />
         {receiver ? (
-          <Row
-            name={<i18n.Translate>Receiver name</i18n.Translate>}
-            value={receiver}
-          />
+          <Row name={i18n.str`Receiver name`} value={receiver} />
         ) : undefined}
       </table>
     </div>
@@ -200,7 +185,7 @@ function Row({
   value,
   literal,
 }: {
-  name: VNode;
+  name: TranslatedString;
   value: string | VNode;
   literal?: boolean;
 }): VNode {
diff --git a/packages/taler-wallet-webextension/src/components/Banner.tsx 
b/packages/taler-wallet-webextension/src/components/Banner.tsx
index a91fd384f..40a4847b8 100644
--- a/packages/taler-wallet-webextension/src/components/Banner.tsx
+++ b/packages/taler-wallet-webextension/src/components/Banner.tsx
@@ -13,6 +13,7 @@
  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 { TranslatedString } from "@gnu-taler/taler-util";
 import { ComponentChildren, Fragment, h, JSX, VNode } from "preact";
 import { Button } from "../mui/Button.js";
 import { Divider } from "../mui/Divider.js";
@@ -20,7 +21,7 @@ import { Grid } from "../mui/Grid.js";
 import { Paper } from "../mui/Paper.js";
 
 interface Props extends JSX.HTMLAttributes<HTMLDivElement> {
-  titleHead?: VNode;
+  titleHead?: VNode | TranslatedString;
   children: ComponentChildren;
   // elements: {
   //   icon?: VNode;
diff --git a/packages/taler-wallet-webextension/src/components/Checkbox.tsx 
b/packages/taler-wallet-webextension/src/components/Checkbox.tsx
index b6fa8b663..70dfab597 100644
--- a/packages/taler-wallet-webextension/src/components/Checkbox.tsx
+++ b/packages/taler-wallet-webextension/src/components/Checkbox.tsx
@@ -14,14 +14,15 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
+import { TranslatedString } from "@gnu-taler/taler-util";
 import { h, VNode } from "preact";
 
 interface Props {
   enabled?: boolean;
   onToggle?: () => Promise<void>;
-  label: VNode;
+  label: TranslatedString;
   name: string;
-  description?: VNode;
+  description?: VNode | TranslatedString;
 }
 export function Checkbox({
   name,
diff --git 
a/packages/taler-wallet-webextension/src/components/CurrentAlerts.tsx 
b/packages/taler-wallet-webextension/src/components/CurrentAlerts.tsx
new file mode 100644
index 000000000..a56c82dee
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/components/CurrentAlerts.tsx
@@ -0,0 +1,108 @@
+/*
+ This file is part of GNU Taler
+ (C) 2022 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 { ComponentChildren, Fragment, h, VNode } from "preact";
+import { useState } from "preact/hooks";
+import { useTranslationContext } from "../../../web-util/src/index.browser.js";
+import {
+  ErrorAlert,
+  Alert as AlertNotification,
+  useAlertContext,
+} from "../context/alert.js";
+import { Alert } from "../mui/Alert.js";
+
+/**
+ *
+ * @author sebasjm
+ */
+
+function AlertContext({
+  context,
+  cause,
+}: {
+  cause: unknown;
+  context: undefined | object;
+}): VNode {
+  const [more, setMore] = useState(false);
+  const { i18n } = useTranslationContext();
+  if (!more) {
+    return (
+      <div style={{ display: "flex", justifyContent: "right" }}>
+        <a onClick={() => setMore(true)}>
+          <i18n.Translate>more info</i18n.Translate>
+        </a>
+      </div>
+    );
+  }
+  return (
+    <pre style={{ overflow: "overlay" }}>
+      {JSON.stringify(
+        context === undefined ? { cause } : { context, cause },
+        undefined,
+        2,
+      )}
+    </pre>
+  );
+}
+
+export function ErrorAlertView({
+  error: alert,
+  onClose,
+}: {
+  error: ErrorAlert;
+  onClose?: () => Promise<void>;
+}): VNode {
+  return (
+    <Alert title={alert.message} severity={alert.type} onClose={onClose}>
+      <div style={{ display: "flex", flexDirection: "column" }}>
+        <div>{alert.description}</div>
+        <AlertContext context={alert.context} cause={alert.cause} />
+      </div>
+    </Alert>
+  );
+}
+
+export function AlertView({
+  alert,
+  onClose,
+}: {
+  alert: AlertNotification;
+  onClose?: () => Promise<void>;
+}): VNode {
+  return (
+    <Alert title={alert.message} severity={alert.type} onClose={onClose}>
+      <div style={{ display: "flex", flexDirection: "column" }}>
+        <div>{alert.description}</div>
+      </div>
+    </Alert>
+  );
+}
+
+export function CurrentAlerts(): VNode {
+  const { alerts, removeAlert } = useAlertContext();
+  if (alerts.length === 0) return <Fragment />;
+  return (
+    <Wrapper>
+      {alerts.map((n, i) => (
+        <AlertView key={i} alert={n} onClose={async () => removeAlert(n)} />
+      ))}
+    </Wrapper>
+  );
+}
+
+function Wrapper({ children }: { children: ComponentChildren }): VNode {
+  return <div style={{ margin: "2em" }}>{children}</div>;
+}
diff --git a/packages/taler-wallet-webextension/src/components/ErrorMessage.tsx 
b/packages/taler-wallet-webextension/src/components/ErrorMessage.tsx
index ce8dc0ad1..11f526865 100644
--- a/packages/taler-wallet-webextension/src/components/ErrorMessage.tsx
+++ b/packages/taler-wallet-webextension/src/components/ErrorMessage.tsx
@@ -13,6 +13,7 @@
  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 { TranslatedString } from "@gnu-taler/taler-util";
 import { h, VNode } from "preact";
 import { useState } from "preact/hooks";
 import arrowDown from "../svg/chevron-down.svg";
@@ -22,7 +23,7 @@ export function ErrorMessage({
   title,
   description,
 }: {
-  title: VNode;
+  title: TranslatedString;
   description?: string | VNode;
 }): VNode | null {
   const [showErrorDetail, setShowErrorDetail] = useState(false);
diff --git 
a/packages/taler-wallet-webextension/src/components/ErrorTalerOperation.tsx 
b/packages/taler-wallet-webextension/src/components/ErrorTalerOperation.tsx
index a7223d2db..f8203f38a 100644
--- a/packages/taler-wallet-webextension/src/components/ErrorTalerOperation.tsx
+++ b/packages/taler-wallet-webextension/src/components/ErrorTalerOperation.tsx
@@ -13,7 +13,7 @@
  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 { TalerErrorDetail } from "@gnu-taler/taler-util";
+import { TalerErrorDetail, TranslatedString } from "@gnu-taler/taler-util";
 import { Fragment, h, VNode } from "preact";
 import { useState } from "preact/hooks";
 import arrowDown from "../svg/chevron-down.svg";
@@ -24,7 +24,7 @@ export function ErrorTalerOperation({
   title,
   error,
 }: {
-  title?: VNode;
+  title?: TranslatedString;
   error?: TalerErrorDetail;
 }): VNode | null {
   const { devMode } = useDevContext();
diff --git a/packages/taler-wallet-webextension/src/components/Loading.tsx 
b/packages/taler-wallet-webextension/src/components/Loading.tsx
index f2195b646..3a6daaaa6 100644
--- a/packages/taler-wallet-webextension/src/components/Loading.tsx
+++ b/packages/taler-wallet-webextension/src/components/Loading.tsx
@@ -13,30 +13,88 @@
  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 { css } from "@linaria/core";
 import { Fragment, h, VNode } from "preact";
 import { useEffect, useState } from "preact/hooks";
 import { useTranslationContext } from "../context/translation.js";
+import ProgressIcon from "../svg/progress.svg";
 import { CenteredText } from "./styled/index.js";
 
+const fadeIn = css`
+  & {
+    animation: fadein 3s;
+  }
+  @keyframes fadein {
+    from {
+      opacity: 0;
+    }
+    to {
+      opacity: 1;
+    }
+  }
+`;
+
 export function Loading(): VNode {
   const { i18n } = useTranslationContext();
-  const [tooLong, setTooLong] = useState(false);
-  useEffect(() => {
-    const id = setTimeout(() => {
-      setTooLong(true);
-    }, 500);
-    return () => {
-      clearTimeout(id);
-    };
-  });
-  if (tooLong) {
-    return (
-      <section style={{ margin: "auto" }}>
-        <CenteredText>
-          <i18n.Translate>Loading</i18n.Translate>...
-        </CenteredText>
-      </section>
-    );
-  }
-  return <Fragment />;
+  return (
+    <section style={{ margin: "auto" }}>
+      <CenteredText class={fadeIn}>
+        <i18n.Translate>Loading</i18n.Translate>...
+      </CenteredText>
+      {/* <div class={ripple} style={{ "--size": "250px" }}>
+        <div></div>
+        <div></div>
+      </div> */}
+      <div class={fadeIn} dangerouslySetInnerHTML={{ __html: ProgressIcon }} />
+    </section>
+  );
 }
+
+const ripple = css`
+  & {
+    display: inline-block;
+    position: relative;
+    width: var(--size);
+    height: var(--size);
+  }
+  & div {
+    position: absolute;
+    border: 4px solid black;
+    opacity: 1;
+    border-radius: 50%;
+    animation: lds-ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite;
+  }
+  & div:nth-child(2) {
+    animation-delay: -0.3s;
+  }
+  @keyframes lds-ripple {
+    0% {
+      top: calc(var(--size) / 2);
+      left: calc(var(--size) / 2);
+      width: 0;
+      height: 0;
+      opacity: 0;
+    }
+    14.9% {
+      top: calc(var(--size) / 2);
+      left: calc(var(--size) / 2);
+      width: 0;
+      height: 0;
+      opacity: 0;
+    }
+    15% {
+      top: calc(var(--size) / 2);
+      left: calc(var(--size) / 2);
+      width: 0;
+      height: 0;
+      opacity: 1;
+    }
+    100% {
+      top: 0px;
+      left: 0px;
+      width: var(--size);
+      height: var(--size);
+      opacity: 0;
+    }
+  }
+`;
diff --git a/packages/taler-wallet-webextension/src/components/LoadingError.tsx 
b/packages/taler-wallet-webextension/src/components/LoadingError.tsx
deleted file mode 100644
index 2cd8bee3b..000000000
--- a/packages/taler-wallet-webextension/src/components/LoadingError.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022 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 { h, VNode } from "preact";
-import { HookError } from "../hooks/useAsyncAsHook.js";
-import { ErrorMessage } from "./ErrorMessage.js";
-import { ErrorTalerOperation } from "./ErrorTalerOperation.js";
-
-export interface Props {
-  title: VNode;
-  error: HookError;
-}
-export function LoadingError({ title, error }: Props): VNode {
-  if (error.operational) {
-    return <ErrorTalerOperation title={title} error={error.details} />;
-  }
-  return <ErrorMessage title={title} description={error.message} />;
-}
diff --git 
a/packages/taler-wallet-webextension/src/components/MultiActionButton.tsx 
b/packages/taler-wallet-webextension/src/components/MultiActionButton.tsx
index 673ff3dc2..d6a730a4f 100644
--- a/packages/taler-wallet-webextension/src/components/MultiActionButton.tsx
+++ b/packages/taler-wallet-webextension/src/components/MultiActionButton.tsx
@@ -13,7 +13,7 @@
  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 { getUnpackedSettings } from "http2";
+import { TranslatedString } from "@gnu-taler/taler-util";
 import { h, VNode } from "preact";
 import { useState } from "preact/hooks";
 import { Button } from "../mui/Button.js";
@@ -21,7 +21,7 @@ import arrowDown from "../svg/chevron-down.svg";
 import { ParagraphClickable } from "./styled/index.js";
 
 export interface Props {
-  label: (s: string) => VNode;
+  label: (s: string) => TranslatedString;
   actions: string[];
   onClick: (s: string) => Promise<void>;
 }
diff --git a/packages/taler-wallet-webextension/src/components/Part.tsx 
b/packages/taler-wallet-webextension/src/components/Part.tsx
index a488ca4dc..1449bcac6 100644
--- a/packages/taler-wallet-webextension/src/components/Part.tsx
+++ b/packages/taler-wallet-webextension/src/components/Part.tsx
@@ -14,7 +14,11 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { PaytoUri, stringifyPaytoUri } from "@gnu-taler/taler-util";
+import {
+  PaytoUri,
+  stringifyPaytoUri,
+  TranslatedString,
+} from "@gnu-taler/taler-util";
 import { styled } from "@linaria/react";
 import { Fragment, h, VNode } from "preact";
 import { useState } from "preact/hooks";
@@ -27,8 +31,8 @@ import {
 
 export type Kind = "positive" | "negative" | "neutral";
 interface Props {
-  title: VNode | string;
-  text: VNode | string;
+  title: VNode | TranslatedString;
+  text: VNode | TranslatedString;
   kind?: Kind;
   big?: boolean;
   showSign?: boolean;
diff --git 
a/packages/taler-wallet-webextension/src/components/PaymentButtons.tsx 
b/packages/taler-wallet-webextension/src/components/PaymentButtons.tsx
index def1e16eb..30c2ef833 100644
--- a/packages/taler-wallet-webextension/src/components/PaymentButtons.tsx
+++ b/packages/taler-wallet-webextension/src/components/PaymentButtons.tsx
@@ -19,6 +19,7 @@ import {
   Amounts,
   PreparePayResult,
   PreparePayResultType,
+  TranslatedString,
 } from "@gnu-taler/taler-util";
 import { Fragment, h, VNode } from "preact";
 import { useState } from "preact/hooks";
@@ -109,8 +110,10 @@ export function PaymentButtons({
         <section>
           {payStatus.paid && payStatus.contractTerms.fulfillment_message && (
             <Part
-              title={<i18n.Translate>Merchant message</i18n.Translate>}
-              text={payStatus.contractTerms.fulfillment_message}
+              title={i18n.str`Merchant message`}
+              text={
+                payStatus.contractTerms.fulfillment_message as TranslatedString
+              }
               kind="neutral"
             />
           )}
@@ -131,11 +134,7 @@ function PayWithMobile({ uri }: { uri: string }): VNode {
   return (
     <section>
       <LinkSuccess upperCased onClick={() => setShowQR((qr) => !qr)}>
-        {!showQR ? (
-          <i18n.Translate>Pay with a mobile phone</i18n.Translate>
-        ) : (
-          <i18n.Translate>Hide QR</i18n.Translate>
-        )}
+        {!showQR ? i18n.str`Pay with a mobile phone` : i18n.str`Hide QR`}
       </LinkSuccess>
       {showQR && (
         <div>
diff --git 
a/packages/taler-wallet-webextension/src/components/PendingTransactions.tsx 
b/packages/taler-wallet-webextension/src/components/PendingTransactions.tsx
index e41ff2836..2bba86dba 100644
--- a/packages/taler-wallet-webextension/src/components/PendingTransactions.tsx
+++ b/packages/taler-wallet-webextension/src/components/PendingTransactions.tsx
@@ -87,7 +87,7 @@ export function PendingTransactionsView({
       }}
     >
       <Banner
-        titleHead={<i18n.Translate>PENDING OPERATIONS</i18n.Translate>}
+        titleHead={i18n.str`PENDING OPERATIONS`}
         style={{
           backgroundColor: "lightcyan",
           maxHeight: 150,
diff --git a/packages/taler-wallet-webextension/src/components/SelectList.tsx 
b/packages/taler-wallet-webextension/src/components/SelectList.tsx
index 3ceac752e..809698711 100644
--- a/packages/taler-wallet-webextension/src/components/SelectList.tsx
+++ b/packages/taler-wallet-webextension/src/components/SelectList.tsx
@@ -14,6 +14,7 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
+import { TranslatedString } from "@gnu-taler/taler-util";
 import { Fragment, h, VNode } from "preact";
 import { useTranslationContext } from "../context/translation.js";
 import { NiceSelect } from "./styled/index.js";
@@ -21,7 +22,7 @@ import { NiceSelect } from "./styled/index.js";
 interface Props {
   value?: string;
   onChange?: (s: string) => void;
-  label: VNode;
+  label: VNode | TranslatedString;
   list: {
     [label: string]: string;
   };
diff --git 
a/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.stories.tsx
 
b/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.stories.tsx
index 841583113..8c94e6e60 100644
--- 
a/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.stories.tsx
+++ 
b/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.stories.tsx
@@ -94,7 +94,10 @@ export const Error = createExample(ErrorView, {
   error: {
     hasError: true,
     message: "message",
-    operational: false,
+    // details: {
+    //   co
+    // },
+    type: "error",
     // details: {
     //   code: 123,
     // },
diff --git 
a/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.tsx
 
b/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.tsx
index 47c10347c..9871611f2 100644
--- 
a/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.tsx
+++ 
b/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.tsx
@@ -22,15 +22,16 @@ import { styled } from "@linaria/react";
 import { Fragment, h, VNode } from "preact";
 import { useState } from "preact/hooks";
 import { Loading } from "../components/Loading.js";
-import { LoadingError } from "../components/LoadingError.js";
 import { Modal } from "../components/Modal.js";
 import { Time } from "../components/Time.js";
+import { alertFromError } from "../context/alert.js";
 import { useBackendContext } from "../context/backend.js";
 import { useTranslationContext } from "../context/translation.js";
 import { HookError, useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
 import { ButtonHandler } from "../mui/handlers.js";
 import { compose, StateViewMap } from "../utils/index.js";
 import { Amount } from "./Amount.js";
+import { AlertView } from "./CurrentAlerts.js";
 import { Link } from "./styled/index.js";
 
 const ContractTermsTable = styled.table`
@@ -160,13 +161,12 @@ export function ErrorView({
   const { i18n } = useTranslationContext();
   return (
     <Modal title="Full detail" onClose={hideHandler}>
-      <LoadingError
-        title={
-          <i18n.Translate>
-            Could not load purchase proposal details
-          </i18n.Translate>
-        }
-        error={error}
+      <AlertView
+        alert={alertFromError(
+          i18n.str`Could not load purchase proposal details`,
+          error,
+          { proposalId },
+        )}
       />
     </Modal>
   );
diff --git 
a/packages/taler-wallet-webextension/src/components/TermsOfService/index.ts 
b/packages/taler-wallet-webextension/src/components/TermsOfService/index.ts
index d7716f208..a8c1558d8 100644
--- a/packages/taler-wallet-webextension/src/components/TermsOfService/index.ts
+++ b/packages/taler-wallet-webextension/src/components/TermsOfService/index.ts
@@ -15,14 +15,13 @@
  */
 
 import { Loading } from "../../components/Loading.js";
-import { HookError } from "../../hooks/useAsyncAsHook.js";
+import { ErrorAlert } from "../../context/alert.js";
 import { ToggleHandler } from "../../mui/handlers.js";
 import { compose, StateViewMap } from "../../utils/index.js";
+import { ErrorAlertView } from "../CurrentAlerts.js";
 import { useComponentState } from "./state.js";
 import { TermsState } from "./utils.js";
 import {
-  ErrorAcceptingView,
-  LoadingUriView,
   ShowButtonsAcceptedTosView,
   ShowButtonsNonAcceptedTosView,
   ShowTosContentView,
@@ -35,8 +34,7 @@ export interface Props {
 
 export type State =
   | State.Loading
-  | State.LoadingUriError
-  | State.ErrorAccepting
+  | State.Error
   | State.ShowButtonsAccepted
   | State.ShowButtonsNotAccepted
   | State.ShowContent;
@@ -47,14 +45,9 @@ export namespace State {
     error: undefined;
   }
 
-  export interface LoadingUriError {
-    status: "loading-error";
-    error: HookError;
-  }
-
-  export interface ErrorAccepting {
-    status: "error-accepting";
-    error: HookError;
+  export interface Error {
+    status: "error";
+    error: ErrorAlert;
   }
 
   export interface BaseInfo {
@@ -79,11 +72,10 @@ export namespace State {
 
 const viewMapping: StateViewMap<State> = {
   loading: Loading,
-  "loading-error": LoadingUriView,
+  error: ErrorAlertView,
   "show-content": ShowTosContentView,
   "show-buttons-accepted": ShowButtonsAcceptedTosView,
   "show-buttons-not-accepted": ShowButtonsNonAcceptedTosView,
-  "error-accepting": ErrorAcceptingView,
 };
 
 export const TermsOfService = compose(
diff --git 
a/packages/taler-wallet-webextension/src/components/TermsOfService/state.ts 
b/packages/taler-wallet-webextension/src/components/TermsOfService/state.ts
index 3b75965d3..c25c0ed13 100644
--- a/packages/taler-wallet-webextension/src/components/TermsOfService/state.ts
+++ b/packages/taler-wallet-webextension/src/components/TermsOfService/state.ts
@@ -16,7 +16,9 @@
 
 import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
 import { useState } from "preact/hooks";
+import { alertFromError, useAlertContext } from "../../context/alert.js";
 import { useBackendContext } from "../../context/backend.js";
+import { useTranslationContext } from "../../context/translation.js";
 import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
 import { Props, State } from "./index.js";
 import { buildTermsOfServiceState } from "./utils.js";
@@ -25,9 +27,8 @@ export function useComponentState({ exchangeUrl, onChange }: 
Props): State {
   const api = useBackendContext();
   const readOnly = !onChange;
   const [showContent, setShowContent] = useState<boolean>(readOnly);
-  const [errorAccepting, setErrorAccepting] = useState<Error | undefined>(
-    undefined,
-  );
+  const { i18n } = useTranslationContext();
+  const { pushAlert } = useAlertContext();
 
   /**
    * For the exchange selected, bring the status of the terms of service
@@ -54,22 +55,13 @@ export function useComponentState({ exchangeUrl, onChange 
}: Props): State {
   }
   if (terms.hasError) {
     return {
-      status: "loading-error",
-      error: terms,
+      status: "error",
+      error: alertFromError(
+        i18n.str`Could not load the status of the term of service`,
+        terms,
+      ),
     };
   }
-
-  if (errorAccepting) {
-    return {
-      status: "error-accepting",
-      error: {
-        hasError: true,
-        operational: false,
-        message: errorAccepting.message,
-      },
-    };
-  }
-
   const { state } = terms.response;
 
   async function onUpdate(accepted: boolean): Promise<void> {
@@ -77,13 +69,13 @@ export function useComponentState({ exchangeUrl, onChange 
}: Props): State {
 
     try {
       if (accepted) {
-        api.wallet.call(WalletApiOperation.SetExchangeTosAccepted, {
+        await api.wallet.call(WalletApiOperation.SetExchangeTosAccepted, {
           exchangeBaseUrl: exchangeUrl,
           etag: state.version,
         });
       } else {
         // mark as not accepted
-        api.wallet.call(WalletApiOperation.SetExchangeTosAccepted, {
+        await api.wallet.call(WalletApiOperation.SetExchangeTosAccepted, {
           exchangeBaseUrl: exchangeUrl,
           etag: undefined,
         });
@@ -91,11 +83,7 @@ export function useComponentState({ exchangeUrl, onChange }: 
Props): State {
       // setAccepted(accepted);
       if (!readOnly) onChange(accepted); //external update
     } catch (e) {
-      if (e instanceof Error) {
-        //FIXME: uncomment this and display error
-        // setErrorAccepting(e.message);
-        setErrorAccepting(e);
-      }
+      pushAlert(alertFromError(i18n.str`Could not accept terms of service`, 
e));
     }
   }
 
diff --git 
a/packages/taler-wallet-webextension/src/components/TermsOfService/views.tsx 
b/packages/taler-wallet-webextension/src/components/TermsOfService/views.tsx
index a7e03fd01..0b5a71b3e 100644
--- a/packages/taler-wallet-webextension/src/components/TermsOfService/views.tsx
+++ b/packages/taler-wallet-webextension/src/components/TermsOfService/views.tsx
@@ -14,49 +14,23 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
+import { ExchangeTosStatus } from "@gnu-taler/taler-util";
 import { Fragment, h, VNode } from "preact";
-import { LoadingError } from "../../components/LoadingError.js";
-import { useTranslationContext } from "../../context/translation.js";
-import { TermsDocument, TermsState } from "./utils.js";
-import { State } from "./index.js";
 import { CheckboxOutlined } from "../../components/CheckboxOutlined.js";
+import { ExchangeXmlTos } from "../../components/ExchangeToS.js";
 import {
   LinkSuccess,
   TermsOfService,
   WarningBox,
   WarningText,
 } from "../../components/styled/index.js";
-import { ExchangeXmlTos } from "../../components/ExchangeToS.js";
-import { ToggleHandler } from "../../mui/handlers.js";
+import { useTranslationContext } from "../../context/translation.js";
 import { Button } from "../../mui/Button.js";
-import { ExchangeTosStatus } from "@gnu-taler/taler-util";
-
-export function LoadingUriView({ error }: State.LoadingUriError): VNode {
-  const { i18n } = useTranslationContext();
-
-  return (
-    <LoadingError
-      title={<i18n.Translate>Could not load</i18n.Translate>}
-      error={error}
-    />
-  );
-}
-
-export function ErrorAcceptingView({ error }: State.ErrorAccepting): VNode {
-  const { i18n } = useTranslationContext();
-
-  return (
-    <LoadingError
-      title={<i18n.Translate>Could not load</i18n.Translate>}
-      error={error}
-    />
-  );
-}
+import { State } from "./index.js";
 
 export function ShowButtonsAcceptedTosView({
   termsAccepted,
   showingTermsOfService,
-  terms,
 }: State.ShowButtonsAccepted): VNode {
   const { i18n } = useTranslationContext();
   const ableToReviewTermsOfService =
diff --git a/packages/taler-wallet-webextension/src/components/styled/index.tsx 
b/packages/taler-wallet-webextension/src/components/styled/index.tsx
index 8e98f75eb..e36502333 100644
--- a/packages/taler-wallet-webextension/src/components/styled/index.tsx
+++ b/packages/taler-wallet-webextension/src/components/styled/index.tsx
@@ -535,7 +535,7 @@ export const LinkDestructive = styled(Link)`
 `;
 
 export const LinkPrimary = styled(Link)`
-  color: rgb(66, 184, 221);
+  color: black;
 `;
 
 export const ButtonPrimary = styled(ButtonVariant)<{ small?: boolean }>`
diff --git a/packages/taler-wallet-webextension/src/context/alert.ts 
b/packages/taler-wallet-webextension/src/context/alert.ts
new file mode 100644
index 000000000..cc98ec1e0
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/context/alert.ts
@@ -0,0 +1,118 @@
+/*
+ This file is part of GNU Taler
+ (C) 2022 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 { TranslatedString } from "@gnu-taler/taler-util";
+import { ComponentChildren, createContext, h, VNode } from "preact";
+import { useContext, useState } from "preact/hooks";
+
+export type AlertType = "info" | "warning" | "error" | "success";
+
+export interface Alert {
+  message: TranslatedString;
+  description: TranslatedString | VNode;
+  type: AlertType;
+}
+
+export interface ErrorAlert extends Alert {
+  type: "error";
+  context: object;
+  cause: any;
+}
+
+type Type = {
+  alerts: Alert[];
+  pushAlert: (n: Alert) => void;
+  removeAlert: (n: Alert) => void;
+};
+
+const initial: Type = {
+  alerts: [],
+  pushAlert: () => {
+    null;
+  },
+  removeAlert: () => {
+    null;
+  },
+};
+
+const Context = createContext<Type>(initial);
+
+type AlertWithDate = Alert & { since: Date };
+
+type Props = Partial<Type> & {
+  children: ComponentChildren;
+};
+
+export const AlertProvider = ({ children }: Props): VNode => {
+  const timeout = 3000;
+
+  const [alerts, setAlerts] = useState<AlertWithDate[]>([]);
+
+  const pushAlert = (n: Alert): void => {
+    const entry = { ...n, since: new Date() };
+    setAlerts((ns) => [...ns, entry]);
+    if (n.type !== "error") {
+      setTimeout(() => {
+        setAlerts((ns) => ns.filter((x) => x.since !== entry.since));
+      }, timeout);
+    }
+  };
+
+  const removeAlert = (alert: Alert): void => {
+    setAlerts((ns: AlertWithDate[]) => ns.filter((n) => n !== alert));
+  };
+
+  return h(Context.Provider, {
+    value: { alerts, pushAlert, removeAlert },
+    children,
+  });
+};
+
+export const useAlertContext = (): Type => useContext(Context);
+
+export function alertFromError(
+  message: TranslatedString,
+  error: unknown,
+  ...context: any[]
+): ErrorAlert {
+  let description = "" as TranslatedString;
+
+  const isObject = typeof error === "object" &&
+    error !== null;
+  const hasMessage =
+    isObject &&
+    "message" in error &&
+    typeof error.message === "string";
+
+  if (hasMessage) {
+    description = error.message as TranslatedString;
+  } else {
+    description = `Unknown error: ${String(error)}` as TranslatedString;
+  }
+
+  return {
+    type: "error",
+    message,
+    description,
+    cause: error,
+    context,
+  };
+}
diff --git a/packages/taler-wallet-webextension/src/cta/Deposit/index.ts 
b/packages/taler-wallet-webextension/src/cta/Deposit/index.ts
index 9ff3ddd1d..6b228188b 100644
--- a/packages/taler-wallet-webextension/src/cta/Deposit/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/Deposit/index.ts
@@ -15,12 +15,13 @@
  */
 
 import { AmountJson, AmountString } from "@gnu-taler/taler-util";
+import { ErrorAlertView } from "../../components/CurrentAlerts.js";
 import { Loading } from "../../components/Loading.js";
-import { HookError } from "../../hooks/useAsyncAsHook.js";
+import { ErrorAlert } from "../../context/alert.js";
 import { ButtonHandler } from "../../mui/handlers.js";
 import { compose, StateViewMap } from "../../utils/index.js";
 import { useComponentState } from "./state.js";
-import { LoadingUriView, ReadyView } from "./views.js";
+import { ReadyView } from "./views.js";
 
 export interface Props {
   talerDepositUri: string | undefined;
@@ -37,8 +38,8 @@ export namespace State {
     error: undefined;
   }
   export interface LoadingUriError {
-    status: "loading-uri";
-    error: HookError;
+    status: "error";
+    error: ErrorAlert;
   }
   export interface Ready {
     status: "ready";
@@ -57,7 +58,7 @@ export namespace State {
 
 const viewMapping: StateViewMap<State> = {
   loading: Loading,
-  "loading-uri": LoadingUriView,
+  error: ErrorAlertView,
   ready: ReadyView,
 };
 
diff --git a/packages/taler-wallet-webextension/src/cta/Deposit/state.ts 
b/packages/taler-wallet-webextension/src/cta/Deposit/state.ts
index dba435611..4cee7cfd0 100644
--- a/packages/taler-wallet-webextension/src/cta/Deposit/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/Deposit/state.ts
@@ -16,7 +16,9 @@
 
 import { Amounts } from "@gnu-taler/taler-util";
 import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
+import { alertFromError } from "../../context/alert.js";
 import { useBackendContext } from "../../context/backend.js";
+import { useTranslationContext } from "../../context/translation.js";
 import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
 import { Props, State } from "./index.js";
 
@@ -38,12 +40,16 @@ export function useComponentState({
     });
     return { deposit, uri: talerDepositUri, amount };
   });
+  const { i18n } = useTranslationContext();
 
   if (!info) return { status: "loading", error: undefined };
   if (info.hasError) {
     return {
-      status: "loading-uri",
-      error: info,
+      status: "error",
+      error: alertFromError(
+        i18n.str`Could not load the status of the term of service`,
+        info,
+      ),
     };
   }
 
diff --git a/packages/taler-wallet-webextension/src/cta/Deposit/test.ts 
b/packages/taler-wallet-webextension/src/cta/Deposit/test.ts
index 6a896fb7f..031dcffaa 100644
--- a/packages/taler-wallet-webextension/src/cta/Deposit/test.ts
+++ b/packages/taler-wallet-webextension/src/cta/Deposit/test.ts
@@ -50,12 +50,12 @@ describe("Deposit CTA states", () => {
           expect(status).equals("loading");
         },
         ({ status, error }) => {
-          expect(status).equals("loading-uri");
+          expect(status).equals("error");
 
           if (!error) expect.fail();
-          if (!error.hasError) expect.fail();
-          if (error.operational) expect.fail();
-          expect(error.message).eq("ERROR_NO-URI-FOR-DEPOSIT");
+          // if (!error.hasError) expect.fail();
+          // if (error.operational) expect.fail();
+          expect(error.cause?.message).eq("ERROR_NO-URI-FOR-DEPOSIT");
         },
       ],
       TestingContext,
diff --git a/packages/taler-wallet-webextension/src/cta/Deposit/views.tsx 
b/packages/taler-wallet-webextension/src/cta/Deposit/views.tsx
index 2ec305de5..7fa43f878 100644
--- a/packages/taler-wallet-webextension/src/cta/Deposit/views.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Deposit/views.tsx
@@ -17,7 +17,6 @@
 import { Amounts } from "@gnu-taler/taler-util";
 import { Fragment, h, VNode } from "preact";
 import { Amount } from "../../components/Amount.js";
-import { LoadingError } from "../../components/LoadingError.js";
 import { LogoHeader } from "../../components/LogoHeader.js";
 import { Part } from "../../components/Part.js";
 import { SubTitle, WalletAction } from "../../components/styled/index.js";
@@ -30,17 +29,6 @@ import { State } from "./index.js";
  * @author sebasjm
  */
 
-export function LoadingUriView({ error }: State.LoadingUriError): VNode {
-  const { i18n } = useTranslationContext();
-
-  return (
-    <LoadingError
-      title={<i18n.Translate>Could not load deposit status</i18n.Translate>}
-      error={error}
-    />
-  );
-}
-
 export function ReadyView(state: State.Ready): VNode {
   const { i18n } = useTranslationContext();
 
@@ -55,7 +43,7 @@ export function ReadyView(state: State.Ready): VNode {
         {Amounts.isNonZero(state.cost) && (
           <Part
             big
-            title={<i18n.Translate>Cost</i18n.Translate>}
+            title={i18n.str`Cost`}
             text={<Amount value={state.cost} />}
             kind="negative"
           />
@@ -63,14 +51,14 @@ export function ReadyView(state: State.Ready): VNode {
         {Amounts.isNonZero(state.fee) && (
           <Part
             big
-            title={<i18n.Translate>Fee</i18n.Translate>}
+            title={i18n.str`Fee`}
             text={<Amount value={state.fee} />}
             kind="negative"
           />
         )}
         <Part
           big
-          title={<i18n.Translate>To be received</i18n.Translate>}
+          title={i18n.str`To be received`}
           text={<Amount value={state.effective} />}
           kind="positive"
         />
diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts 
b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts
index 0569e8e5f..f39ab6794 100644
--- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts
@@ -14,16 +14,17 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { AmountJson, TalerErrorDetail } from "@gnu-taler/taler-util";
+import { AmountJson } from "@gnu-taler/taler-util";
+import { ErrorAlertView } from "../../components/CurrentAlerts.js";
 import { Loading } from "../../components/Loading.js";
-import { HookError } from "../../hooks/useAsyncAsHook.js";
+import { ErrorAlert } from "../../context/alert.js";
 import { State as SelectExchangeState } from 
"../../hooks/useSelectedExchange.js";
 import { ButtonHandler, TextFieldHandler } from "../../mui/handlers.js";
 import { compose, StateViewMap } from "../../utils/index.js";
 import { ExchangeSelectionPage } from 
"../../wallet/ExchangeSelection/index.js";
 import { NoExchangesView } from "../../wallet/ExchangeSelection/views.js";
 import { useComponentState } from "./state.js";
-import { LoadingUriView, ReadyView } from "./views.js";
+import { ReadyView } from "./views.js";
 
 export interface Props {
   amount: string;
@@ -45,8 +46,8 @@ export namespace State {
   }
 
   export interface LoadingUriError {
-    status: "loading-uri";
-    error: HookError;
+    status: "error";
+    error: ErrorAlert;
   }
 
   export interface BaseInfo {
@@ -63,13 +64,12 @@ export namespace State {
     requestAmount: AmountJson;
     exchangeUrl: string;
     error: undefined;
-    operationError?: TalerErrorDetail;
   }
 }
 
 const viewMapping: StateViewMap<State> = {
   loading: Loading,
-  "loading-uri": LoadingUriView,
+  error: ErrorAlertView,
   "no-exchange": NoExchangesView,
   "selecting-exchange": ExchangeSelectionPage,
   ready: ReadyView,
diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts 
b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts
index 998270e53..46b1262b1 100644
--- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts
@@ -23,7 +23,9 @@ import {
 import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
 import { isFuture, parse } from "date-fns";
 import { useState } from "preact/hooks";
+import { alertFromError } from "../../context/alert.js";
 import { useBackendContext } from "../../context/backend.js";
+import { useTranslationContext } from "../../context/translation.js";
 import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
 import { useSelectedExchange } from "../../hooks/useSelectedExchange.js";
 import { RecursiveState } from "../../utils/index.js";
@@ -40,6 +42,7 @@ export function useComponentState({
   const hook = useAsyncAsHook(() =>
     api.wallet.call(WalletApiOperation.ListExchanges, {}),
   );
+  const { i18n } = useTranslationContext();
 
   if (!hook) {
     return {
@@ -49,10 +52,19 @@ export function useComponentState({
   }
   if (hook.hasError) {
     return {
-      status: "loading-uri",
-      error: hook,
+      status: "error",
+      error: alertFromError(
+        i18n.str`Could not load the status of the term of service`,
+        hook,
+      ),
     };
   }
+  // if (hook.hasError) {
+  //   return {
+  //     status: "loading-uri",
+  //     error: hook,
+  //   };
+  // }
 
   const exchangeList = hook.response.exchanges;
 
@@ -60,10 +72,6 @@ export function useComponentState({
     const [subject, setSubject] = useState<string | undefined>();
     const [timestamp, setTimestamp] = useState<string | undefined>();
 
-    const [operationError, setOperationError] = useState<
-      TalerErrorDetail | undefined
-    >(undefined);
-
     const selectedExchange = useSelectedExchange({
       currency: amount.currency,
       defaultExchange: undefined,
@@ -93,11 +101,19 @@ export function useComponentState({
         error: undefined,
       };
     }
+
     if (hook.hasError) {
       return {
-        status: "loading-uri",
-        error: hook,
+        status: "error",
+        error: alertFromError(
+          i18n.str`Could not load the status of the term of service`,
+          hook,
+        ),
       };
+      // return {
+      //   status: "loading-uri",
+      //   error: hook,
+      // };
     }
 
     const { amountEffective, amountRaw } = hook.response;
@@ -160,8 +176,8 @@ export function useComponentState({
           subject === undefined
             ? undefined
             : !subject
-            ? "Can't be empty"
-            : undefined,
+              ? "Can't be empty"
+              : undefined,
         value: subject ?? "",
         onInput: async (e) => setSubject(e),
       },
@@ -183,7 +199,6 @@ export function useComponentState({
       requestAmount,
       toBeReceived,
       error: undefined,
-      operationError,
     };
   };
 }
diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx 
b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx
index 0ef5c697e..10e0e68d5 100644
--- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx
+++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx
@@ -17,41 +17,24 @@
 import { format } from "date-fns";
 import { h, VNode } from "preact";
 import { ErrorTalerOperation } from "../../components/ErrorTalerOperation.js";
-import { LoadingError } from "../../components/LoadingError.js";
 import { LogoHeader } from "../../components/LogoHeader.js";
 import { Part } from "../../components/Part.js";
-import { QR } from "../../components/QR.js";
 import {
-  Link,
   SubTitle,
   SvgIcon,
   WalletAction,
 } from "../../components/styled/index.js";
 import { useTranslationContext } from "../../context/translation.js";
 import { Button } from "../../mui/Button.js";
-import { Grid } from "../../mui/Grid.js";
 import { TextField } from "../../mui/TextField.js";
 import editIcon from "../../svg/edit_24px.svg";
 import { ExchangeDetails, InvoiceDetails } from "../../wallet/Transaction.js";
 import { State } from "./index.js";
 
-export function LoadingUriView({ error }: State.LoadingUriError): VNode {
-  const { i18n } = useTranslationContext();
-
-  return (
-    <LoadingError
-      title={<i18n.Translate>Could not load</i18n.Translate>}
-      error={error}
-    />
-  );
-}
-
 export function ReadyView({
   exchangeUrl,
   subject,
   expiration,
-  cancel,
-  operationError,
   create,
   toBeReceived,
   requestAmount,
@@ -59,7 +42,7 @@ export function ReadyView({
 }: State.Ready): VNode {
   const { i18n } = useTranslationContext();
 
-  async function oneDayExpiration() {
+  async function oneDayExpiration(): Promise<void> {
     if (expiration.onInput) {
       expiration.onInput(
         format(new Date().getTime() + 1000 * 60 * 60 * 24, "dd/MM/yyyy"),
@@ -67,14 +50,14 @@ export function ReadyView({
     }
   }
 
-  async function oneWeekExpiration() {
+  async function oneWeekExpiration(): Promise<void> {
     if (expiration.onInput) {
       expiration.onInput(
         format(new Date().getTime() + 1000 * 60 * 60 * 24 * 7, "dd/MM/yyyy"),
       );
     }
   }
-  async function _20DaysExpiration() {
+  async function _20DaysExpiration(): Promise<void> {
     if (expiration.onInput) {
       expiration.onInput(
         format(new Date().getTime() + 1000 * 60 * 60 * 24 * 20, "dd/MM/yyyy"),
@@ -87,16 +70,6 @@ export function ReadyView({
       <SubTitle>
         <i18n.Translate>Digital invoice</i18n.Translate>
       </SubTitle>
-      {operationError && (
-        <ErrorTalerOperation
-          title={
-            <i18n.Translate>
-              Could not finish the invoice creation
-            </i18n.Translate>
-          }
-          error={operationError}
-        />
-      )}
       <section style={{ textAlign: "left" }}>
         <Part
           title={
@@ -125,9 +98,7 @@ export function ReadyView({
             label="Subject"
             variant="filled"
             error={subject.error}
-            helperText={
-              <i18n.Translate>Short description of the invoice</i18n.Translate>
-            }
+            helperText={i18n.str`Short description of the invoice`}
             required
             fullWidth
             value={subject.value}
@@ -171,7 +142,7 @@ export function ReadyView({
         </p>
 
         <Part
-          title={<i18n.Translate>Details</i18n.Translate>}
+          title={i18n.str`Details`}
           text={
             <InvoiceDetails
               amount={{
@@ -187,11 +158,6 @@ export function ReadyView({
           <i18n.Translate>Create</i18n.Translate>
         </Button>
       </section>
-      <section>
-        <Link upperCased onClick={cancel.onClick}>
-          <i18n.Translate>Cancel</i18n.Translate>
-        </Link>
-      </section>
     </WalletAction>
   );
 }
diff --git a/packages/taler-wallet-webextension/src/cta/InvoicePay/index.ts 
b/packages/taler-wallet-webextension/src/cta/InvoicePay/index.ts
index f3de0885d..82b2c7af5 100644
--- a/packages/taler-wallet-webextension/src/cta/InvoicePay/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/InvoicePay/index.ts
@@ -20,12 +20,13 @@ import {
   PreparePayResult,
   TalerErrorDetail,
 } from "@gnu-taler/taler-util";
+import { ErrorAlertView } from "../../components/CurrentAlerts.js";
 import { Loading } from "../../components/Loading.js";
-import { HookError } from "../../hooks/useAsyncAsHook.js";
+import { ErrorAlert } from "../../context/alert.js";
 import { ButtonHandler } from "../../mui/handlers.js";
 import { compose, StateViewMap } from "../../utils/index.js";
 import { useComponentState } from "./state.js";
-import { LoadingUriView, ReadyView } from "./views.js";
+import { ReadyView } from "./views.js";
 
 export interface Props {
   talerPayPullUri: string;
@@ -48,8 +49,8 @@ export namespace State {
   }
 
   export interface LoadingUriError {
-    status: "loading-uri";
-    error: HookError;
+    status: "error";
+    error: ErrorAlert;
   }
 
   export interface BaseInfo {
@@ -83,7 +84,7 @@ export namespace State {
 
 const viewMapping: StateViewMap<State> = {
   loading: Loading,
-  "loading-uri": LoadingUriView,
+  error: ErrorAlertView,
   "no-balance-for-currency": ReadyView,
   "no-enough-balance": ReadyView,
   ready: ReadyView,
diff --git a/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts 
b/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts
index c0b97c106..9c4a3162e 100644
--- a/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts
@@ -25,7 +25,9 @@ import {
 } from "@gnu-taler/taler-util";
 import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
 import { useEffect, useState } from "preact/hooks";
+import { alertFromError } from "../../context/alert.js";
 import { useBackendContext } from "../../context/backend.js";
+import { useTranslationContext } from "../../context/translation.js";
 import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
 import { Props, State } from "./index.js";
 
@@ -36,6 +38,7 @@ export function useComponentState({
   onSuccess,
 }: Props): State {
   const api = useBackendContext();
+  const { i18n } = useTranslationContext();
   const hook = useAsyncAsHook(async () => {
     const p2p = await api.wallet.call(WalletApiOperation.CheckPeerPullPayment, 
{
       talerUri: talerPayPullUri,
@@ -63,10 +66,19 @@ export function useComponentState({
   }
   if (hook.hasError) {
     return {
-      status: "loading-uri",
-      error: hook,
+      status: "error",
+      error: alertFromError(
+        i18n.str`Could not load the status of the term of service`,
+        hook,
+      ),
     };
   }
+  // if (hook.hasError) {
+  //   return {
+  //     status: "loading-uri",
+  //     error: hook,
+  //   };
+  // }
 
   const { contractTerms, peerPullPaymentIncomingId } = hook.response.p2p;
 
diff --git a/packages/taler-wallet-webextension/src/cta/InvoicePay/views.tsx 
b/packages/taler-wallet-webextension/src/cta/InvoicePay/views.tsx
index a53fa881a..6a9ab3cf7 100644
--- a/packages/taler-wallet-webextension/src/cta/InvoicePay/views.tsx
+++ b/packages/taler-wallet-webextension/src/cta/InvoicePay/views.tsx
@@ -17,26 +17,14 @@
 import { Fragment, h, VNode } from "preact";
 import { Amount } from "../../components/Amount.js";
 import { ErrorTalerOperation } from "../../components/ErrorTalerOperation.js";
-import { LoadingError } from "../../components/LoadingError.js";
 import { LogoHeader } from "../../components/LogoHeader.js";
 import { Part } from "../../components/Part.js";
+import { PaymentButtons } from "../../components/PaymentButtons.js";
 import { Link, SubTitle, WalletAction } from 
"../../components/styled/index.js";
 import { Time } from "../../components/Time.js";
 import { useTranslationContext } from "../../context/translation.js";
-import { PaymentButtons } from "../../components/PaymentButtons";
 import { State } from "./index.js";
 
-export function LoadingUriView({ error }: State.LoadingUriError): VNode {
-  const { i18n } = useTranslationContext();
-
-  return (
-    <LoadingError
-      title={<i18n.Translate>Could not load</i18n.Translate>}
-      error={error}
-    />
-  );
-}
-
 export function ReadyView(
   state: State.Ready | State.NoBalanceForCurrency | State.NoEnoughBalance,
 ): VNode {
@@ -60,25 +48,15 @@ export function ReadyView(
       </SubTitle>
       {operationError && (
         <ErrorTalerOperation
-          title={
-            <i18n.Translate>
-              Could not finish the payment operation
-            </i18n.Translate>
-          }
+          title={i18n.str`Could not finish the payment operation`}
           error={operationError}
         />
       )}
       <section style={{ textAlign: "left" }}>
+        <Part title={i18n.str`Subject`} text={<div>{summary}</div>} />
+        <Part title={i18n.str`Amount`} text={<Amount value={amount} />} />
         <Part
-          title={<i18n.Translate>Subject</i18n.Translate>}
-          text={<div>{summary}</div>}
-        />
-        <Part
-          title={<i18n.Translate>Amount</i18n.Translate>}
-          text={<Amount value={amount} />}
-        />
-        <Part
-          title={<i18n.Translate>Valid until</i18n.Translate>}
+          title={i18n.str`Valid until`}
           text={<Time timestamp={expiration} format="dd MMMM yyyy, HH:mm" />}
           kind="neutral"
         />
@@ -91,11 +69,6 @@ export function ReadyView(
         payHandler={status === "ready" ? state.accept : undefined}
         goToWalletManualWithdraw={state.goToWalletManualWithdraw}
       />
-      <section>
-        <Link upperCased onClick={cancel.onClick}>
-          <i18n.Translate>Cancel</i18n.Translate>
-        </Link>
-      </section>
     </WalletAction>
   );
 }
diff --git a/packages/taler-wallet-webextension/src/cta/Payment/index.ts 
b/packages/taler-wallet-webextension/src/cta/Payment/index.ts
index 2dc6b6741..e844c1706 100644
--- a/packages/taler-wallet-webextension/src/cta/Payment/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/Payment/index.ts
@@ -21,12 +21,13 @@ import {
   PreparePayResultInsufficientBalance,
   PreparePayResultPaymentPossible,
 } from "@gnu-taler/taler-util";
+import { ErrorAlertView } from "../../components/CurrentAlerts.js";
 import { Loading } from "../../components/Loading.js";
-import { HookError } from "../../hooks/useAsyncAsHook.js";
+import { ErrorAlert } from "../../context/alert.js";
 import { ButtonHandler } from "../../mui/handlers.js";
 import { compose, StateViewMap } from "../../utils/index.js";
 import { useComponentState } from "./state.js";
-import { BaseView, LoadingUriView } from "./views.js";
+import { BaseView } from "./views.js";
 
 export interface Props {
   talerPayUri?: string;
@@ -49,8 +50,8 @@ export namespace State {
     error: undefined;
   }
   export interface LoadingUriError {
-    status: "loading-uri";
-    error: HookError;
+    status: "error";
+    error: ErrorAlert;
   }
 
   interface BaseInfo {
@@ -86,7 +87,7 @@ export namespace State {
 
 const viewMapping: StateViewMap<State> = {
   loading: Loading,
-  "loading-uri": LoadingUriView,
+  error: ErrorAlertView,
   "no-balance-for-currency": BaseView,
   "no-enough-balance": BaseView,
   confirmed: BaseView,
diff --git a/packages/taler-wallet-webextension/src/cta/Payment/state.ts 
b/packages/taler-wallet-webextension/src/cta/Payment/state.ts
index d4adf4bcb..6d7ef6b20 100644
--- a/packages/taler-wallet-webextension/src/cta/Payment/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/Payment/state.ts
@@ -23,7 +23,9 @@ import {
 } from "@gnu-taler/taler-util";
 import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
 import { useEffect, useState } from "preact/hooks";
+import { alertFromError } from "../../context/alert.js";
 import { useBackendContext } from "../../context/backend.js";
+import { useTranslationContext } from "../../context/translation.js";
 import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
 import { ButtonHandler } from "../../mui/handlers.js";
 import { Props, State } from "./index.js";
@@ -36,6 +38,7 @@ export function useComponentState({
 }: Props): State {
   const [payErrMsg, setPayErrMsg] = useState<TalerError | 
undefined>(undefined);
   const api = useBackendContext();
+  const { i18n } = useTranslationContext();
 
   const hook = useAsyncAsHook(async () => {
     if (!talerPayUri) throw Error("ERROR_NO-URI-FOR-PAYMENT");
@@ -80,10 +83,19 @@ export function useComponentState({
   if (!hook) return { status: "loading", error: undefined };
   if (hook.hasError) {
     return {
-      status: "loading-uri",
-      error: hook,
+      status: "error",
+      error: alertFromError(
+        i18n.str`Could not load the status of the term of service`,
+        hook,
+      ),
     };
   }
+  // if (hook.hasError) {
+  //   return {
+  //     status: "loading-uri",
+  //     error: hook,
+  //   };
+  // }
   const { payStatus } = hook.response;
 
   const amount = Amounts.parseOrThrow(payStatus.amountRaw);
diff --git a/packages/taler-wallet-webextension/src/cta/Payment/test.ts 
b/packages/taler-wallet-webextension/src/cta/Payment/test.ts
index 077930972..123e95a87 100644
--- a/packages/taler-wallet-webextension/src/cta/Payment/test.ts
+++ b/packages/taler-wallet-webextension/src/cta/Payment/test.ts
@@ -54,10 +54,10 @@ describe("Payment CTA states", () => {
           expect(error).undefined;
         },
         ({ status, error }) => {
-          expect(status).equals("loading-uri");
+          expect(status).equals("error");
           if (error === undefined) expect.fail();
-          expect(error.hasError).true;
-          expect(error.operational).false;
+          // expect(error.hasError).true;
+          // expect(error.operational).false;
         },
       ],
       TestingContext,
diff --git a/packages/taler-wallet-webextension/src/cta/Payment/views.tsx 
b/packages/taler-wallet-webextension/src/cta/Payment/views.tsx
index efc8bcfc4..244ac5886 100644
--- a/packages/taler-wallet-webextension/src/cta/Payment/views.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Payment/views.tsx
@@ -19,28 +19,17 @@ import {
   Amounts,
   MerchantContractTerms as ContractTerms,
   PreparePayResultType,
+  TranslatedString,
 } from "@gnu-taler/taler-util";
 import { Fragment, h, VNode } from "preact";
-import { LoadingError } from "../../components/LoadingError.js";
 import { Part } from "../../components/Part.js";
 import { PaymentButtons } from "../../components/PaymentButtons.js";
-import { Link, SuccessBox, WarningBox } from 
"../../components/styled/index.js";
+import { SuccessBox, WarningBox } from "../../components/styled/index.js";
 import { Time } from "../../components/Time.js";
 import { useTranslationContext } from "../../context/translation.js";
 import { MerchantDetails, PurchaseDetails } from "../../wallet/Transaction.js";
 import { State } from "./index.js";
 
-export function LoadingUriView({ error }: State.LoadingUriError): VNode {
-  const { i18n } = useTranslationContext();
-
-  return (
-    <LoadingError
-      title={<i18n.Translate>Could not load pay status</i18n.Translate>}
-      error={error}
-    />
-  );
-}
-
 type SupportedStates =
   | State.Ready
   | State.Confirmed
@@ -66,17 +55,17 @@ export function BaseView(state: SupportedStates): VNode {
 
       <section style={{ textAlign: "left" }}>
         <Part
-          title={<i18n.Translate>Purchase</i18n.Translate>}
-          text={contractTerms.summary}
+          title={i18n.str`Purchase`}
+          text={contractTerms.summary as TranslatedString}
           kind="neutral"
         />
         <Part
-          title={<i18n.Translate>Merchant</i18n.Translate>}
+          title={i18n.str`Merchant`}
           text={<MerchantDetails merchant={contractTerms.merchant} />}
           kind="neutral"
         />
         <Part
-          title={<i18n.Translate>Details</i18n.Translate>}
+          title={i18n.str`Details`}
           text={
             <PurchaseDetails
               price={price}
@@ -93,14 +82,14 @@ export function BaseView(state: SupportedStates): VNode {
         />
         {contractTerms.order_id && (
           <Part
-            title={<i18n.Translate>Receipt</i18n.Translate>}
-            text={`#${contractTerms.order_id}`}
+            title={i18n.str`Receipt`}
+            text={`#${contractTerms.order_id}` as TranslatedString}
             kind="neutral"
           />
         )}
         {contractTerms.pay_deadline && (
           <Part
-            title={<i18n.Translate>Valid until</i18n.Translate>}
+            title={i18n.str`Valid until`}
             text={
               <Time
                 timestamp={AbsoluteTime.fromTimestamp(
@@ -121,11 +110,6 @@ export function BaseView(state: SupportedStates): VNode {
         payHandler={state.status === "ready" ? state.payHandler : undefined}
         goToWalletManualWithdraw={state.goToWalletManualWithdraw}
       />
-      <section>
-        <Link upperCased onClick={state.cancel}>
-          <i18n.Translate>Cancel</i18n.Translate>
-        </Link>
-      </section>
     </Fragment>
   );
 }
diff --git a/packages/taler-wallet-webextension/src/cta/Recovery/index.ts 
b/packages/taler-wallet-webextension/src/cta/Recovery/index.ts
index 4a6fc79c9..79056c15b 100644
--- a/packages/taler-wallet-webextension/src/cta/Recovery/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/Recovery/index.ts
@@ -14,12 +14,13 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
+import { ErrorAlertView } from "../../components/CurrentAlerts.js";
 import { Loading } from "../../components/Loading.js";
-import { HookError } from "../../hooks/useAsyncAsHook.js";
+import { ErrorAlert } from "../../context/alert.js";
 import { ButtonHandler } from "../../mui/handlers.js";
 import { compose, StateViewMap } from "../../utils/index.js";
 import { useComponentState } from "./state.js";
-import { LoadingUriView, ReadyView } from "./views.js";
+import { ReadyView } from "./views.js";
 
 export interface Props {
   talerRecoveryUri?: string;
@@ -36,8 +37,8 @@ export namespace State {
   }
 
   export interface LoadingUriError {
-    status: "loading-uri";
-    error: HookError;
+    status: "error";
+    error: ErrorAlert;
   }
 
   export interface BaseInfo {
@@ -53,7 +54,7 @@ export namespace State {
 
 const viewMapping: StateViewMap<State> = {
   loading: Loading,
-  "loading-uri": LoadingUriView,
+  error: ErrorAlertView,
   ready: ReadyView,
 };
 
diff --git a/packages/taler-wallet-webextension/src/cta/Recovery/state.ts 
b/packages/taler-wallet-webextension/src/cta/Recovery/state.ts
index 4fef2c862..078e53bf9 100644
--- a/packages/taler-wallet-webextension/src/cta/Recovery/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/Recovery/state.ts
@@ -16,7 +16,9 @@
 
 import { parseRecoveryUri } from "@gnu-taler/taler-util";
 import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
+import { Alert } from "../../context/alert.js";
 import { useBackendContext } from "../../context/backend.js";
+import { useTranslationContext } from "../../context/translation.js";
 import { Props, State } from "./index.js";
 
 export function useComponentState({
@@ -25,13 +27,16 @@ export function useComponentState({
   onSuccess,
 }: Props): State {
   const api = useBackendContext();
+  const { i18n } = useTranslationContext();
   if (!talerRecoveryUri) {
     return {
-      status: "loading-uri",
+      status: "error",
       error: {
-        operational: false,
-        hasError: true,
-        message: "Missing URI",
+        type: "error",
+        message: i18n.str`Missing URI`,
+        description: i18n.str``,
+        cause: new Error("something"),
+        context: {},
       },
     };
   }
@@ -39,11 +44,13 @@ export function useComponentState({
 
   if (!info) {
     return {
-      status: "loading-uri",
+      status: "error",
       error: {
-        operational: false,
-        hasError: true,
-        message: "Could not be read",
+        type: "error",
+        message: i18n.str`Could not parse the recovery URI`,
+        description: i18n.str``,
+        cause: new Error("something"),
+        context: {},
       },
     };
   }
diff --git a/packages/taler-wallet-webextension/src/cta/Recovery/views.tsx 
b/packages/taler-wallet-webextension/src/cta/Recovery/views.tsx
index 371516932..858349ef3 100644
--- a/packages/taler-wallet-webextension/src/cta/Recovery/views.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Recovery/views.tsx
@@ -15,28 +15,12 @@
  */
 
 import { Fragment, h, VNode } from "preact";
-import { LoadingError } from "../../components/LoadingError.js";
 import { LogoHeader } from "../../components/LogoHeader.js";
 import { SubTitle, WalletAction } from "../../components/styled/index.js";
 import { useTranslationContext } from "../../context/translation.js";
 import { Button } from "../../mui/Button.js";
 import { State } from "./index.js";
 
-export function LoadingUriView({ error }: State.LoadingUriError): VNode {
-  const { i18n } = useTranslationContext();
-
-  return (
-    <LoadingError
-      title={
-        <i18n.Translate>
-          Could not load backup recovery information
-        </i18n.Translate>
-      }
-      error={error}
-    />
-  );
-}
-
 export function ReadyView({ accept, cancel }: State.Ready): VNode {
   const { i18n } = useTranslationContext();
   return (
diff --git a/packages/taler-wallet-webextension/src/cta/Refund/index.ts 
b/packages/taler-wallet-webextension/src/cta/Refund/index.ts
index f79a77680..e90f770ff 100644
--- a/packages/taler-wallet-webextension/src/cta/Refund/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/Refund/index.ts
@@ -15,17 +15,13 @@
  */
 
 import { AmountJson, Product } from "@gnu-taler/taler-util";
+import { ErrorAlertView } from "../../components/CurrentAlerts.js";
 import { Loading } from "../../components/Loading.js";
-import { HookError } from "../../hooks/useAsyncAsHook.js";
+import { ErrorAlert } from "../../context/alert.js";
 import { ButtonHandler } from "../../mui/handlers.js";
 import { compose, StateViewMap } from "../../utils/index.js";
 import { useComponentState } from "./state.js";
-import {
-  IgnoredView,
-  InProgressView,
-  LoadingUriView,
-  ReadyView,
-} from "./views.js";
+import { IgnoredView, InProgressView, ReadyView } from "./views.js";
 
 export interface Props {
   talerRefundUri?: string;
@@ -47,8 +43,8 @@ export namespace State {
   }
 
   export interface LoadingUriError {
-    status: "loading-uri";
-    error: HookError;
+    status: "error";
+    error: ErrorAlert;
   }
 
   interface BaseInfo {
@@ -81,7 +77,7 @@ export namespace State {
 
 const viewMapping: StateViewMap<State> = {
   loading: Loading,
-  "loading-uri": LoadingUriView,
+  error: ErrorAlertView,
   "in-progress": InProgressView,
   ignored: IgnoredView,
   ready: ReadyView,
diff --git a/packages/taler-wallet-webextension/src/cta/Refund/state.ts 
b/packages/taler-wallet-webextension/src/cta/Refund/state.ts
index 9e3311b65..5a5073ba3 100644
--- a/packages/taler-wallet-webextension/src/cta/Refund/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/Refund/state.ts
@@ -17,7 +17,9 @@
 import { Amounts, NotificationType } from "@gnu-taler/taler-util";
 import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
 import { useEffect, useState } from "preact/hooks";
+import { alertFromError } from "../../context/alert.js";
 import { useBackendContext } from "../../context/backend.js";
+import { useTranslationContext } from "../../context/translation.js";
 import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
 import { Props, State } from "./index.js";
 
@@ -27,6 +29,7 @@ export function useComponentState({
   onSuccess,
 }: Props): State {
   const api = useBackendContext();
+  const { i18n } = useTranslationContext();
   const [ignored, setIgnored] = useState(false);
 
   const info = useAsyncAsHook(async () => {
@@ -49,10 +52,19 @@ export function useComponentState({
   }
   if (info.hasError) {
     return {
-      status: "loading-uri",
-      error: info,
+      status: "error",
+      error: alertFromError(
+        i18n.str`Could not load the status of the term of service`,
+        info,
+      ),
     };
   }
+  // if (info.hasError) {
+  //   return {
+  //     status: "loading-uri",
+  //     error: info,
+  //   };
+  // }
 
   const { refund, uri } = info.response;
 
diff --git a/packages/taler-wallet-webextension/src/cta/Refund/test.ts 
b/packages/taler-wallet-webextension/src/cta/Refund/test.ts
index 24d483a9a..8c4daa4d2 100644
--- a/packages/taler-wallet-webextension/src/cta/Refund/test.ts
+++ b/packages/taler-wallet-webextension/src/cta/Refund/test.ts
@@ -53,11 +53,11 @@ describe("Refund CTA states", () => {
           expect(error).undefined;
         },
         ({ status, error }) => {
-          expect(status).equals("loading-uri");
+          expect(status).equals("error");
           if (!error) expect.fail();
-          if (!error.hasError) expect.fail();
-          if (error.operational) expect.fail();
-          expect(error.message).eq("ERROR_NO-URI-FOR-REFUND");
+          // if (!error.hasError) expect.fail();
+          // if (error.operational) expect.fail();
+          expect(error.cause?.message).eq("ERROR_NO-URI-FOR-REFUND");
         },
       ],
       TestingContext,
diff --git a/packages/taler-wallet-webextension/src/cta/Refund/views.tsx 
b/packages/taler-wallet-webextension/src/cta/Refund/views.tsx
index a55bc43dd..16e1c519c 100644
--- a/packages/taler-wallet-webextension/src/cta/Refund/views.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Refund/views.tsx
@@ -17,26 +17,14 @@
 import { Amounts } from "@gnu-taler/taler-util";
 import { Fragment, h, VNode } from "preact";
 import { Amount } from "../../components/Amount.js";
-import { LoadingError } from "../../components/LoadingError.js";
 import { LogoHeader } from "../../components/LogoHeader.js";
 import { Part } from "../../components/Part.js";
+import { ProductList } from "../../components/ProductList.js";
 import { Link, SubTitle, WalletAction } from 
"../../components/styled/index.js";
 import { useTranslationContext } from "../../context/translation.js";
 import { Button } from "../../mui/Button.js";
-import { ProductList } from "../../components/ProductList.js";
 import { State } from "./index.js";
 
-export function LoadingUriView({ error }: State.LoadingUriError): VNode {
-  const { i18n } = useTranslationContext();
-
-  return (
-    <LoadingError
-      title={<i18n.Translate>Could not load refund status</i18n.Translate>}
-      error={error}
-    />
-  );
-}
-
 export function IgnoredView(state: State.Ignored): VNode {
   const { i18n } = useTranslationContext();
 
@@ -73,13 +61,13 @@ export function InProgressView(state: State.InProgress): 
VNode {
       <section>
         <Part
           big
-          title={<i18n.Translate>Total to refund</i18n.Translate>}
+          title={i18n.str`Total to refund`}
           text={<Amount value={state.awaitingAmount} />}
           kind="negative"
         />
         <Part
           big
-          title={<i18n.Translate>Refunded</i18n.Translate>}
+          title={i18n.str`Refunded`}
           text={<Amount value={state.amount} />}
           kind="negative"
         />
@@ -112,21 +100,21 @@ export function ReadyView(state: State.Ready): VNode {
       <section>
         <Part
           big
-          title={<i18n.Translate>Order amount</i18n.Translate>}
+          title={i18n.str`Order amount`}
           text={<Amount value={state.amount} />}
           kind="neutral"
         />
         {Amounts.isNonZero(state.granted) && (
           <Part
             big
-            title={<i18n.Translate>Already refunded</i18n.Translate>}
+            title={i18n.str`Already refunded`}
             text={<Amount value={state.granted} />}
             kind="neutral"
           />
         )}
         <Part
           big
-          title={<i18n.Translate>Refund offered</i18n.Translate>}
+          title={i18n.str`Refund offered`}
           text={<Amount value={state.awaitingAmount} />}
           kind="positive"
         />
@@ -147,11 +135,6 @@ export function ReadyView(state: State.Ready): VNode {
           </i18n.Translate>
         </Button>
       </section>
-      <section>
-        <Link upperCased onClick={state.cancel}>
-          <i18n.Translate>Cancel</i18n.Translate>
-        </Link>
-      </section>
     </WalletAction>
   );
 }
diff --git a/packages/taler-wallet-webextension/src/cta/Tip/index.ts 
b/packages/taler-wallet-webextension/src/cta/Tip/index.ts
index 62e0688be..5e56db7bc 100644
--- a/packages/taler-wallet-webextension/src/cta/Tip/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/Tip/index.ts
@@ -15,17 +15,13 @@
  */
 
 import { AmountJson } from "@gnu-taler/taler-util";
+import { ErrorAlertView } from "../../components/CurrentAlerts.js";
 import { Loading } from "../../components/Loading.js";
-import { HookError } from "../../hooks/useAsyncAsHook.js";
+import { ErrorAlert } from "../../context/alert.js";
 import { ButtonHandler } from "../../mui/handlers.js";
 import { compose, StateViewMap } from "../../utils/index.js";
 import { useComponentState } from "./state.js";
-import {
-  AcceptedView,
-  IgnoredView,
-  LoadingUriView,
-  ReadyView,
-} from "./views.js";
+import { AcceptedView, IgnoredView, ReadyView } from "./views.js";
 
 export interface Props {
   talerTipUri?: string;
@@ -48,8 +44,8 @@ export namespace State {
   }
 
   export interface LoadingUriError {
-    status: "loading-uri";
-    error: HookError;
+    status: "error";
+    error: ErrorAlert;
   }
 
   export interface BaseInfo {
@@ -75,7 +71,7 @@ export namespace State {
 
 const viewMapping: StateViewMap<State> = {
   loading: Loading,
-  "loading-uri": LoadingUriView,
+  error: ErrorAlertView,
   accepted: AcceptedView,
   ignored: IgnoredView,
   ready: ReadyView,
diff --git a/packages/taler-wallet-webextension/src/cta/Tip/state.ts 
b/packages/taler-wallet-webextension/src/cta/Tip/state.ts
index e83755119..29a9c4c71 100644
--- a/packages/taler-wallet-webextension/src/cta/Tip/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/Tip/state.ts
@@ -16,7 +16,9 @@
 
 import { Amounts } from "@gnu-taler/taler-util";
 import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
+import { alertFromError } from "../../context/alert.js";
 import { useBackendContext } from "../../context/backend.js";
+import { useTranslationContext } from "../../context/translation.js";
 import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
 import { Props, State } from "./index.js";
 
@@ -26,6 +28,7 @@ export function useComponentState({
   onSuccess,
 }: Props): State {
   const api = useBackendContext();
+  const { i18n } = useTranslationContext();
   const tipInfo = useAsyncAsHook(async () => {
     if (!talerTipUri) throw Error("ERROR_NO-URI-FOR-TIP");
     const tip = await api.wallet.call(WalletApiOperation.PrepareTip, {
@@ -42,10 +45,19 @@ export function useComponentState({
   }
   if (tipInfo.hasError) {
     return {
-      status: "loading-uri",
-      error: tipInfo,
+      status: "error",
+      error: alertFromError(
+        i18n.str`Could not load the status of the term of service`,
+        tipInfo,
+      ),
     };
   }
+  // if (tipInfo.hasError) {
+  //   return {
+  //     status: "loading-uri",
+  //     error: tipInfo,
+  //   };
+  // }
 
   const { tip } = tipInfo.response;
 
diff --git a/packages/taler-wallet-webextension/src/cta/Tip/test.ts 
b/packages/taler-wallet-webextension/src/cta/Tip/test.ts
index 5688d82a9..2cc95f424 100644
--- a/packages/taler-wallet-webextension/src/cta/Tip/test.ts
+++ b/packages/taler-wallet-webextension/src/cta/Tip/test.ts
@@ -23,8 +23,7 @@ import { Amounts } from "@gnu-taler/taler-util";
 import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
 import { expect } from "chai";
 import { tests } from "../../../../web-util/src/index.browser.js";
-import { mountHook, nullFunction } from "../../test-utils.js";
-import { createWalletApiMock } from "../../test-utils.js";
+import { createWalletApiMock, nullFunction } from "../../test-utils.js";
 import { Props } from "./index.js";
 import { useComponentState } from "./state.js";
 
@@ -47,11 +46,9 @@ describe("Tip CTA states", () => {
           expect(error).undefined;
         },
         ({ status, error }) => {
-          expect(status).equals("loading-uri");
+          expect(status).equals("error");
           if (!error) expect.fail();
-          if (!error.hasError) expect.fail();
-          if (error.operational) expect.fail();
-          expect(error.message).eq("ERROR_NO-URI-FOR-TIP");
+          expect(error.cause?.message).eq("ERROR_NO-URI-FOR-TIP");
         },
       ],
       TestingContext,
diff --git a/packages/taler-wallet-webextension/src/cta/Tip/views.tsx 
b/packages/taler-wallet-webextension/src/cta/Tip/views.tsx
index fbc93c5ab..000daf19e 100644
--- a/packages/taler-wallet-webextension/src/cta/Tip/views.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Tip/views.tsx
@@ -14,9 +14,9 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
+import { TranslatedString } from "@gnu-taler/taler-util";
 import { Fragment, h, VNode } from "preact";
 import { Amount } from "../../components/Amount.js";
-import { LoadingError } from "../../components/LoadingError.js";
 import { LogoHeader } from "../../components/LogoHeader.js";
 import { Part } from "../../components/Part.js";
 import { Link, SubTitle, WalletAction } from 
"../../components/styled/index.js";
@@ -24,17 +24,6 @@ import { useTranslationContext } from 
"../../context/translation.js";
 import { Button } from "../../mui/Button.js";
 import { State } from "./index.js";
 
-export function LoadingUriView({ error }: State.LoadingUriError): VNode {
-  const { i18n } = useTranslationContext();
-
-  return (
-    <LoadingError
-      title={<i18n.Translate>Could not load tip status</i18n.Translate>}
-      error={error}
-    />
-  );
-}
-
 export function IgnoredView(state: State.Ignored): VNode {
   const { i18n } = useTranslationContext();
   return (
@@ -66,18 +55,18 @@ export function ReadyView(state: State.Ready): VNode {
           <i18n.Translate>The merchant is offering you a tip</i18n.Translate>
         </p>
         <Part
-          title={<i18n.Translate>Amount</i18n.Translate>}
+          title={i18n.str`Amount`}
           text={<Amount value={state.amount} />}
           kind="positive"
         />
         <Part
-          title={<i18n.Translate>Merchant URL</i18n.Translate>}
-          text={state.merchantBaseUrl}
+          title={i18n.str`Merchant URL`}
+          text={state.merchantBaseUrl as TranslatedString}
           kind="neutral"
         />
         <Part
-          title={<i18n.Translate>Exchange</i18n.Translate>}
-          text={state.exchangeBaseUrl}
+          title={i18n.str`Exchange`}
+          text={state.exchangeBaseUrl as TranslatedString}
           kind="neutral"
         />
       </section>
@@ -92,11 +81,6 @@ export function ReadyView(state: State.Ready): VNode {
           </i18n.Translate>
         </Button>
       </section>
-      <section>
-        <Link upperCased onClick={state.cancel.onClick}>
-          <i18n.Translate>Cancel</i18n.Translate>
-        </Link>
-      </section>
     </WalletAction>
   );
 }
diff --git a/packages/taler-wallet-webextension/src/cta/TransferCreate/index.ts 
b/packages/taler-wallet-webextension/src/cta/TransferCreate/index.ts
index 0715bb60e..b191b4efa 100644
--- a/packages/taler-wallet-webextension/src/cta/TransferCreate/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/TransferCreate/index.ts
@@ -15,12 +15,13 @@
  */
 
 import { AmountJson, TalerErrorDetail } from "@gnu-taler/taler-util";
+import { ErrorAlertView } from "../../components/CurrentAlerts.js";
 import { Loading } from "../../components/Loading.js";
-import { HookError } from "../../hooks/useAsyncAsHook.js";
+import { ErrorAlert } from "../../context/alert.js";
 import { ButtonHandler, TextFieldHandler } from "../../mui/handlers.js";
 import { compose, StateViewMap } from "../../utils/index.js";
 import { useComponentState } from "./state.js";
-import { LoadingUriView, ReadyView } from "./views.js";
+import { ReadyView } from "./views.js";
 
 export interface Props {
   amount: string;
@@ -37,8 +38,8 @@ export namespace State {
   }
 
   export interface LoadingUriError {
-    status: "loading-uri";
-    error: HookError;
+    status: "error";
+    error: ErrorAlert;
   }
 
   export interface BaseInfo {
@@ -59,7 +60,7 @@ export namespace State {
 
 const viewMapping: StateViewMap<State> = {
   loading: Loading,
-  "loading-uri": LoadingUriView,
+  error: ErrorAlertView,
   ready: ReadyView,
 };
 
diff --git a/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts 
b/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts
index c09a524c8..ecea53848 100644
--- a/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts
@@ -22,7 +22,9 @@ import {
 import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
 import { isFuture, parse } from "date-fns";
 import { useState } from "preact/hooks";
+import { alertFromError } from "../../context/alert.js";
 import { useBackendContext } from "../../context/backend.js";
+import { useTranslationContext } from "../../context/translation.js";
 import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
 import { Props, State } from "./index.js";
 
@@ -33,6 +35,7 @@ export function useComponentState({
 }: Props): State {
   const api = useBackendContext();
   const amount = Amounts.parseOrThrow(amountStr);
+  const { i18n } = useTranslationContext();
 
   const [subject, setSubject] = useState<string | undefined>();
   const [timestamp, setTimestamp] = useState<string | undefined>();
@@ -59,10 +62,19 @@ export function useComponentState({
   }
   if (hook.hasError) {
     return {
-      status: "loading-uri",
-      error: hook,
+      status: "error",
+      error: alertFromError(
+        i18n.str`Could not load the status of the term of service`,
+        hook,
+      ),
     };
   }
+  // if (hook.hasError) {
+  //   return {
+  //     status: "loading-uri",
+  //     error: hook,
+  //   };
+  // }
 
   const { amountEffective, amountRaw } = hook.response;
   const debitAmount = Amounts.parseOrThrow(amountRaw);
diff --git 
a/packages/taler-wallet-webextension/src/cta/TransferCreate/views.tsx 
b/packages/taler-wallet-webextension/src/cta/TransferCreate/views.tsx
index 0b034e3fb..cee61b3b8 100644
--- a/packages/taler-wallet-webextension/src/cta/TransferCreate/views.tsx
+++ b/packages/taler-wallet-webextension/src/cta/TransferCreate/views.tsx
@@ -17,10 +17,8 @@
 import { format } from "date-fns";
 import { h, VNode } from "preact";
 import { ErrorTalerOperation } from "../../components/ErrorTalerOperation.js";
-import { LoadingError } from "../../components/LoadingError.js";
 import { LogoHeader } from "../../components/LogoHeader.js";
 import { Part } from "../../components/Part.js";
-import { QR } from "../../components/QR.js";
 import { Link, SubTitle, WalletAction } from 
"../../components/styled/index.js";
 import { useTranslationContext } from "../../context/translation.js";
 import { Button } from "../../mui/Button.js";
@@ -28,17 +26,6 @@ import { TextField } from "../../mui/TextField.js";
 import { TransferDetails } from "../../wallet/Transaction.js";
 import { State } from "./index.js";
 
-export function LoadingUriView({ error }: State.LoadingUriError): VNode {
-  const { i18n } = useTranslationContext();
-
-  return (
-    <LoadingError
-      title={<i18n.Translate>Could not load</i18n.Translate>}
-      error={error}
-    />
-  );
-}
-
 export function ReadyView({
   subject,
   expiration,
@@ -80,11 +67,7 @@ export function ReadyView({
       </SubTitle>
       {operationError && (
         <ErrorTalerOperation
-          title={
-            <i18n.Translate>
-              Could not finish the transfer creation
-            </i18n.Translate>
-          }
+          title={i18n.str`Could not finish the transfer creation`}
           error={operationError}
         />
       )}
@@ -93,9 +76,7 @@ export function ReadyView({
           <TextField
             label="Subject"
             variant="filled"
-            helperText={
-              <i18n.Translate>Short description of the 
transfer</i18n.Translate>
-            }
+            helperText={i18n.str`Short description of the transfer`}
             error={subject.error}
             required
             fullWidth
@@ -138,7 +119,7 @@ export function ReadyView({
           </p>
         </p>
         <Part
-          title={<i18n.Translate>Details</i18n.Translate>}
+          title={i18n.str`Details`}
           text={
             <TransferDetails
               amount={{
@@ -154,13 +135,6 @@ export function ReadyView({
           <i18n.Translate>Create</i18n.Translate>
         </Button>
       </section>
-      <section>
-        <section>
-          <Link upperCased onClick={cancel.onClick}>
-            <i18n.Translate>Cancel</i18n.Translate>
-          </Link>
-        </section>
-      </section>
     </WalletAction>
   );
 }
diff --git a/packages/taler-wallet-webextension/src/cta/TransferPickup/index.ts 
b/packages/taler-wallet-webextension/src/cta/TransferPickup/index.ts
index fe6fb2ada..7bb8785d7 100644
--- a/packages/taler-wallet-webextension/src/cta/TransferPickup/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/TransferPickup/index.ts
@@ -19,12 +19,13 @@ import {
   AmountJson,
   TalerErrorDetail,
 } from "@gnu-taler/taler-util";
+import { ErrorAlertView } from "../../components/CurrentAlerts.js";
 import { Loading } from "../../components/Loading.js";
-import { HookError } from "../../hooks/useAsyncAsHook.js";
+import { ErrorAlert } from "../../context/alert.js";
 import { ButtonHandler } from "../../mui/handlers.js";
 import { compose, StateViewMap } from "../../utils/index.js";
 import { useComponentState } from "./state.js";
-import { LoadingUriView, ReadyView } from "./views.js";
+import { ReadyView } from "./views.js";
 
 export interface Props {
   talerPayPushUri: string;
@@ -41,8 +42,8 @@ export namespace State {
   }
 
   export interface LoadingUriError {
-    status: "loading-uri";
-    error: HookError;
+    status: "error";
+    error: ErrorAlert;
   }
 
   export interface BaseInfo {
@@ -62,7 +63,7 @@ export namespace State {
 
 const viewMapping: StateViewMap<State> = {
   loading: Loading,
-  "loading-uri": LoadingUriView,
+  error: ErrorAlertView,
   ready: ReadyView,
 };
 
diff --git a/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts 
b/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts
index 82c95b0c6..04fc0e0a7 100644
--- a/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts
@@ -22,7 +22,9 @@ import {
 } from "@gnu-taler/taler-util";
 import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
 import { useState } from "preact/hooks";
+import { alertFromError } from "../../context/alert.js";
 import { useBackendContext } from "../../context/backend.js";
+import { useTranslationContext } from "../../context/translation.js";
 import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
 import { Props, State } from "./index.js";
 
@@ -32,6 +34,7 @@ export function useComponentState({
   onSuccess,
 }: Props): State {
   const api = useBackendContext();
+  const { i18n } = useTranslationContext();
   const hook = useAsyncAsHook(async () => {
     return await api.wallet.call(WalletApiOperation.CheckPeerPushPayment, {
       talerUri: talerPayPushUri,
@@ -49,10 +52,19 @@ export function useComponentState({
   }
   if (hook.hasError) {
     return {
-      status: "loading-uri",
-      error: hook,
+      status: "error",
+      error: alertFromError(
+        i18n.str`Could not load the status of the term of service`,
+        hook,
+      ),
     };
   }
+  // if (hook.hasError) {
+  //   return {
+  //     status: "loading-uri",
+  //     error: hook,
+  //   };
+  // }
 
   const { contractTerms, peerPushPaymentIncomingId } = hook.response;
 
diff --git 
a/packages/taler-wallet-webextension/src/cta/TransferPickup/views.tsx 
b/packages/taler-wallet-webextension/src/cta/TransferPickup/views.tsx
index c43b0ff52..d2402db3a 100644
--- a/packages/taler-wallet-webextension/src/cta/TransferPickup/views.tsx
+++ b/packages/taler-wallet-webextension/src/cta/TransferPickup/views.tsx
@@ -17,7 +17,6 @@
 import { h, VNode } from "preact";
 import { Amount } from "../../components/Amount.js";
 import { ErrorTalerOperation } from "../../components/ErrorTalerOperation.js";
-import { LoadingError } from "../../components/LoadingError.js";
 import { LogoHeader } from "../../components/LogoHeader.js";
 import { Part } from "../../components/Part.js";
 import { Link, SubTitle, WalletAction } from 
"../../components/styled/index.js";
@@ -26,17 +25,6 @@ import { useTranslationContext } from 
"../../context/translation.js";
 import { Button } from "../../mui/Button.js";
 import { State } from "./index.js";
 
-export function LoadingUriView({ error }: State.LoadingUriError): VNode {
-  const { i18n } = useTranslationContext();
-
-  return (
-    <LoadingError
-      title={<i18n.Translate>Could not load</i18n.Translate>}
-      error={error}
-    />
-  );
-}
-
 export function ReadyView({
   accept,
   summary,
@@ -54,25 +42,15 @@ export function ReadyView({
       </SubTitle>
       {operationError && (
         <ErrorTalerOperation
-          title={
-            <i18n.Translate>
-              Could not finish the pickup operation
-            </i18n.Translate>
-          }
+          title={i18n.str`Could not finish the pickup operation`}
           error={operationError}
         />
       )}
       <section style={{ textAlign: "left" }}>
+        <Part title={i18n.str`Subject`} text={<div>{summary}</div>} />
+        <Part title={i18n.str`Amount`} text={<Amount value={amount} />} />
         <Part
-          title={<i18n.Translate>Subject</i18n.Translate>}
-          text={<div>{summary}</div>}
-        />
-        <Part
-          title={<i18n.Translate>Amount</i18n.Translate>}
-          text={<Amount value={amount} />}
-        />
-        <Part
-          title={<i18n.Translate>Valid until</i18n.Translate>}
+          title={i18n.str`Valid until`}
           text={<Time timestamp={expiration} format="dd MMMM yyyy, HH:mm" />}
           kind="neutral"
         />
@@ -84,11 +62,6 @@ export function ReadyView({
           </i18n.Translate>
         </Button>
       </section>
-      <section>
-        <Link upperCased onClick={cancel.onClick}>
-          <i18n.Translate>Cancel</i18n.Translate>
-        </Link>
-      </section>
     </WalletAction>
   );
 }
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts 
b/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts
index 25d4e44e5..7dfc7c141 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts
@@ -27,7 +27,9 @@ import {
 
 import { ExchangeSelectionPage } from 
"../../wallet/ExchangeSelection/index.js";
 import { NoExchangesView } from "../../wallet/ExchangeSelection/views.js";
-import { LoadingInfoView, LoadingUriView, SuccessView } from "./views.js";
+import { SuccessView } from "./views.js";
+import { ErrorAlert } from "../../context/alert.js";
+import { ErrorAlertView } from "../../components/CurrentAlerts.js";
 
 export interface PropsFromURI {
   talerWithdrawUri: string | undefined;
@@ -44,7 +46,6 @@ export interface PropsFromParams {
 export type State =
   | State.Loading
   | State.LoadingUriError
-  | State.LoadingInfoError
   | SelectExchangeState.NoExchange
   | SelectExchangeState.Selecting
   | State.Success;
@@ -55,12 +56,8 @@ export namespace State {
     error: undefined;
   }
   export interface LoadingUriError {
-    status: "uri-error";
-    error: HookError;
-  }
-  export interface LoadingInfoError {
-    status: "amount-error";
-    error: HookError;
+    status: "error";
+    error: ErrorAlert;
   }
 
   export type Success = {
@@ -86,8 +83,7 @@ export namespace State {
 
 const viewMapping: StateViewMap<State> = {
   loading: Loading,
-  "uri-error": LoadingUriView,
-  "amount-error": LoadingInfoView,
+  error: ErrorAlertView,
   "no-exchange": NoExchangesView,
   "selecting-exchange": ExchangeSelectionPage,
   success: SuccessView,
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts 
b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts
index d1853442b..18c467aae 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts
@@ -23,7 +23,9 @@ import {
 } from "@gnu-taler/taler-util";
 import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
 import { useState } from "preact/hooks";
+import { alertFromError } from "../../context/alert.js";
 import { useBackendContext } from "../../context/backend.js";
+import { useTranslationContext } from "../../context/translation.js";
 import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
 import { useSelectedExchange } from "../../hooks/useSelectedExchange.js";
 import { RecursiveState } from "../../utils/index.js";
@@ -35,6 +37,7 @@ export function useComponentStateFromParams({
   onSuccess,
 }: PropsFromParams): RecursiveState<State> {
   const api = useBackendContext();
+  const { i18n } = useTranslationContext();
   const uriInfoHook = useAsyncAsHook(async () => {
     const exchanges = await api.wallet.call(
       WalletApiOperation.ListExchanges,
@@ -47,8 +50,11 @@ export function useComponentStateFromParams({
 
   if (uriInfoHook.hasError) {
     return {
-      status: "uri-error",
-      error: uriInfoHook,
+      status: "error",
+      error: alertFromError(
+        i18n.str`Could not load the list of exchanges`,
+        uriInfoHook,
+      ),
     };
   }
 
@@ -95,6 +101,7 @@ export function useComponentStateFromURI({
   onSuccess,
 }: PropsFromURI): RecursiveState<State> {
   const api = useBackendContext();
+  const { i18n } = useTranslationContext();
   /**
    * Ask the wallet about the withdraw URI
    */
@@ -123,8 +130,11 @@ export function useComponentStateFromURI({
 
   if (uriInfoHook.hasError) {
     return {
-      status: "uri-error",
-      error: uriInfoHook,
+      status: "error",
+      error: alertFromError(
+        i18n.str`Could not load info from URI`,
+        uriInfoHook,
+      ),
     };
   }
 
@@ -194,6 +204,7 @@ function exchangeSelectionState(
   }
 
   return () => {
+    const { i18n } = useTranslationContext();
     const [ageRestricted, setAgeRestricted] = useState(0);
     const currentExchange = selectedExchange.selected;
     const tosNeedToBeAccepted =
@@ -255,8 +266,11 @@ function exchangeSelectionState(
     }
     if (amountHook.hasError) {
       return {
-        status: "amount-error",
-        error: amountHook,
+        status: "error",
+        error: alertFromError(
+          i18n.str`Could not load the withdrawal details`,
+          amountHook,
+        ),
       };
     }
     if (!amountHook.response) {
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts 
b/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts
index 3277ac18d..2caa50dca 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts
@@ -84,11 +84,11 @@ describe("Withdraw CTA states", () => {
           expect(status).equals("loading");
         },
         ({ status, error }) => {
-          if (status != "uri-error") expect.fail();
+          if (status != "error") expect.fail();
           if (!error) expect.fail();
-          if (!error.hasError) expect.fail();
-          if (error.operational) expect.fail();
-          expect(error.message).eq("ERROR_NO-URI-FOR-WITHDRAWAL");
+          // if (!error.hasError) expect.fail();
+          // if (error.operational) expect.fail();
+          expect(error.cause?.message).eq("ERROR_NO-URI-FOR-WITHDRAWAL");
         },
       ],
       TestingContext,
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx 
b/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx
index 9dbe24b7e..cf87b35bb 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx
@@ -19,16 +19,10 @@ import { Fragment, h, VNode } from "preact";
 import { useState } from "preact/hooks";
 import { Amount } from "../../components/Amount.js";
 import { ErrorTalerOperation } from "../../components/ErrorTalerOperation.js";
-import { LoadingError } from "../../components/LoadingError.js";
 import { Part } from "../../components/Part.js";
 import { QR } from "../../components/QR.js";
 import { SelectList } from "../../components/SelectList.js";
-import {
-  Input,
-  Link,
-  LinkSuccess,
-  SvgIcon,
-} from "../../components/styled/index.js";
+import { Input, LinkSuccess, SvgIcon } from "../../components/styled/index.js";
 import { TermsOfService } from "../../components/TermsOfService/index.js";
 import { useTranslationContext } from "../../context/translation.js";
 import { Button } from "../../mui/Button.js";
@@ -36,30 +30,6 @@ import editIcon from "../../svg/edit_24px.svg";
 import { ExchangeDetails, WithdrawDetails } from "../../wallet/Transaction.js";
 import { State } from "./index.js";
 
-export function LoadingUriView({ error }: State.LoadingUriError): VNode {
-  const { i18n } = useTranslationContext();
-
-  return (
-    <LoadingError
-      title={
-        <i18n.Translate>Could not get the info from the URI</i18n.Translate>
-      }
-      error={error}
-    />
-  );
-}
-
-export function LoadingInfoView({ error }: State.LoadingInfoError): VNode {
-  const { i18n } = useTranslationContext();
-
-  return (
-    <LoadingError
-      title={<i18n.Translate>Could not get info of withdrawal</i18n.Translate>}
-      error={error}
-    />
-  );
-}
-
 export function SuccessView(state: State.Success): VNode {
   const { i18n } = useTranslationContext();
   const currentTosVersionIsAccepted =
@@ -68,11 +38,7 @@ export function SuccessView(state: State.Success): VNode {
     <Fragment>
       {state.doWithdrawal.error && (
         <ErrorTalerOperation
-          title={
-            <i18n.Translate>
-              Could not finish the withdrawal operation
-            </i18n.Translate>
-          }
+          title={i18n.str`Could not finish the withdrawal operation`}
           error={state.doWithdrawal.error.errorDetail}
         />
       )}
@@ -103,7 +69,7 @@ export function SuccessView(state: State.Success): VNode {
           big
         />
         <Part
-          title={<i18n.Translate>Details</i18n.Translate>}
+          title={i18n.str`Details`}
           text={
             <WithdrawDetails
               amount={{
@@ -116,7 +82,7 @@ export function SuccessView(state: State.Success): VNode {
         {state.ageRestriction && (
           <Input>
             <SelectList
-              label={<i18n.Translate>Age restriction</i18n.Translate>}
+              label={i18n.str`Age restriction`}
               list={state.ageRestriction.list}
               name="age"
               value={state.ageRestriction.value}
@@ -148,11 +114,6 @@ export function SuccessView(state: State.Success): VNode {
       {state.talerWithdrawUri ? (
         <WithdrawWithMobile talerWithdrawUri={state.talerWithdrawUri} />
       ) : undefined}
-      <section>
-        <Link upperCased onClick={state.cancel}>
-          <i18n.Translate>Cancel</i18n.Translate>
-        </Link>
-      </section>
     </Fragment>
   );
 }
@@ -168,11 +129,7 @@ function WithdrawWithMobile({
   return (
     <section>
       <LinkSuccess upperCased onClick={() => setShowQR((qr) => !qr)}>
-        {!showQR ? (
-          <i18n.Translate>Withdraw to a mobile phone</i18n.Translate>
-        ) : (
-          <i18n.Translate>Hide QR</i18n.Translate>
-        )}
+        {!showQR ? i18n.str`Withdraw to a mobile phone` : i18n.str`Hide QR`}
       </LinkSuccess>
       {showQR && (
         <div>
diff --git a/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts 
b/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts
index 1b2929317..978ea90e1 100644
--- a/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts
@@ -16,6 +16,7 @@
 import { TalerErrorDetail } from "@gnu-taler/taler-util";
 import { TalerError } from "@gnu-taler/taler-wallet-core";
 import { useEffect, useMemo, useState } from "preact/hooks";
+import { WalletError } from "../wxApi.js";
 
 export interface HookOk<T> {
   hasError: false;
@@ -26,13 +27,14 @@ export type HookError = HookGenericError | 
HookOperationalError;
 
 export interface HookGenericError {
   hasError: true;
-  operational: false;
+  type: "error";
   message: string;
 }
 
 export interface HookOperationalError {
   hasError: true;
-  operational: true;
+  type: "taler";
+  message: string;
   details: TalerErrorDetail;
 }
 
@@ -68,13 +70,21 @@ export function useAsyncAsHook<T>(
       if (e instanceof TalerError) {
         setHookResponse({
           hasError: true,
-          operational: true,
+          type: "taler",
+          message: e.message,
           details: e.errorDetail,
         });
+      } else if (e instanceof WalletError) {
+        setHookResponse({
+          hasError: true,
+          type: "taler",
+          message: e.message,
+          details: e.errorDetail.errorDetail,
+        });
       } else if (e instanceof Error) {
         setHookResponse({
           hasError: true,
-          operational: false,
+          type: "error",
           message: e.message,
         });
       }
diff --git a/packages/taler-wallet-webextension/src/hooks/useLang.ts 
b/packages/taler-wallet-webextension/src/hooks/useLang.ts
index 269fe6239..b1aa40015 100644
--- a/packages/taler-wallet-webextension/src/hooks/useLang.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useLang.ts
@@ -17,6 +17,7 @@
 import { useNotNullLocalStorage } from "./useLocalStorage.js";
 
 function getBrowserLang(): string | undefined {
+  if (typeof window === "undefined") return undefined;
   if (window.navigator.languages) return window.navigator.languages[0];
   if (window.navigator.language) return window.navigator.language;
   return undefined;
diff --git a/packages/taler-wallet-webextension/src/hooks/useLocalStorage.ts 
b/packages/taler-wallet-webextension/src/hooks/useLocalStorage.ts
index 88b7655b6..387798c96 100644
--- a/packages/taler-wallet-webextension/src/hooks/useLocalStorage.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useLocalStorage.ts
@@ -75,6 +75,9 @@ export function useNotNullLocalStorage(
     }
   };
 
-  const isSaved = window.localStorage.getItem(key) !== null;
+  const isSaved =
+    typeof window === "undefined"
+      ? false
+      : window.localStorage.getItem(key) !== null;
   return [storedValue, setValue, isSaved];
 }
diff --git a/packages/taler-wallet-webextension/src/mui/Alert.stories.tsx 
b/packages/taler-wallet-webextension/src/mui/Alert.stories.tsx
index 62f7a2993..b0c2a2730 100644
--- a/packages/taler-wallet-webextension/src/mui/Alert.stories.tsx
+++ b/packages/taler-wallet-webextension/src/mui/Alert.stories.tsx
@@ -19,6 +19,7 @@
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
+import { TranslatedString } from "@gnu-taler/taler-util";
 import { css } from "@linaria/core";
 import { ComponentChildren, Fragment, h, VNode } from "preact";
 import { Alert } from "./Alert.jsx";
@@ -53,16 +54,16 @@ export const BasicExample = (): VNode => (
 
 export const WithTitle = (): VNode => (
   <Wrapper>
-    <Alert title="Warning" severity="warning">
+    <Alert title={"Warning" as TranslatedString} severity="warning">
       this is an warning
     </Alert>
-    <Alert title="Error" severity="error">
+    <Alert title={"Error" as TranslatedString} severity="error">
       this is an error
     </Alert>
-    <Alert title="Success" severity="success">
+    <Alert title={"Success" as TranslatedString} severity="success">
       this is an success
     </Alert>
-    <Alert title="Info" severity="info">
+    <Alert title={"Info" as TranslatedString} severity="info">
       this is an info
     </Alert>
   </Wrapper>
@@ -74,16 +75,32 @@ const showSomething = async function (): Promise<void> {
 
 export const WithAction = (): VNode => (
   <Wrapper>
-    <Alert title="Warning" severity="warning" onClose={showSomething}>
+    <Alert
+      title={"Warning" as TranslatedString}
+      severity="warning"
+      onClose={showSomething}
+    >
       this is an warning
     </Alert>
-    <Alert title="Error" severity="error" onClose={showSomething}>
+    <Alert
+      title={"Error" as TranslatedString}
+      severity="error"
+      onClose={showSomething}
+    >
       this is an error
     </Alert>
-    <Alert title="Success" severity="success" onClose={showSomething}>
+    <Alert
+      title={"Success" as TranslatedString}
+      severity="success"
+      onClose={showSomething}
+    >
       this is an success
     </Alert>
-    <Alert title="Info" severity="info" onClose={showSomething}>
+    <Alert
+      title={"Info" as TranslatedString}
+      severity="info"
+      onClose={showSomething}
+    >
       this is an info
     </Alert>
   </Wrapper>
diff --git a/packages/taler-wallet-webextension/src/mui/Alert.tsx 
b/packages/taler-wallet-webextension/src/mui/Alert.tsx
index 360c3c3cb..b00312a86 100644
--- a/packages/taler-wallet-webextension/src/mui/Alert.tsx
+++ b/packages/taler-wallet-webextension/src/mui/Alert.tsx
@@ -13,6 +13,7 @@
  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 { TranslatedString } from "@gnu-taler/taler-util";
 import { css } from "@linaria/core";
 import { ComponentChildren, h, VNode } from "preact";
 // eslint-disable-next-line import/extensions
@@ -61,7 +62,7 @@ const colorVariant = {
 };
 
 interface Props {
-  title?: string;
+  title?: TranslatedString;
   variant?: "filled" | "outlined" | "standard";
   role?: string;
   onClose?: () => Promise<void>;
@@ -110,20 +111,20 @@ function Message({
   title,
   children,
 }: {
-  title?: string;
+  title?: TranslatedString;
   children: ComponentChildren;
 }): VNode {
   return (
     <div
       class={css`
         padding: 8px 0px;
-        width: 100%;
+        width: 90%;
       `}
     >
       {title && (
         <Typography
           class={css`
-            font-weight: ${theme.typography.fontWeightMedium};
+            font-weight: ${theme.typography.fontWeightBold};
           `}
           gutterBottom
         >
@@ -160,6 +161,7 @@ export function Alert({
         "--color-main": theme.palette[severity].main,
         "--color-light": theme.palette[severity].light,
         // ...(style as any),
+        textAlign: "left",
       }}
       elevation={1}
     >
diff --git a/packages/taler-wallet-webextension/src/mui/Paper.tsx 
b/packages/taler-wallet-webextension/src/mui/Paper.tsx
index 3b5f24bc1..0c805e307 100644
--- a/packages/taler-wallet-webextension/src/mui/Paper.tsx
+++ b/packages/taler-wallet-webextension/src/mui/Paper.tsx
@@ -29,9 +29,6 @@ const borderVariant = {
   `,
 };
 const baseStyle = css`
-  background-color: ${theme.palette.background.paper};
-  color: ${theme.palette.text.primary};
-
   .theme-dark & {
     background-image: var(--gradient-white-elevation);
   }
diff --git a/packages/taler-wallet-webextension/src/mui/colors/manipulation.ts 
b/packages/taler-wallet-webextension/src/mui/colors/manipulation.ts
index 226d3c860..f9bf9eb2b 100644
--- a/packages/taler-wallet-webextension/src/mui/colors/manipulation.ts
+++ b/packages/taler-wallet-webextension/src/mui/colors/manipulation.ts
@@ -57,7 +57,7 @@ export function hexToRgb(color: string): string {
   let colors = color.match(re);
 
   if (colors && colors[0].length === 1) {
-    colors = colors.map((n) => n + n);
+    colors = colors.map((n) => n + n) as RegExpMatchArray;
   }
 
   return colors
diff --git a/packages/taler-wallet-webextension/src/platform/api.ts 
b/packages/taler-wallet-webextension/src/platform/api.ts
index cd09f6438..40993477b 100644
--- a/packages/taler-wallet-webextension/src/platform/api.ts
+++ b/packages/taler-wallet-webextension/src/platform/api.ts
@@ -146,9 +146,9 @@ export interface BackgroundPlatformAPI {
    */
   getPermissionsApi(): CrossBrowserPermissionsApi;
   /**
- * Used by the wallet backend to send notification about new information
- * @param message
- */
+   * Used by the wallet backend to send notification about new information
+   * @param message
+   */
   sendMessageToAllChannels(message: MessageFromBackend): void;
 
   /**
@@ -196,7 +196,6 @@ export interface ForegroundPlatformAPI {
    */
   openWalletURIFromPopup(talerUri: string): void;
 
-
   /**
    * Popup API
    *
@@ -248,5 +247,4 @@ export interface ForegroundPlatformAPI {
   listenToWalletBackground(
     listener: (message: MessageFromBackend) => void,
   ): () => void;
-
 }
diff --git a/packages/taler-wallet-webextension/src/platform/chrome.ts 
b/packages/taler-wallet-webextension/src/platform/chrome.ts
index e5efdec4e..fc51a65fb 100644
--- a/packages/taler-wallet-webextension/src/platform/chrome.ts
+++ b/packages/taler-wallet-webextension/src/platform/chrome.ts
@@ -14,17 +14,17 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import {
-  classifyTalerUri, Logger,
-  TalerUriType
-} from "@gnu-taler/taler-util";
+import { classifyTalerUri, Logger, TalerUriType } from "@gnu-taler/taler-util";
 import { WalletOperations } from "@gnu-taler/taler-wallet-core";
 import { BackgroundOperations } from "../wxApi.js";
 import {
-  BackgroundPlatformAPI, CrossBrowserPermissionsApi, ForegroundPlatformAPI, 
MessageFromBackend,
+  BackgroundPlatformAPI,
+  CrossBrowserPermissionsApi,
+  ForegroundPlatformAPI,
+  MessageFromBackend,
   MessageFromFrontend,
   MessageResponse,
-  Permissions
+  Permissions,
 } from "./api.js";
 
 const api: BackgroundPlatformAPI & ForegroundPlatformAPI = {
@@ -306,13 +306,12 @@ function openWalletPageFromPopup(page: string): void {
   });
 }
 
-
 let nextMessageIndex = 0;
 
 /**
  * To be used by the foreground
- * @param message 
- * @returns 
+ * @param message
+ * @returns
  */
 async function sendMessageToBackground<
   Op extends WalletOperations | BackgroundOperations,
@@ -321,13 +320,13 @@ async function sendMessageToBackground<
 
   return new Promise<any>((resolve, reject) => {
     logger.trace("send operation to the wallet background", message);
-    let timedout = false
+    let timedout = false;
     setTimeout(() => {
-      timedout = true
-      reject("timedout")
+      timedout = true;
+      reject("timedout");
     }, 2000);
     chrome.runtime.sendMessage(messageWithId, (backgroundResponse) => {
-      if (timedout) return false
+      if (timedout) return false;
       if (chrome.runtime.lastError) {
         reject(chrome.runtime.lastError.message);
       } else {
@@ -358,7 +357,6 @@ function listenToWalletBackground(listener: (m: any) => 
void): () => void {
 
 const allPorts: chrome.runtime.Port[] = [];
 
-
 function sendMessageToAllChannels(message: MessageFromBackend): void {
   for (const notif of allPorts) {
     // const message: MessageFromBackend = { type: msg.type };
@@ -578,26 +576,26 @@ function setAlertedIcon(): void {
 
 interface OffscreenCanvasRenderingContext2D
   extends CanvasState,
-  CanvasTransform,
-  CanvasCompositing,
-  CanvasImageSmoothing,
-  CanvasFillStrokeStyles,
-  CanvasShadowStyles,
-  CanvasFilters,
-  CanvasRect,
-  CanvasDrawPath,
-  CanvasUserInterface,
-  CanvasText,
-  CanvasDrawImage,
-  CanvasImageData,
-  CanvasPathDrawingStyles,
-  CanvasTextDrawingStyles,
-  CanvasPath {
+    CanvasTransform,
+    CanvasCompositing,
+    CanvasImageSmoothing,
+    CanvasFillStrokeStyles,
+    CanvasShadowStyles,
+    CanvasFilters,
+    CanvasRect,
+    CanvasDrawPath,
+    CanvasUserInterface,
+    CanvasText,
+    CanvasDrawImage,
+    CanvasImageData,
+    CanvasPathDrawingStyles,
+    CanvasTextDrawingStyles,
+    CanvasPath {
   readonly canvas: OffscreenCanvas;
 }
 declare const OffscreenCanvasRenderingContext2D: {
   prototype: OffscreenCanvasRenderingContext2D;
-  new(): OffscreenCanvasRenderingContext2D;
+  new (): OffscreenCanvasRenderingContext2D;
 };
 
 interface OffscreenCanvas extends EventTarget {
@@ -610,7 +608,7 @@ interface OffscreenCanvas extends EventTarget {
 }
 declare const OffscreenCanvas: {
   prototype: OffscreenCanvas;
-  new(width: number, height: number): OffscreenCanvas;
+  new (width: number, height: number): OffscreenCanvas;
 };
 
 function createCanvas(size: number): OffscreenCanvas {
diff --git a/packages/taler-wallet-webextension/src/platform/firefox.ts 
b/packages/taler-wallet-webextension/src/platform/firefox.ts
index a36859a0b..7f6980be7 100644
--- a/packages/taler-wallet-webextension/src/platform/firefox.ts
+++ b/packages/taler-wallet-webextension/src/platform/firefox.ts
@@ -14,7 +14,12 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { BackgroundPlatformAPI, CrossBrowserPermissionsApi, 
ForegroundPlatformAPI, Permissions } from "./api.js";
+import {
+  BackgroundPlatformAPI,
+  CrossBrowserPermissionsApi,
+  ForegroundPlatformAPI,
+  Permissions,
+} from "./api.js";
 import chromePlatform, {
   containsHostPermissions as chromeHostContains,
   removeHostPermissions as chromeHostRemove,
diff --git a/packages/taler-wallet-webextension/src/popup/BalancePage.tsx 
b/packages/taler-wallet-webextension/src/popup/BalancePage.tsx
index 8786b2ff7..96f0f6dd9 100644
--- a/packages/taler-wallet-webextension/src/popup/BalancePage.tsx
+++ b/packages/taler-wallet-webextension/src/popup/BalancePage.tsx
@@ -19,12 +19,13 @@ import { WalletApiOperation } from 
"@gnu-taler/taler-wallet-core";
 import { Fragment, h, VNode } from "preact";
 import { useEffect, useState } from "preact/hooks";
 import { BalanceTable } from "../components/BalanceTable.js";
+import { ErrorAlertView } from "../components/CurrentAlerts.js";
 import { Loading } from "../components/Loading.js";
-import { LoadingError } from "../components/LoadingError.js";
 import { MultiActionButton } from "../components/MultiActionButton.js";
+import { alertFromError, ErrorAlert } from "../context/alert.js";
 import { useBackendContext } from "../context/backend.js";
 import { useTranslationContext } from "../context/translation.js";
-import { HookError, useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
+import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
 import { Button } from "../mui/Button.js";
 import { ButtonHandler } from "../mui/handlers.js";
 import { compose, StateViewMap } from "../utils/index.js";
@@ -47,7 +48,7 @@ export namespace State {
 
   export interface Error {
     status: "error";
-    error: HookError;
+    error: ErrorAlert;
   }
 
   export interface Action {
@@ -73,6 +74,7 @@ function useComponentState({
   goToWalletManualWithdraw,
 }: Props): State {
   const api = useBackendContext();
+  const { i18n } = useTranslationContext();
   const [addingAction, setAddingAction] = useState(false);
   const state = useAsyncAsHook(() =>
     api.wallet.call(WalletApiOperation.GetBalances, {}),
@@ -94,7 +96,7 @@ function useComponentState({
   if (state.hasError) {
     return {
       status: "error",
-      error: state,
+      error: alertFromError(i18n.str`Could not load the balance`, state),
     };
   }
   if (addingAction) {
@@ -123,7 +125,7 @@ function useComponentState({
 
 const viewMapping: StateViewMap<State> = {
   loading: Loading,
-  error: ErrorView,
+  error: ErrorAlertView,
   action: ActionView,
   balance: BalanceView,
 };
@@ -134,16 +136,6 @@ export const BalancePage = compose(
   viewMapping,
 );
 
-function ErrorView({ error }: State.Error): VNode {
-  const { i18n } = useTranslationContext();
-  return (
-    <LoadingError
-      title={<i18n.Translate>Could not load balance page</i18n.Translate>}
-      error={error}
-    />
-  );
-}
-
 function ActionView({ cancel }: State.Action): VNode {
   return <AddNewActionView onCancel={cancel.onClick!} />;
 }
@@ -179,7 +171,7 @@ export function BalanceView(state: State.Balances): VNode {
         </Button>
         {currencyWithNonZeroAmount.length > 0 && (
           <MultiActionButton
-            label={(s) => <i18n.Translate>Send {s}</i18n.Translate>}
+            label={(s) => i18n.str`Send ${s}`}
             actions={currencyWithNonZeroAmount}
             onClick={(c) => state.goToWalletDeposit(c)}
           />
diff --git a/packages/taler-wallet-webextension/src/popup/NoBalanceHelp.tsx 
b/packages/taler-wallet-webextension/src/popup/NoBalanceHelp.tsx
index 7d2e15726..5eb31ba46 100644
--- a/packages/taler-wallet-webextension/src/popup/NoBalanceHelp.tsx
+++ b/packages/taler-wallet-webextension/src/popup/NoBalanceHelp.tsx
@@ -33,7 +33,7 @@ export function NoBalanceHelp({
   const { i18n } = useTranslationContext();
   return (
     <Paper class={margin}>
-      <Alert title="Your wallet is empty." severity="info">
+      <Alert title={i18n.str`Your wallet is empty.`} severity="info">
         <Button
           fullWidth
           color="info"
diff --git a/packages/taler-wallet-webextension/src/svg/progress.svg 
b/packages/taler-wallet-webextension/src/svg/progress.svg
new file mode 100644
index 000000000..c7284a545
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/svg/progress.svg
@@ -0,0 +1,12 @@
+<svg xmlns="http://www.w3.org/2000/svg"; 
xmlns:xlink="http://www.w3.org/1999/xlink"; 
style="margin:auto;background:#fff;display:block;" viewBox="0 0 100 100" 
preserveAspectRatio="xMidYMid">
+  <defs>
+    <clipPath id="progress-cp" x="0" y="0" width="100" height="100">
+      <rect x="0" y="0" width="0" height="100">
+        <animate attributeName="width" repeatCount="indefinite" dur="2s" 
values="0;100;100" keyTimes="0;0.5;1"></animate>
+        <animate attributeName="x" repeatCount="indefinite" dur="2s" 
values="0;0;100" keyTimes="0;0.5;1"></animate>
+      </rect>
+    </clipPath>
+  </defs>
+  <path fill="none" stroke="darkgrey" stroke-width="1.04" 
d="M10.000000000000004 44.019999999999996L89.99999999999999 
44.019999999999996A5.98 5.98 0 0 1 95.97999999999999 50L95.97999999999999 
50A5.98 5.98 0 0 1 89.99999999999999 55.980000000000004L10.000000000000004 
55.980000000000004A5.98 5.98 0 0 1 4.020000000000003 50L4.020000000000003 
50A5.98 5.98 0 0 1 10.000000000000004 44.019999999999996 Z"></path>
+  <path fill="#0042b2" clip-path="url(#progress-cp)" d="M10.000000000000004 
45.54L90 45.54A4.460000000000001 4.460000000000001 0 0 1 94.46 50L94.46 
50A4.460000000000001 4.460000000000001 0 0 1 90 54.46L10.000000000000004 
54.46A4.460000000000001 4.460000000000001 0 0 1 5.540000000000003 
50L5.540000000000003 50A4.460000000000001 4.460000000000001 0 0 1 
10.000000000000004 45.54 Z"></path>
+</svg>
\ No newline at end of file
diff --git a/packages/taler-wallet-webextension/src/test-utils.ts 
b/packages/taler-wallet-webextension/src/test-utils.ts
index 379513782..7e7ddd88d 100644
--- a/packages/taler-wallet-webextension/src/test-utils.ts
+++ b/packages/taler-wallet-webextension/src/test-utils.ts
@@ -32,6 +32,7 @@ import {
 } from "preact";
 import { render as renderToString } from "preact-render-to-string";
 import { BackendProvider } from "./context/backend.js";
+import { TranslationProvider } from "./context/translation.js";
 import { BackgroundApiClient, wxApi } from "./wxApi.js";
 
 // When doing tests we want the requestAnimationFrame to be as fast as 
possible.
@@ -359,10 +360,12 @@ export function createWalletApiMock(): {
   };
 
   function TestingContext({
-    children,
+    children: _cs,
   }: {
     children: ComponentChildren;
   }): VNode {
+    let children = _cs;
+    children = create(TranslationProvider, { children }, children);
     return create(
       BackendProvider,
       {
diff --git 
a/packages/taler-wallet-webextension/src/wallet/AddBackupProvider/index.ts 
b/packages/taler-wallet-webextension/src/wallet/AddBackupProvider/index.ts
index 10fcd84ce..4ec4c0ffe 100644
--- a/packages/taler-wallet-webextension/src/wallet/AddBackupProvider/index.ts
+++ b/packages/taler-wallet-webextension/src/wallet/AddBackupProvider/index.ts
@@ -16,8 +16,9 @@
 
 import { TalerErrorDetail } from "@gnu-taler/taler-util";
 import { SyncTermsOfServiceResponse } from "@gnu-taler/taler-wallet-core";
+import { ErrorAlertView } from "../../components/CurrentAlerts.js";
 import { Loading } from "../../components/Loading.js";
-import { HookError } from "../../hooks/useAsyncAsHook.js";
+import { ErrorAlert } from "../../context/alert.js";
 import {
   ButtonHandler,
   TextFieldHandler,
@@ -25,11 +26,7 @@ import {
 } from "../../mui/handlers.js";
 import { compose, StateViewMap } from "../../utils/index.js";
 import { useComponentState } from "./state.js";
-import {
-  ConfirmProviderView,
-  LoadingUriView,
-  SelectProviderView,
-} from "./views.js";
+import { ConfirmProviderView, SelectProviderView } from "./views.js";
 
 export interface Props {
   onBack: () => Promise<void>;
@@ -50,8 +47,8 @@ export namespace State {
   }
 
   export interface LoadingUriError {
-    status: "loading-error";
-    error: HookError;
+    status: "error";
+    error: ErrorAlert;
   }
 
   export interface ConfirmProvider {
@@ -77,7 +74,7 @@ export namespace State {
 
 const viewMapping: StateViewMap<State> = {
   loading: Loading,
-  "loading-error": LoadingUriView,
+  error: ErrorAlertView,
   "select-provider": SelectProviderView,
   "confirm-provider": ConfirmProviderView,
 };
diff --git 
a/packages/taler-wallet-webextension/src/wallet/AddBackupProvider/views.tsx 
b/packages/taler-wallet-webextension/src/wallet/AddBackupProvider/views.tsx
index b633a595f..c3afc0d33 100644
--- a/packages/taler-wallet-webextension/src/wallet/AddBackupProvider/views.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/AddBackupProvider/views.tsx
@@ -17,12 +17,10 @@
 import { Amounts } from "@gnu-taler/taler-util";
 import { Fragment, h, VNode } from "preact";
 import { Checkbox } from "../../components/Checkbox.js";
-import { LoadingError } from "../../components/LoadingError.js";
 import {
   LightText,
   SmallLightText,
   SubTitle,
-  TermsOfService,
   Title,
 } from "../../components/styled/index.js";
 import { useTranslationContext } from "../../context/translation.js";
@@ -30,17 +28,6 @@ import { Button } from "../../mui/Button.js";
 import { TextField } from "../../mui/TextField.js";
 import { State } from "./index.js";
 
-export function LoadingUriView({ error }: State.LoadingUriError): VNode {
-  const { i18n } = useTranslationContext();
-
-  return (
-    <LoadingError
-      title={<i18n.Translate>Could not load</i18n.Translate>}
-      error={error}
-    />
-  );
-}
-
 export function ConfirmProviderView({
   url,
   provider,
@@ -88,9 +75,8 @@ export function ConfirmProviderView({
             of service
           </i18n.Translate>
         </p>
-        {/* replace with <TermsOfService /> */}
         <Checkbox
-          label={<i18n.Translate>Accept terms of service</i18n.Translate>}
+          label={i18n.str`Accept terms of service`}
           name="terms"
           onToggle={tos.button.onClick}
           enabled={tos.value}
diff --git a/packages/taler-wallet-webextension/src/wallet/Application.tsx 
b/packages/taler-wallet-webextension/src/wallet/Application.tsx
index 372db847c..46fe02225 100644
--- a/packages/taler-wallet-webextension/src/wallet/Application.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Application.tsx
@@ -25,13 +25,17 @@ import { createHashHistory } from "history";
 import { ComponentChildren, Fragment, h, VNode } from "preact";
 import Router, { route, Route } from "preact-router";
 import { useEffect } from "preact/hooks";
+import { CurrentAlerts } from "../components/CurrentAlerts.js";
 import { LogoHeader } from "../components/LogoHeader.js";
 import PendingTransactions from "../components/PendingTransactions.js";
 import {
+  Link,
+  LinkPrimary,
   SubTitle,
   WalletAction,
   WalletBox,
 } from "../components/styled/index.js";
+import { AlertProvider } from "../context/alert.js";
 import { DevContextProvider } from "../context/devContext.js";
 import { IoCProviderForRuntime } from "../context/iocContext.js";
 import {
@@ -66,6 +70,7 @@ import { QrReaderPage } from "./QrReader.js";
 import { SettingsPage } from "./Settings.js";
 import { TransactionPage } from "./Transaction.js";
 import { WelcomePage } from "./Welcome.js";
+import CloseIcon from "../svg/close_24px.svg";
 
 export function Application(): VNode {
   const { i18n } = useTranslationContext();
@@ -495,15 +500,6 @@ function matchesRoute(url: string, route: string): boolean 
{
   return !result ? false : true;
 }
 
-function shouldShowPendingOperations(url: string): boolean {
-  return [
-    Pages.balanceHistory.pattern,
-    Pages.dev,
-    Pages.settings,
-    Pages.backup,
-  ].some((p) => matchesRoute(url, p));
-}
-
 function CallToActionTemplate({
   title,
   children,
@@ -511,11 +507,35 @@ function CallToActionTemplate({
   title: TranslatedString;
   children: ComponentChildren;
 }): VNode {
+  const { i18n } = useTranslationContext();
   return (
     <WalletAction>
       <LogoHeader />
+      <section style={{ display: "flex", justifyContent: "right", margin: 0 }}>
+        <LinkPrimary href={Pages.balance}>
+          <div
+            style={{
+              height: 24,
+              width: 24,
+              marginLeft: 4,
+              marginRight: 4,
+              border: "1px solid black",
+              borderRadius: 12,
+            }}
+            dangerouslySetInnerHTML={{ __html: CloseIcon }}
+          />
+        </LinkPrimary>
+      </section>
       <SubTitle>{title}</SubTitle>
-      {children}
+      <AlertProvider>
+        <CurrentAlerts />
+        {children}
+      </AlertProvider>
+      <section style={{ display: "flex", justifyContent: "right" }}>
+        <LinkPrimary href={Pages.balance}>
+          <i18n.Translate>Return to wallet</i18n.Translate>
+        </LinkPrimary>
+      </section>
     </WalletAction>
   );
 }
@@ -536,7 +556,10 @@ function WalletTemplate({
       {goToTransaction ? (
         <PendingTransactions goToTransaction={goToTransaction} />
       ) : undefined}
-      <WalletBox>{children}</WalletBox>
+      <CurrentAlerts />
+      <WalletBox>
+        <AlertProvider>{children}</AlertProvider>
+      </WalletBox>
     </Fragment>
   );
 }
diff --git a/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx 
b/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx
index 6e987f965..48c9c9cb1 100644
--- a/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx
@@ -29,8 +29,8 @@ import {
 } from "date-fns";
 import { Fragment, h, VNode } from "preact";
 import { useEffect, useState } from "preact/hooks";
+import { AlertView } from "../components/CurrentAlerts.js";
 import { Loading } from "../components/Loading.js";
-import { LoadingError } from "../components/LoadingError.js";
 import { QR } from "../components/QR.js";
 import {
   BoldLight,
@@ -42,6 +42,7 @@ import {
   SmallText,
   WarningBox,
 } from "../components/styled/index.js";
+import { alertFromError } from "../context/alert.js";
 import { useBackendContext } from "../context/backend.js";
 import { useTranslationContext } from "../context/translation.js";
 import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
@@ -117,9 +118,11 @@ export function BackupPage({ onAddProvider }: Props): 
VNode {
   }
   if (status.hasError) {
     return (
-      <LoadingError
-        title={<i18n.Translate>Could not load backup 
providers</i18n.Translate>}
-        error={status}
+      <AlertView
+        alert={alertFromError(
+          i18n.str`Could not load backup providers`,
+          status,
+        )}
       />
     );
   }
@@ -219,11 +222,9 @@ export function BackupView({
           </div>
           <div>
             <Button variant="contained" onClick={onSyncAll}>
-              {providers.length > 1 ? (
-                <i18n.Translate>Sync all backups</i18n.Translate>
-              ) : (
-                <i18n.Translate>Sync now</i18n.Translate>
-              )}
+              {providers.length > 1
+                ? i18n.str`Sync all backups`
+                : i18n.str`Sync now`}
             </Button>
             <Button variant="contained" color="success" 
onClick={onAddProvider}>
               <i18n.Translate>Add provider</i18n.Translate>
diff --git a/packages/taler-wallet-webextension/src/wallet/DepositPage/index.ts 
b/packages/taler-wallet-webextension/src/wallet/DepositPage/index.ts
index 6ffbccc27..6de406400 100644
--- a/packages/taler-wallet-webextension/src/wallet/DepositPage/index.ts
+++ b/packages/taler-wallet-webextension/src/wallet/DepositPage/index.ts
@@ -15,8 +15,9 @@
  */
 
 import { AmountJson, PaytoUri } from "@gnu-taler/taler-util";
+import { ErrorAlertView } from "../../components/CurrentAlerts.js";
 import { Loading } from "../../components/Loading.js";
-import { HookError } from "../../hooks/useAsyncAsHook.js";
+import { ErrorAlert } from "../../context/alert.js";
 import {
   AmountFieldHandler,
   ButtonHandler,
@@ -27,7 +28,6 @@ import { ManageAccountPage } from "../ManageAccount/index.js";
 import { useComponentState } from "./state.js";
 import {
   AmountOrCurrencyErrorView,
-  LoadingErrorView,
   NoAccountToDepositView,
   NoEnoughBalanceView,
   ReadyView,
@@ -56,8 +56,8 @@ export namespace State {
   }
 
   export interface LoadingUriError {
-    status: "loading-error";
-    error: HookError;
+    status: "error";
+    error: ErrorAlert;
   }
 
   export interface AddingAccount {
@@ -107,7 +107,7 @@ export namespace State {
 
 const viewMapping: StateViewMap<State> = {
   loading: Loading,
-  "loading-error": LoadingErrorView,
+  error: ErrorAlertView,
   "amount-or-currency-error": AmountOrCurrencyErrorView,
   "no-enough-balance": NoEnoughBalanceView,
   "no-accounts": NoAccountToDepositView,
diff --git a/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts 
b/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts
index 02e85a1c7..b597c77be 100644
--- a/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts
+++ b/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts
@@ -25,7 +25,9 @@ import {
 } from "@gnu-taler/taler-util";
 import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
 import { useState } from "preact/hooks";
+import { alertFromError } from "../../context/alert.js";
 import { useBackendContext } from "../../context/backend.js";
+import { useTranslationContext } from "../../context/translation.js";
 import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
 import { Props, State } from "./index.js";
 
@@ -36,6 +38,7 @@ export function useComponentState({
   onSuccess,
 }: Props): State {
   const api = useBackendContext();
+  const { i18n } = useTranslationContext();
   const parsed = amountStr === undefined ? undefined : 
Amounts.parse(amountStr);
   const currency = parsed !== undefined ? parsed.currency : currencyStr;
 
@@ -82,8 +85,8 @@ export function useComponentState({
   }
   if (hook.hasError) {
     return {
-      status: "loading-error",
-      error: hook,
+      status: "error",
+      error: alertFromError(i18n.str`Could not load balance information`, 
hook),
     };
   }
   const { accounts, balances } = hook.response;
diff --git 
a/packages/taler-wallet-webextension/src/wallet/DepositPage/views.tsx 
b/packages/taler-wallet-webextension/src/wallet/DepositPage/views.tsx
index 6a28f31e1..0d827db43 100644
--- a/packages/taler-wallet-webextension/src/wallet/DepositPage/views.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/DepositPage/views.tsx
@@ -18,31 +18,13 @@ import { Amounts, PaytoUri } from "@gnu-taler/taler-util";
 import { Fragment, h, VNode } from "preact";
 import { AmountField } from "../../components/AmountField.js";
 import { ErrorMessage } from "../../components/ErrorMessage.js";
-import { LoadingError } from "../../components/LoadingError.js";
 import { SelectList } from "../../components/SelectList.js";
-import {
-  ErrorText,
-  Input,
-  InputWithLabel,
-  SubTitle,
-  WarningBox,
-} from "../../components/styled/index.js";
+import { Input, SubTitle, WarningBox } from "../../components/styled/index.js";
 import { useTranslationContext } from "../../context/translation.js";
 import { Button } from "../../mui/Button.js";
 import { Grid } from "../../mui/Grid.js";
 import { State } from "./index.js";
 
-export function LoadingErrorView({ error }: State.LoadingUriError): VNode {
-  const { i18n } = useTranslationContext();
-
-  return (
-    <LoadingError
-      title={<i18n.Translate>Could not load deposit balance</i18n.Translate>}
-      error={error}
-    />
-  );
-}
-
 export function AmountOrCurrencyErrorView(
   p: State.AmountOrCurrencyError,
 ): VNode {
@@ -50,11 +32,7 @@ export function AmountOrCurrencyErrorView(
 
   return (
     <ErrorMessage
-      title={
-        <i18n.Translate>
-          A currency or an amount should be indicated
-        </i18n.Translate>
-      }
+      title={i18n.str`A currency or an amount should be indicated`}
     />
   );
 }
@@ -66,11 +44,7 @@ export function NoEnoughBalanceView({
 
   return (
     <ErrorMessage
-      title={
-        <i18n.Translate>
-          There is no enough balance to make a deposit for currency {currency}
-        </i18n.Translate>
-      }
+      title={i18n.str`There is no enough balance to make a deposit for 
currency ${currency}`}
     />
   );
 }
@@ -150,7 +124,7 @@ export function ReadyView(state: State.Ready): VNode {
         >
           <Input>
             <SelectList
-              label={<i18n.Translate>Select account</i18n.Translate>}
+              label={i18n.str`Select account`}
               list={state.account.list}
               name="account"
               value={state.account.value}
@@ -171,14 +145,11 @@ export function ReadyView(state: State.Ready): VNode {
         </p>
         <Grid container spacing={2} columns={1}>
           <Grid item xs={1}>
-            <AmountField
-              label={<i18n.Translate>Amount</i18n.Translate>}
-              handler={state.amount}
-            />
+            <AmountField label={i18n.str`Amount`} handler={state.amount} />
           </Grid>
           <Grid item xs={1}>
             <AmountField
-              label={<i18n.Translate>Deposit fee</i18n.Translate>}
+              label={i18n.str`Deposit fee`}
               handler={{
                 value: state.totalFee,
               }}
@@ -186,7 +157,7 @@ export function ReadyView(state: State.Ready): VNode {
           </Grid>
           <Grid item xs={1}>
             <AmountField
-              label={<i18n.Translate>Total deposit</i18n.Translate>}
+              label={i18n.str`Total deposit`}
               handler={{
                 value: state.totalToDeposit,
               }}
diff --git 
a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/index.ts 
b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/index.ts
index f1e766a18..bd6b32e78 100644
--- 
a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/index.ts
+++ 
b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/index.ts
@@ -14,12 +14,13 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
+import { ErrorAlertView } from "../../components/CurrentAlerts.js";
 import { Loading } from "../../components/Loading.js";
-import { HookError } from "../../hooks/useAsyncAsHook.js";
+import { ErrorAlert } from "../../context/alert.js";
 import { AmountFieldHandler, ButtonHandler } from "../../mui/handlers.js";
 import { compose, StateViewMap } from "../../utils/index.js";
 import { useComponentState } from "./state.js";
-import { LoadingUriView, ReadyView, SelectCurrencyView } from "./views.js";
+import { ReadyView, SelectCurrencyView } from "./views.js";
 
 export type Props = PropsGet | PropsSend;
 
@@ -49,8 +50,8 @@ export namespace State {
   }
 
   export interface LoadingUriError {
-    status: "loading-error";
-    error: HookError;
+    status: "error";
+    error: ErrorAlert;
   }
 
   export interface SelectCurrency {
@@ -80,7 +81,7 @@ export type Contact = {
 
 const viewMapping: StateViewMap<State> = {
   loading: Loading,
-  "loading-error": LoadingUriView,
+  error: ErrorAlertView,
   "select-currency": SelectCurrencyView,
   ready: ReadyView,
 };
diff --git 
a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/state.ts 
b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/state.ts
index dd711f406..1fe324c5a 100644
--- 
a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/state.ts
+++ 
b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/state.ts
@@ -17,7 +17,9 @@
 import { Amounts } from "@gnu-taler/taler-util";
 import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
 import { useState } from "preact/hooks";
+import { alertFromError } from "../../context/alert.js";
 import { useBackendContext } from "../../context/backend.js";
+import { useTranslationContext } from "../../context/translation.js";
 import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
 import { assertUnreachable, RecursiveState } from "../../utils/index.js";
 import { Contact, Props, State } from "./index.js";
@@ -58,6 +60,8 @@ export function useComponentState(props: Props): 
RecursiveState<State> {
 
   if (!amount) {
     return () => {
+      // eslint-disable-next-line react-hooks/rules-of-hooks
+      const { i18n } = useTranslationContext();
       // eslint-disable-next-line react-hooks/rules-of-hooks
       const hook = useAsyncAsHook(() =>
         api.wallet.call(WalletApiOperation.ListExchanges, {}),
@@ -71,8 +75,8 @@ export function useComponentState(props: Props): 
RecursiveState<State> {
       }
       if (hook.hasError) {
         return {
-          status: "loading-error",
-          error: hook,
+          status: "error",
+          error: alertFromError(i18n.str`Could not load exchanges`, hook),
         };
       }
       const currencies: Record<string, string> = {};
diff --git 
a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/views.tsx 
b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/views.tsx
index a9a4b2e41..8a7a1fa97 100644
--- 
a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/views.tsx
+++ 
b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/views.tsx
@@ -16,7 +16,7 @@
 
 import { styled } from "@linaria/react";
 import { Fragment, h, VNode } from "preact";
-import { LoadingError } from "../../components/LoadingError.js";
+import { AmountField } from "../../components/AmountField.js";
 import { SelectList } from "../../components/SelectList.js";
 import {
   Input,
@@ -25,24 +25,14 @@ import {
   SvgIcon,
 } from "../../components/styled/index.js";
 import { useTranslationContext } from "../../context/translation.js";
-import { Pages } from "../../NavigationBar.js";
-import { Contact, State } from "./index.js";
-import arrowIcon from "../../svg/chevron-down.svg";
-import { AmountField } from "../../components/AmountField.js";
+import { Button } from "../../mui/Button.js";
 import { Grid } from "../../mui/Grid.js";
 import { Paper } from "../../mui/Paper.js";
-import { Button } from "../../mui/Button.js";
+import { Pages } from "../../NavigationBar.js";
+import arrowIcon from "../../svg/chevron-down.svg";
+import bankIcon from "../../svg/ri-bank-line.svg";
 import { assertUnreachable } from "../../utils/index.js";
-
-export function LoadingUriView({ error }: State.LoadingUriError): VNode {
-  const { i18n } = useTranslationContext();
-  return (
-    <LoadingError
-      title={<i18n.Translate>Could not load</i18n.Translate>}
-      error={error}
-    />
-  );
-}
+import { Contact, State } from "./index.js";
 
 export function SelectCurrencyView({
   currencies,
@@ -61,7 +51,7 @@ export function SelectCurrencyView({
       <p>
         <Input>
           <SelectList
-            label={<i18n.Translate>Known currencies</i18n.Translate>}
+            label={i18n.str`Known currencies`}
             list={currencies}
             name="lang"
             value={""}
@@ -214,7 +204,7 @@ export function ReadyGetView({
       </h1>
       <Grid container columns={2} justifyContent="space-between">
         <AmountField
-          label={<i18n.Translate>Amount</i18n.Translate>}
+          label={i18n.str`Amount`}
           required
           handler={amountHandler}
         />
@@ -304,7 +294,7 @@ export function ReadySendView({
 
       <div>
         <AmountField
-          label={<i18n.Translate>Amount</i18n.Translate>}
+          label={i18n.str`Amount`}
           required
           handler={amountHandler}
         />
@@ -377,7 +367,6 @@ export function ReadySendView({
     </Container>
   );
 }
-import bankIcon from "../../svg/ri-bank-line.svg";
 
 function RowExample({
   info,
diff --git 
a/packages/taler-wallet-webextension/src/wallet/EmptyComponentExample/index.ts 
b/packages/taler-wallet-webextension/src/wallet/EmptyComponentExample/index.ts
index 95badb218..afbaf1945 100644
--- 
a/packages/taler-wallet-webextension/src/wallet/EmptyComponentExample/index.ts
+++ 
b/packages/taler-wallet-webextension/src/wallet/EmptyComponentExample/index.ts
@@ -14,11 +14,12 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
+import { ErrorAlertView } from "../../components/CurrentAlerts.js";
 import { Loading } from "../../components/Loading.js";
-import { HookError } from "../../hooks/useAsyncAsHook.js";
+import { ErrorAlert } from "../../context/alert.js";
 import { compose, StateViewMap } from "../../utils/index.js";
 import { useComponentState } from "./state.js";
-import { LoadingUriView, ReadyView } from "./views.js";
+import { ReadyView } from "./views.js";
 
 export interface Props {
   p: string;
@@ -33,8 +34,8 @@ export namespace State {
   }
 
   export interface LoadingUriError {
-    status: "loading-error";
-    error: HookError;
+    status: "error";
+    error: ErrorAlert;
   }
 
   export interface BaseInfo {
@@ -48,7 +49,7 @@ export namespace State {
 
 const viewMapping: StateViewMap<State> = {
   loading: Loading,
-  "loading-error": LoadingUriView,
+  error: ErrorAlertView,
   ready: ReadyView,
 };
 
diff --git 
a/packages/taler-wallet-webextension/src/wallet/EmptyComponentExample/views.tsx 
b/packages/taler-wallet-webextension/src/wallet/EmptyComponentExample/views.tsx
index 5784a7db5..dc8a42b84 100644
--- 
a/packages/taler-wallet-webextension/src/wallet/EmptyComponentExample/views.tsx
+++ 
b/packages/taler-wallet-webextension/src/wallet/EmptyComponentExample/views.tsx
@@ -15,21 +15,9 @@
  */
 
 import { h, VNode } from "preact";
-import { LoadingError } from "../../components/LoadingError.js";
 import { useTranslationContext } from "../../context/translation.js";
 import { State } from "./index.js";
 
-export function LoadingUriView({ error }: State.LoadingUriError): VNode {
-  const { i18n } = useTranslationContext();
-
-  return (
-    <LoadingError
-      title={<i18n.Translate>Could not load</i18n.Translate>}
-      error={error}
-    />
-  );
-}
-
 export function ReadyView({ error }: State.Ready): VNode {
   const { i18n } = useTranslationContext();
 
diff --git 
a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/index.ts 
b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/index.ts
index 10e44ce7d..299c236c4 100644
--- a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/index.ts
+++ b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/index.ts
@@ -20,7 +20,9 @@ import {
   ExchangeListItem,
   FeeDescriptionPair,
 } from "@gnu-taler/taler-util";
+import { ErrorAlertView } from "../../components/CurrentAlerts.js";
 import { Loading } from "../../components/Loading.js";
+import { ErrorAlert } from "../../context/alert.js";
 import { HookError } from "../../hooks/useAsyncAsHook.js";
 import { State as SelectExchangeState } from 
"../../hooks/useSelectedExchange.js";
 import { ButtonHandler, SelectFieldHandler } from "../../mui/handlers.js";
@@ -28,7 +30,6 @@ import { compose, StateViewMap } from "../../utils/index.js";
 import { useComponentState } from "./state.js";
 import {
   ComparingView,
-  ErrorLoadingView,
   NoExchangesView,
   PrivacyContentView,
   ReadyView,
@@ -58,8 +59,8 @@ export namespace State {
   }
 
   export interface LoadingUriError {
-    status: "error-loading";
-    error: HookError;
+    status: "error";
+    error: ErrorAlert;
   }
 
   export interface BaseInfo {
@@ -99,7 +100,7 @@ export namespace State {
 
 const viewMapping: StateViewMap<State> = {
   loading: Loading,
-  "error-loading": ErrorLoadingView,
+  error: ErrorAlertView,
   comparing: ComparingView,
   "no-exchange": NoExchangesView,
   "showing-tos": TosContentView,
diff --git 
a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts 
b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts
index 3c10febd9..cfb32cbbb 100644
--- a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts
+++ b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts
@@ -20,7 +20,9 @@ import {
   WalletApiOperation,
 } from "@gnu-taler/taler-wallet-core";
 import { useState } from "preact/hooks";
+import { alertFromError } from "../../context/alert.js";
 import { useBackendContext } from "../../context/backend.js";
+import { useTranslationContext } from "../../context/translation.js";
 import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
 import { Props, State } from "./index.js";
 
@@ -31,6 +33,7 @@ export function useComponentState({
   currentExchange,
 }: Props): State {
   const api = useBackendContext();
+  const { i18n } = useTranslationContext();
   const initialValue = exchanges.findIndex(
     (e) => e.exchangeBaseUrl === currentExchange,
   );
@@ -84,8 +87,11 @@ export function useComponentState({
   }
   if (hook.hasError) {
     return {
-      status: "error-loading",
-      error: hook,
+      status: "error",
+      error: alertFromError(
+        i18n.str`Could not load exchange details info`,
+        hook,
+      ),
     };
   }
 
diff --git 
a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/views.tsx 
b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/views.tsx
index 26ff2c0d3..d01ce7ca0 100644
--- a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/views.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/views.tsx
@@ -20,7 +20,6 @@ import { Fragment, h, VNode } from "preact";
 import { useState } from "preact/hooks";
 import { Amount } from "../../components/Amount.js";
 import { ErrorMessage } from "../../components/ErrorMessage.js";
-import { LoadingError } from "../../components/LoadingError.js";
 import { SelectList } from "../../components/SelectList.js";
 import { Input, SvgIcon } from "../../components/styled/index.js";
 import { TermsOfService } from "../../components/TermsOfService/index.js";
@@ -110,17 +109,6 @@ const Container = styled.div`
   }
 `;
 
-export function ErrorLoadingView({ error }: State.LoadingUriError): VNode {
-  const { i18n } = useTranslationContext();
-
-  return (
-    <LoadingError
-      title={<i18n.Translate>Could not load exchange fees</i18n.Translate>}
-      error={error}
-    />
-  );
-}
-
 export function PrivacyContentView({
   exchangeUrl,
   onClose,
@@ -156,19 +144,11 @@ export function NoExchangesView({
 }: SelectExchangeState.NoExchange): VNode {
   const { i18n } = useTranslationContext();
   if (!currency) {
-    return (
-      <ErrorMessage
-        title={<i18n.Translate>Could not find any exchange</i18n.Translate>}
-      />
-    );
+    return <ErrorMessage title={i18n.str`Could not find any exchange`} />;
   }
   return (
     <ErrorMessage
-      title={
-        <i18n.Translate>
-          Could not find any exchange for the currency {currency}
-        </i18n.Translate>
-      }
+      title={i18n.str`Could not find any exchange for the currency 
${currency}`}
     />
   );
 }
diff --git a/packages/taler-wallet-webextension/src/wallet/ExchangeSetUrl.tsx 
b/packages/taler-wallet-webextension/src/wallet/ExchangeSetUrl.tsx
index 8c31d8d95..404fc8bee 100644
--- a/packages/taler-wallet-webextension/src/wallet/ExchangeSetUrl.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ExchangeSetUrl.tsx
@@ -140,15 +140,13 @@ export function ExchangeSetUrlPage({
         )}
         {error && (
           <ErrorMessage
-            title={
-              <i18n.Translate>Unable to verify this exchange</i18n.Translate>
-            }
+            title={i18n.str`Unable to verify this exchange`}
             description={error}
           />
         )}
         {confirmationError && (
           <ErrorMessage
-            title={<i18n.Translate>Unable to add this 
exchange</i18n.Translate>}
+            title={i18n.str`Unable to add this exchange`}
             description={confirmationError}
           />
         )}
diff --git a/packages/taler-wallet-webextension/src/wallet/History.tsx 
b/packages/taler-wallet-webextension/src/wallet/History.tsx
index 50f634f52..143d3adbb 100644
--- a/packages/taler-wallet-webextension/src/wallet/History.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/History.tsx
@@ -23,8 +23,8 @@ import {
 import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
 import { Fragment, h, VNode } from "preact";
 import { useEffect, useState } from "preact/hooks";
+import { AlertView } from "../components/CurrentAlerts.js";
 import { Loading } from "../components/Loading.js";
-import { LoadingError } from "../components/LoadingError.js";
 import {
   CenteredBoldText,
   CenteredText,
@@ -33,6 +33,7 @@ import {
 } from "../components/styled/index.js";
 import { Time } from "../components/Time.js";
 import { TransactionItem } from "../components/TransactionItem.js";
+import { alertFromError } from "../context/alert.js";
 import { useBackendContext } from "../context/backend.js";
 import { useTranslationContext } from "../context/translation.js";
 import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
@@ -71,13 +72,11 @@ export function HistoryPage({
 
   if (state.hasError) {
     return (
-      <LoadingError
-        title={
-          <i18n.Translate>
-            Could not load the list of transactions
-          </i18n.Translate>
-        }
-        error={state}
+      <AlertView
+        alert={alertFromError(
+          i18n.str`Could not load the list of transactions`,
+          state,
+        )}
       />
     );
   }
diff --git 
a/packages/taler-wallet-webextension/src/wallet/ManageAccount/index.ts 
b/packages/taler-wallet-webextension/src/wallet/ManageAccount/index.ts
index 8541821b7..3a00d48ce 100644
--- a/packages/taler-wallet-webextension/src/wallet/ManageAccount/index.ts
+++ b/packages/taler-wallet-webextension/src/wallet/ManageAccount/index.ts
@@ -15,8 +15,9 @@
  */
 
 import { KnownBankAccountsInfo } from "@gnu-taler/taler-util";
+import { ErrorAlertView } from "../../components/CurrentAlerts.js";
 import { Loading } from "../../components/Loading.js";
-import { HookError } from "../../hooks/useAsyncAsHook.js";
+import { ErrorAlert } from "../../context/alert.js";
 import {
   ButtonHandler,
   SelectFieldHandler,
@@ -24,7 +25,7 @@ import {
 } from "../../mui/handlers.js";
 import { compose, StateViewMap } from "../../utils/index.js";
 import { useComponentState } from "./state.js";
-import { LoadingUriView, ReadyView } from "./views.js";
+import { ReadyView } from "./views.js";
 
 export interface Props {
   currency: string;
@@ -41,8 +42,8 @@ export namespace State {
   }
 
   export interface LoadingUriError {
-    status: "loading-error";
-    error: HookError;
+    status: "error";
+    error: ErrorAlert;
   }
 
   export interface BaseInfo {
@@ -68,7 +69,7 @@ export type AccountByType = {
 
 const viewMapping: StateViewMap<State> = {
   loading: Loading,
-  "loading-error": LoadingUriView,
+  error: ErrorAlertView,
   ready: ReadyView,
 };
 
diff --git 
a/packages/taler-wallet-webextension/src/wallet/ManageAccount/state.ts 
b/packages/taler-wallet-webextension/src/wallet/ManageAccount/state.ts
index 9690a5c79..176a8d100 100644
--- a/packages/taler-wallet-webextension/src/wallet/ManageAccount/state.ts
+++ b/packages/taler-wallet-webextension/src/wallet/ManageAccount/state.ts
@@ -21,7 +21,9 @@ import {
 } from "@gnu-taler/taler-util";
 import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
 import { useState } from "preact/hooks";
+import { alertFromError } from "../../context/alert.js";
 import { useBackendContext } from "../../context/backend.js";
+import { useTranslationContext } from "../../context/translation.js";
 import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
 import { AccountByType, Props, State } from "./index.js";
 
@@ -31,6 +33,7 @@ export function useComponentState({
   onCancel,
 }: Props): State {
   const api = useBackendContext();
+  const { i18n } = useTranslationContext();
   const hook = useAsyncAsHook(() =>
     api.wallet.call(WalletApiOperation.ListKnownBankAccounts, { currency }),
   );
@@ -47,8 +50,8 @@ export function useComponentState({
   }
   if (hook.hasError) {
     return {
-      status: "loading-error",
-      error: hook,
+      status: "error",
+      error: alertFromError(i18n.str`Could not load known bank accounts`, 
hook),
     };
   }
 
diff --git 
a/packages/taler-wallet-webextension/src/wallet/ManageAccount/views.tsx 
b/packages/taler-wallet-webextension/src/wallet/ManageAccount/views.tsx
index 3af0d5505..e5be8d17d 100644
--- a/packages/taler-wallet-webextension/src/wallet/ManageAccount/views.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ManageAccount/views.tsx
@@ -23,11 +23,10 @@ import {
 import { styled } from "@linaria/react";
 import { Fragment, h, VNode } from "preact";
 import { useState } from "preact/hooks";
-import { LoadingError } from "../../components/LoadingError.js";
+import { ErrorMessage } from "../../components/ErrorMessage.js";
 import { SelectList } from "../../components/SelectList.js";
 import {
   Input,
-  LightText,
   SubTitle,
   SvgIcon,
   WarningText,
@@ -37,10 +36,9 @@ import { Button } from "../../mui/Button.js";
 import { TextFieldHandler } from "../../mui/handlers.js";
 import { TextField } from "../../mui/TextField.js";
 import checkIcon from "../../svg/check_24px.svg";
-import warningIcon from "../../svg/warning_24px.svg";
 import deleteIcon from "../../svg/delete_24px.svg";
+import warningIcon from "../../svg/warning_24px.svg";
 import { State } from "./index.js";
-import { ErrorMessage } from "../../components/ErrorMessage.js";
 
 type AccountType = "bitcoin" | "x-taler-bank" | "iban";
 type ComponentFormByAccountType = {
@@ -80,17 +78,6 @@ const AccountTable = styled.table`
   }
 `;
 
-export function LoadingUriView({ error }: State.LoadingUriError): VNode {
-  const { i18n } = useTranslationContext();
-
-  return (
-    <LoadingError
-      title={<i18n.Translate>Could not load</i18n.Translate>}
-      error={error}
-    />
-  );
-}
-
 export function ReadyView({
   currency,
   error,
@@ -118,14 +105,14 @@ export function ReadyView({
 
         {error && (
           <ErrorMessage
-            title={<i18n.Translate>Unable add this account</i18n.Translate>}
+            title={i18n.str`Unable add this account`}
             description={error}
           />
         )}
         <p>
           <Input>
             <SelectList
-              label={<i18n.Translate>Select account type</i18n.Translate>}
+              label={i18n.str`Select account type`}
               list={accountType.list}
               name="accountType"
               value={accountType.value}
diff --git 
a/packages/taler-wallet-webextension/src/wallet/Notifications/index.ts 
b/packages/taler-wallet-webextension/src/wallet/Notifications/index.ts
index 4697ca549..22b3adb0f 100644
--- a/packages/taler-wallet-webextension/src/wallet/Notifications/index.ts
+++ b/packages/taler-wallet-webextension/src/wallet/Notifications/index.ts
@@ -15,11 +15,12 @@
  */
 
 import { UserAttentionUnreadList } from "@gnu-taler/taler-util";
+import { ErrorAlertView } from "../../components/CurrentAlerts.js";
 import { Loading } from "../../components/Loading.js";
-import { HookError } from "../../hooks/useAsyncAsHook.js";
+import { ErrorAlert } from "../../context/alert.js";
 import { compose, StateViewMap } from "../../utils/index.js";
 import { useComponentState } from "./state.js";
-import { LoadingUriView, ReadyView } from "./views.js";
+import { ReadyView } from "./views.js";
 
 export type Props = object;
 
@@ -32,8 +33,8 @@ export namespace State {
   }
 
   export interface LoadingUriError {
-    status: "loading-error";
-    error: HookError;
+    status: "error";
+    error: ErrorAlert;
   }
 
   export interface BaseInfo {
@@ -49,7 +50,7 @@ export namespace State {
 
 const viewMapping: StateViewMap<State> = {
   loading: Loading,
-  "loading-error": LoadingUriView,
+  error: ErrorAlertView,
   ready: ReadyView,
 };
 
diff --git 
a/packages/taler-wallet-webextension/src/wallet/Notifications/state.ts 
b/packages/taler-wallet-webextension/src/wallet/Notifications/state.ts
index 648e490ce..0e06a1e75 100644
--- a/packages/taler-wallet-webextension/src/wallet/Notifications/state.ts
+++ b/packages/taler-wallet-webextension/src/wallet/Notifications/state.ts
@@ -15,12 +15,15 @@
  */
 
 import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
+import { alertFromError } from "../../context/alert.js";
 import { useBackendContext } from "../../context/backend.js";
+import { useTranslationContext } from "../../context/translation.js";
 import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
 import { Props, State } from "./index.js";
 
 export function useComponentState(p: Props): State {
   const api = useBackendContext();
+  const { i18n } = useTranslationContext();
   const hook = useAsyncAsHook(async () => {
     return await api.wallet.call(
       WalletApiOperation.GetUserAttentionRequests,
@@ -34,10 +37,14 @@ export function useComponentState(p: Props): State {
       error: undefined,
     };
   }
+
   if (hook.hasError) {
     return {
-      status: "loading-error",
-      error: hook,
+      status: "error",
+      error: alertFromError(
+        i18n.str`Could not load user attention request`,
+        hook,
+      ),
     };
   }
 
diff --git 
a/packages/taler-wallet-webextension/src/wallet/Notifications/views.tsx 
b/packages/taler-wallet-webextension/src/wallet/Notifications/views.tsx
index 9146d8837..8d0bb34c0 100644
--- a/packages/taler-wallet-webextension/src/wallet/Notifications/views.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Notifications/views.tsx
@@ -20,7 +20,6 @@ import {
   AttentionType,
 } from "@gnu-taler/taler-util";
 import { Fragment, h, VNode } from "preact";
-import { LoadingError } from "../../components/LoadingError.js";
 import {
   Column,
   DateSeparator,
@@ -37,17 +36,6 @@ import { Pages } from "../../NavigationBar.js";
 import { assertUnreachable } from "../../utils/index.js";
 import { State } from "./index.js";
 
-export function LoadingUriView({ error }: State.LoadingUriError): VNode {
-  const { i18n } = useTranslationContext();
-
-  return (
-    <LoadingError
-      title={<i18n.Translate>Could not load notifications</i18n.Translate>}
-      error={error}
-    />
-  );
-}
-
 const term = 1000 * 60 * 60 * 24;
 function normalizeToDay(x: number): number {
   return Math.round(x / term) * term;
diff --git a/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx 
b/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx
index eb86c9a3f..286a2a88d 100644
--- a/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx
@@ -127,11 +127,7 @@ export function SetUrlView({
         </Title>
         {error && (
           <ErrorMessage
-            title={
-              <i18n.Translate>
-                Could not get provider information
-              </i18n.Translate>
-            }
+            title={i18n.str`Could not get provider information`}
             description={error}
           />
         )}
@@ -223,7 +219,7 @@ export function ConfirmProviderView({
         </SubTitle>
         <p>
           {Amounts.isZero(provider.annual_fee) ? (
-            <i18n.Translate>free of charge</i18n.Translate>
+            i18n.str`free of charge`
           ) : (
             <i18n.Translate>
               {provider.annual_fee} per year of service
@@ -240,7 +236,7 @@ export function ConfirmProviderView({
           </i18n.Translate>
         </p>
         <Checkbox
-          label={<i18n.Translate>Accept terms of service</i18n.Translate>}
+          label={i18n.str`Accept terms of service`}
           name="terms"
           onToggle={async () => setAccepted((old) => !old)}
           enabled={accepted}
diff --git 
a/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx 
b/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx
index 46d54e871..9b72c0fae 100644
--- a/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx
@@ -23,11 +23,12 @@ import {
   WalletApiOperation,
 } from "@gnu-taler/taler-wallet-core";
 import { Fragment, h, VNode } from "preact";
+import { AlertView } from "../components/CurrentAlerts.js";
 import { ErrorMessage } from "../components/ErrorMessage.js";
 import { Loading } from "../components/Loading.js";
-import { LoadingError } from "../components/LoadingError.js";
 import { PaymentStatus, SmallLightText } from "../components/styled/index.js";
 import { Time } from "../components/Time.js";
+import { alertFromError } from "../context/alert.js";
 import { useBackendContext } from "../context/backend.js";
 import { useTranslationContext } from "../context/translation.js";
 import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
@@ -65,14 +66,11 @@ export function ProviderDetailPage({
   }
   if (state.hasError) {
     return (
-      <LoadingError
-        title={
-          <i18n.Translate>
-            There was an error loading the provider detail for &quot;
-            {providerURL}&quot;
-          </i18n.Translate>
-        }
-        error={state}
+      <AlertView
+        alert={alertFromError(
+          i18n.str`There was an error loading the provider detail for 
&quot;${providerURL}&quot;`,
+          state,
+        )}
       />
     );
   }
@@ -270,9 +268,7 @@ function Error({ info }: { info: ProviderInfo }): VNode {
   if (info.lastError) {
     return (
       <ErrorMessage
-        title={
-          <i18n.Translate>This provider has reported an error</i18n.Translate>
-        }
+        title={i18n.str`This provider has reported an error`}
         description={info.lastError.hint}
       />
     );
@@ -282,32 +278,17 @@ function Error({ info }: { info: ProviderInfo }): VNode {
       case "backup-conflicting-device":
         return (
           <ErrorMessage
-            title={
-              <Fragment>
-                <i18n.Translate>
-                  There is conflict with another backup from{" "}
-                  <b>{info.backupProblem.otherDeviceId}</b>
-                </i18n.Translate>
-              </Fragment>
-            }
+            title={i18n.str`There is conflict with another backup from 
&quot;${info.backupProblem.otherDeviceId}&quot;`}
           />
         );
       case "backup-unreadable":
-        return (
-          <ErrorMessage
-            title={<i18n.Translate>Backup is not readable</i18n.Translate>}
-          />
-        );
+        return <ErrorMessage title={i18n.str`Backup is not readable`} />;
       default:
         return (
           <ErrorMessage
-            title={
-              <Fragment>
-                <i18n.Translate>
-                  Unknown backup problem: {JSON.stringify(info.backupProblem)}
-                </i18n.Translate>
-              </Fragment>
-            }
+            title={i18n.str`Unknown backup problem: ${JSON.stringify(
+              info.backupProblem,
+            )}`}
           />
         );
     }
diff --git a/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx 
b/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx
index a259f7c9a..c366f014f 100644
--- a/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx
@@ -42,8 +42,8 @@ export function ReserveCreated({
   if (!paytoURI) {
     return (
       <ErrorMessage
-        title={<i18n.Translate>Could not parse the payto URI</i18n.Translate>}
-        description={<i18n.Translate>Please check the uri</i18n.Translate>}
+        title={i18n.str`Could not parse the payto URI`}
+        description={i18n.str`Please check the uri`}
       />
     );
   }
diff --git a/packages/taler-wallet-webextension/src/wallet/Settings.tsx 
b/packages/taler-wallet-webextension/src/wallet/Settings.tsx
index 768a4ca6a..ed1bc838a 100644
--- a/packages/taler-wallet-webextension/src/wallet/Settings.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Settings.tsx
@@ -111,13 +111,13 @@ export function SettingsView({
       <section>
         {autoOpenToggle.button.error && (
           <ErrorTalerOperation
-            title={<i18n.Translate>Could not toggle auto-open</i18n.Translate>}
+            title={i18n.str`Could not toggle auto-open`}
             error={autoOpenToggle.button.error.errorDetail}
           />
         )}
         {/* {clipboardToggle.button.error && (
           <ErrorTalerOperation
-            title={<i18n.Translate>Could not toggle clipboard</i18n.Translate>}
+            title={i18n.str`Could not toggle clipboard`}
             error={clipboardToggle.button.error.errorDetail}
           />
         )} */}
@@ -125,11 +125,7 @@ export function SettingsView({
           <i18n.Translate>Navigator</i18n.Translate>
         </SubTitle>
         <Checkbox
-          label={
-            <i18n.Translate>
-              Automatically open wallet based on page content
-            </i18n.Translate>
-          }
+          label={i18n.str`Automatically open wallet based on page content`}
           name="autoOpen"
           description={
             <i18n.Translate>
@@ -142,9 +138,7 @@ export function SettingsView({
         />
         {/* <Checkbox
           label={
-            <i18n.Translate>
-              Automatically check clipboard for Taler URI
-            </i18n.Translate>
+            i18n.str`Automatically check clipboard for Taler URI`
           }
           name="clipboard"
           description={
@@ -241,13 +235,9 @@ export function SettingsView({
           <i18n.Translate>Troubleshooting</i18n.Translate>
         </SubTitle>
         <Checkbox
-          label={<i18n.Translate>Developer mode</i18n.Translate>}
+          label={i18n.str`Developer mode`}
           name="devMode"
-          description={
-            <i18n.Translate>
-              More options and information useful for debugging
-            </i18n.Translate>
-          }
+          description={i18n.str`More options and information useful for 
debugging`}
           enabled={devModeToggle.value!}
           onToggle={devModeToggle.button.onClick!}
         />
@@ -271,7 +261,7 @@ export function SettingsView({
         </SubTitle>
         {coreVersion && (
           <Part
-            title={<i18n.Translate>Wallet Core</i18n.Translate>}
+            title={i18n.str`Wallet Core`}
             text={
               <span>
                 {coreVersion.version}{" "}
@@ -281,7 +271,7 @@ export function SettingsView({
           />
         )}
         <Part
-          title={<i18n.Translate>Web Extension</i18n.Translate>}
+          title={i18n.str`Web Extension`}
           text={
             <span>
               {webexVersion.version}{" "}
@@ -292,15 +282,15 @@ export function SettingsView({
         {coreVersion && (
           <JustInDevMode>
             <Part
-              title={<i18n.Translate>Exchange compatibility</i18n.Translate>}
+              title={i18n.str`Exchange compatibility`}
               text={<span>{coreVersion.exchange}</span>}
             />
             <Part
-              title={<i18n.Translate>Merchant compatibility</i18n.Translate>}
+              title={i18n.str`Merchant compatibility`}
               text={<span>{coreVersion.merchant}</span>}
             />
             <Part
-              title={<i18n.Translate>Bank compatibility</i18n.Translate>}
+              title={i18n.str`Bank compatibility`}
               text={<span>{coreVersion.bank}</span>}
             />
           </JustInDevMode>
diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx 
b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
index b7eb4a947..542694490 100644
--- a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
@@ -32,6 +32,7 @@ import {
   TransactionRefund,
   TransactionTip,
   TransactionType,
+  TranslatedString,
   WithdrawalType,
 } from "@gnu-taler/taler-util";
 import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
@@ -43,9 +44,8 @@ import emptyImg from "../../static/img/empty.png";
 import { Amount } from "../components/Amount.js";
 import { BankDetailsByPaytoType } from 
"../components/BankDetailsByPaytoType.js";
 import { CopyButton } from "../components/CopyButton.js";
-import { ErrorTalerOperation } from "../components/ErrorTalerOperation.js";
+import { AlertView, ErrorAlertView } from "../components/CurrentAlerts.js";
 import { Loading } from "../components/Loading.js";
-import { LoadingError } from "../components/LoadingError.js";
 import { Kind, Part, PartCollapsible, PartPayto } from "../components/Part.js";
 import { QR } from "../components/QR.js";
 import { ShowFullContractTermPopup } from 
"../components/ShowFullContractTermPopup.js";
@@ -60,6 +60,7 @@ import {
   WarningBox,
 } from "../components/styled/index.js";
 import { Time } from "../components/Time.js";
+import { alertFromError } from "../context/alert.js";
 import { useBackendContext } from "../context/backend.js";
 import { useTranslationContext } from "../context/translation.js";
 import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
@@ -98,13 +99,11 @@ export function TransactionPage({
 
   if (state.hasError) {
     return (
-      <LoadingError
-        title={
-          <i18n.Translate>
-            Could not load the transaction information
-          </i18n.Translate>
-        }
-        error={state}
+      <AlertView
+        alert={alertFromError(
+          i18n.str`Could not load transaction information`,
+          state,
+        )}
       />
     );
   }
@@ -199,14 +198,14 @@ export function TransactionView({
     return (
       <Fragment>
         <section style={{ padding: 8, textAlign: "center" }}>
-          <ErrorTalerOperation
-            title={
-              <i18n.Translate>
-                There was an error trying to complete the transaction
-              </i18n.Translate>
-            }
-            error={transaction?.error}
-          />
+          {transaction?.error ? (
+            <ErrorAlertView
+              error={alertFromError(
+                i18n.str`There was an error trying to complete the 
transaction`,
+                transaction.error,
+              )}
+            />
+          ) : undefined}
           {transaction.pending && (
             <WarningBox>
               <i18n.Translate>This transaction is not 
completed</i18n.Translate>
@@ -367,7 +366,7 @@ export function TransactionView({
           </Fragment>
         )}
         <Part
-          title={<i18n.Translate>Details</i18n.Translate>}
+          title={i18n.str`Details`}
           text={
             <WithdrawDetails
               amount={{
@@ -420,7 +419,7 @@ export function TransactionView({
         <br />
         {transaction.refunds.length > 0 ? (
           <Part
-            title={<i18n.Translate>Refunds</i18n.Translate>}
+            title={i18n.str`Refunds`}
             text={
               <table>
                 {transaction.refunds.map((r, i) => {
@@ -462,7 +461,7 @@ export function TransactionView({
               picked up.
             </i18n.Translate>
             <Part
-              title={<i18n.Translate>Offer</i18n.Translate>}
+              title={i18n.str`Offer`}
               text={<Amount value={pendingRefund} />}
               kind="positive"
             />
@@ -480,17 +479,17 @@ export function TransactionView({
           </InfoBox>
         )}
         <Part
-          title={<i18n.Translate>Merchant</i18n.Translate>}
+          title={i18n.str`Merchant`}
           text={<MerchantDetails merchant={transaction.info.merchant} />}
           kind="neutral"
         />
         <Part
-          title={<i18n.Translate>Invoice ID</i18n.Translate>}
-          text={transaction.info.orderId}
+          title={i18n.str`Invoice ID`}
+          text={transaction.info.orderId as TranslatedString}
           kind="neutral"
         />
         <Part
-          title={<i18n.Translate>Details</i18n.Translate>}
+          title={i18n.str`Details`}
           text={
             <PurchaseDetails
               price={price}
@@ -520,12 +519,12 @@ export function TransactionView({
         </Header>
         {payto && <PartPayto payto={payto} kind="neutral" />}
         <Part
-          title={<i18n.Translate>Details</i18n.Translate>}
+          title={i18n.str`Details`}
           text={<DepositDetails transaction={transaction} />}
           kind="neutral"
         />
         <Part
-          title={<i18n.Translate>Wire transfer deadline</i18n.Translate>}
+          title={i18n.str`Wire transfer deadline`}
           text={
             <Time
               timestamp={AbsoluteTime.fromTimestamp(
@@ -557,7 +556,7 @@ export function TransactionView({
           {transaction.exchangeBaseUrl}
         </Header>
         <Part
-          title={<i18n.Translate>Details</i18n.Translate>}
+          title={i18n.str`Details`}
           text={<RefreshDetails transaction={transaction} />}
         />
       </TransactionTemplate>
@@ -578,12 +577,12 @@ export function TransactionView({
           {transaction.merchantBaseUrl}
         </Header>
         {/* <Part
-          title={<i18n.Translate>Merchant</i18n.Translate>}
+          title={i18n.str`Merchant`}
           text={<MerchantDetails merchant={transaction.merchant} />}
           kind="neutral"
         /> */}
         <Part
-          title={<i18n.Translate>Details</i18n.Translate>}
+          title={i18n.str`Details`}
           text={<TipDetails transaction={transaction} />}
         />
       </TransactionTemplate>
@@ -604,12 +603,12 @@ export function TransactionView({
         </Header>
 
         <Part
-          title={<i18n.Translate>Merchant</i18n.Translate>}
-          text={transaction.info.merchant.name}
+          title={i18n.str`Merchant`}
+          text={transaction.info.merchant.name as TranslatedString}
           kind="neutral"
         />
         <Part
-          title={<i18n.Translate>Original order ID</i18n.Translate>}
+          title={i18n.str`Original order ID`}
           text={
             <a
               href={Pages.balanceTransaction({
@@ -622,12 +621,12 @@ export function TransactionView({
           kind="neutral"
         />
         <Part
-          title={<i18n.Translate>Purchase summary</i18n.Translate>}
-          text={transaction.info.summary}
+          title={i18n.str`Purchase summary`}
+          text={transaction.info.summary as TranslatedString}
           kind="neutral"
         />
         <Part
-          title={<i18n.Translate>Details</i18n.Translate>}
+          title={i18n.str`Details`}
           text={<RefundDetails transaction={transaction} />}
         />
       </TransactionTemplate>
@@ -683,25 +682,25 @@ export function TransactionView({
 
         {transaction.info.summary ? (
           <Part
-            title={<i18n.Translate>Subject</i18n.Translate>}
-            text={transaction.info.summary}
+            title={i18n.str`Subject`}
+            text={transaction.info.summary as TranslatedString}
             kind="neutral"
           />
         ) : undefined}
         <Part
-          title={<i18n.Translate>Exchange</i18n.Translate>}
-          text={transaction.exchangeBaseUrl}
+          title={i18n.str`Exchange`}
+          text={transaction.exchangeBaseUrl as TranslatedString}
           kind="neutral"
         />
         {transaction.pending /** pending is not-pay */ && (
           <Part
-            title={<i18n.Translate>URI</i18n.Translate>}
+            title={i18n.str`URI`}
             text={<ShowQrWithCopy text={transaction.talerUri} />}
             kind="neutral"
           />
         )}
         <Part
-          title={<i18n.Translate>Details</i18n.Translate>}
+          title={i18n.str`Details`}
           text={
             <InvoiceDetails
               amount={{
@@ -730,18 +729,18 @@ export function TransactionView({
 
         {transaction.info.summary ? (
           <Part
-            title={<i18n.Translate>Subject</i18n.Translate>}
-            text={transaction.info.summary}
+            title={i18n.str`Subject`}
+            text={transaction.info.summary as TranslatedString}
             kind="neutral"
           />
         ) : undefined}
         <Part
-          title={<i18n.Translate>Exchange</i18n.Translate>}
-          text={transaction.exchangeBaseUrl}
+          title={i18n.str`Exchange`}
+          text={transaction.exchangeBaseUrl as TranslatedString}
           kind="neutral"
         />
         <Part
-          title={<i18n.Translate>Details</i18n.Translate>}
+          title={i18n.str`Details`}
           text={
             <InvoiceDetails
               amount={{
@@ -769,25 +768,25 @@ export function TransactionView({
 
         {transaction.info.summary ? (
           <Part
-            title={<i18n.Translate>Subject</i18n.Translate>}
-            text={transaction.info.summary}
+            title={i18n.str`Subject`}
+            text={transaction.info.summary as TranslatedString}
             kind="neutral"
           />
         ) : undefined}
         <Part
-          title={<i18n.Translate>Exchange</i18n.Translate>}
-          text={transaction.exchangeBaseUrl}
+          title={i18n.str`Exchange`}
+          text={transaction.exchangeBaseUrl as TranslatedString}
           kind="neutral"
         />
         {/* {transaction.pending && ( //pending is not-received 
             )} */}
         <Part
-          title={<i18n.Translate>URI</i18n.Translate>}
+          title={i18n.str`URI`}
           text={<ShowQrWithCopy text={transaction.talerUri} />}
           kind="neutral"
         />
         <Part
-          title={<i18n.Translate>Details</i18n.Translate>}
+          title={i18n.str`Details`}
           text={
             <TransferDetails
               amount={{
@@ -816,18 +815,18 @@ export function TransactionView({
 
         {transaction.info.summary ? (
           <Part
-            title={<i18n.Translate>Subject</i18n.Translate>}
-            text={transaction.info.summary}
+            title={i18n.str`Subject`}
+            text={transaction.info.summary as TranslatedString}
             kind="neutral"
           />
         ) : undefined}
         <Part
-          title={<i18n.Translate>Exchange</i18n.Translate>}
-          text={transaction.exchangeBaseUrl}
+          title={i18n.str`Exchange`}
+          text={transaction.exchangeBaseUrl as TranslatedString}
           kind="neutral"
         />
         <Part
-          title={<i18n.Translate>Details</i18n.Translate>}
+          title={i18n.str`Details`}
           text={
             <TransferDetails
               amount={{
@@ -1245,7 +1244,7 @@ export function PurchaseDetails({
           <td colSpan={2}>
             <PartCollapsible
               big
-              title={<i18n.Translate>Products</i18n.Translate>}
+              title={i18n.str`Products`}
               text={
                 <ListOfProducts>
                   {info.products?.map((p, k) => (
@@ -1274,7 +1273,7 @@ export function PurchaseDetails({
           <td colSpan={2}>
             <PartCollapsible
               big
-              title={<i18n.Translate>Delivery</i18n.Translate>}
+              title={i18n.str`Delivery`}
               text={
                 <DeliveryDetails
                   date={info.delivery_date}
@@ -1508,7 +1507,7 @@ function Header({
   total: AmountJson;
   children: ComponentChildren;
   kind: Kind;
-  type: string;
+  type: TranslatedString;
 }): VNode {
   return (
     <div
diff --git a/packages/taler-wallet-webextension/src/wallet/Welcome.tsx 
b/packages/taler-wallet-webextension/src/wallet/Welcome.tsx
index 0b64417b8..b243eaa1c 100644
--- a/packages/taler-wallet-webextension/src/wallet/Welcome.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Welcome.tsx
@@ -91,11 +91,7 @@ export function View({
           <i18n.Translate>Permissions</i18n.Translate>
         </SubTitle>
         <Checkbox
-          label={
-            <i18n.Translate>
-              Automatically open wallet based on page content
-            </i18n.Translate>
-          }
+          label={i18n.str`Automatically open wallet based on page content`}
           name="perm"
           description={
             <i18n.Translate>
diff --git a/packages/taler-wallet-webextension/src/wxApi.ts 
b/packages/taler-wallet-webextension/src/wxApi.ts
index 5c2a577b3..a41372e37 100644
--- a/packages/taler-wallet-webextension/src/wxApi.ts
+++ b/packages/taler-wallet-webextension/src/wxApi.ts
@@ -25,6 +25,8 @@ import {
   CoreApiResponse,
   Logger,
   NotificationType,
+  TalerErrorCode,
+  TalerErrorDetail,
   WalletDiagnostics,
 } from "@gnu-taler/taler-util";
 import {
@@ -33,11 +35,14 @@ import {
   WalletCoreOpKeys,
   WalletCoreRequestType,
   WalletCoreResponseType,
+  WalletOperations,
 } from "@gnu-taler/taler-wallet-core";
-import { MessageFromBackend, MessageFromFrontendBackground, 
MessageFromFrontendWallet } from "./platform/api.js";
 import {
-  platform,
-} from "./platform/foreground.js";
+  MessageFromBackend,
+  MessageFromFrontendBackground,
+  MessageFromFrontendWallet,
+} from "./platform/api.js";
+import { platform } from "./platform/foreground.js";
 
 /**
  *
@@ -88,6 +93,25 @@ export interface BackgroundApiClient {
   ): Promise<BackgroundOperations[Op]["response"]>;
 }
 
+export class WalletError extends Error {
+  public errorDetail: TalerError;
+
+  constructor(op: string, e: TalerError) {
+    super(`Wallet operation "${op}" failed: ${e.message}`);
+    this.errorDetail = e;
+    // Object.setPrototypeOf(this, WalletError.prototype);
+  }
+}
+export class BackgroundError extends Error {
+  public errorDetail: TalerErrorDetail;
+
+  constructor(op: string, e: TalerErrorDetail) {
+    super(`Background operation "${op}" failed: ${e.message}`);
+    this.errorDetail = e;
+    // Object.setPrototypeOf(this, BackgroundError.prototype);
+  }
+}
+
 /**
  * BackgroundApiClient integration with browser platform
  */
@@ -106,13 +130,18 @@ class BackgroundApiClientImpl implements 
BackgroundApiClient {
 
     try {
       response = await platform.sendMessageToBackground(message);
-    } catch (e) {
+    } catch (error) {
       console.log("Error calling backend");
-      throw new Error(`Error contacting backend: ${e}`);
+      if (error instanceof Error) {
+        throw new BackgroundError(operation, {
+          code: TalerErrorCode.GENERIC_UNEXPECTED_REQUEST_ERROR,
+        });
+      }
+      throw error;
     }
     logger.info("got response", response);
     if (response.type === "error") {
-      throw TalerError.fromUncheckedDetail(response.error);
+      throw new BackgroundError(operation, response.error);
     }
     return response.result as any;
   }
@@ -140,7 +169,8 @@ class WalletApiClientImpl implements WalletCoreApiClient {
     }
     logger.info("got response", response);
     if (response.type === "error") {
-      throw TalerError.fromUncheckedDetail(response.error);
+      const error = TalerError.fromUncheckedDetail(response.error);
+      throw new WalletError(operation, error);
     }
     return response.result as any;
   }
diff --git a/packages/taler-wallet-webextension/src/wxBackend.ts 
b/packages/taler-wallet-webextension/src/wxBackend.ts
index b75e92004..c7b964c28 100644
--- a/packages/taler-wallet-webextension/src/wxBackend.ts
+++ b/packages/taler-wallet-webextension/src/wxBackend.ts
@@ -46,9 +46,7 @@ import {
   WalletStoresV1,
 } from "@gnu-taler/taler-wallet-core";
 import { BrowserHttpLib } from "./browserHttpLib.js";
-import {
-  platform,
-} from "./platform/background.js";
+import { platform } from "./platform/background.js";
 import {
   MessageFromBackend,
   MessageFromFrontend,
@@ -199,13 +197,22 @@ async function dispatch<Op extends WalletOperations | 
BackgroundOperations>(
         ),
       };
     }
-    const result = await handler(req.payload);
-    return {
-      type: "response",
-      id: req.id,
-      operation: String(req.operation),
-      result,
-    };
+    try {
+      const result = await handler(req.payload);
+      return {
+        type: "response",
+        id: req.id,
+        operation: String(req.operation),
+        result,
+      };
+    } catch (er) {
+      return {
+        type: "error",
+        id: req.id,
+        error: getErrorDetailFromException(er),
+        operation: String(req.operation),
+      };
+    }
   }
 
   if (req.channel === "wallet") {
@@ -232,7 +239,9 @@ async function dispatch<Op extends WalletOperations | 
BackgroundOperations>(
     id: anyReq.id,
     operation: String(anyReq.operation),
     error: getErrorDetailFromException(
-      Error(`unknown channel ${anyReq.channel}`),
+      Error(
+        `unknown channel ${anyReq.channel}, should be "background" or 
"wallet"`,
+      ),
     ),
   };
 }
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 6983ba177..0355f1535 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -649,7 +649,7 @@ importers:
       qrcode-generator: ^1.4.4
       rimraf: ^3.0.2
       tslib: ^2.4.0
-      typescript: ^4.8.4
+      typescript: 4.9.4
     dependencies:
       '@gnu-taler/taler-util': link:../taler-util
       '@gnu-taler/taler-wallet-core': link:../taler-wallet-core
@@ -687,7 +687,7 @@ importers:
       preact-cli: 3.4.1_i2jslynuqxjzp37vlc24guk7gu
       preact-render-to-string: 5.2.6_preact@10.11.3
       rimraf: 3.0.2
-      typescript: 4.8.4
+      typescript: 4.9.4
 
   packages/web-util:
     specifiers:
@@ -8412,7 +8412,7 @@ packages:
       minipass-pipeline: 1.2.4
       mkdirp: 1.0.4
       p-map: 4.0.0
-      promise-inflight: 1.0.1
+      promise-inflight: 1.0.1_bluebird@3.7.2
       rimraf: 3.0.2
       ssri: 8.0.1
       tar: 6.1.11
@@ -18096,15 +18096,6 @@ packages:
     engines: {node: '>=0.4.0'}
     dev: true
 
-  /promise-inflight/1.0.1:
-    resolution: {integrity: 
sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==}
-    peerDependencies:
-      bluebird: '*'
-    peerDependenciesMeta:
-      bluebird:
-        optional: true
-    dev: true
-
   /promise-inflight/1.0.1_bluebird@3.7.2:
     resolution: {integrity: 
sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==}
     peerDependencies:
@@ -20691,6 +20682,12 @@ packages:
     hasBin: true
     dev: true
 
+  /typescript/4.9.4:
+    resolution: {integrity: 
sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==}
+    engines: {node: '>=4.2.0'}
+    hasBin: true
+    dev: true
+
   /uglify-js/3.17.4:
     resolution: {integrity: 
sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==}
     engines: {node: '>=0.8.0'}

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]