commit 8dcc6a041e36e43d9b34c4eb3f881a77a64f4a55
parent aeea52790fa0d4a54f5839a1adce9eaace5a9dba
Author: Florian Dold <dold@taler.net>
Date: Mon, 31 Aug 2026 14:23:31 +0200
exchange AML web UI: redesign officer case management
Diffstat:
169 files changed, 52666 insertions(+), 19191 deletions(-)
diff --git a/packages/libeufin-bank-webui/src/hooks/account.test.ts b/packages/libeufin-bank-webui/src/hooks/account.test.ts
@@ -0,0 +1,58 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import assert from "node:assert/strict";
+import test from "node:test";
+import { StateUpdater } from "preact/hooks";
+import { PAGINATED_LIST_REQUEST } from "../utils.js";
+import { buildPaginatedResult } from "./account.js";
+
+test("forward pagination reports and updates the current page", () => {
+ let offset: number | undefined = 1;
+ let currentPage = 2;
+ const setOffset = (next: number | undefined) => {
+ offset = next;
+ };
+ const setCurrentPage: StateUpdater<number> = (next) => {
+ currentPage = typeof next === "function" ? next(currentPage) : next;
+ };
+ const rows = Array.from({ length: PAGINATED_LIST_REQUEST }, (_, index) => ({
+ id: index + 2,
+ }));
+
+ const middlePage = buildPaginatedResult(
+ rows,
+ offset,
+ setOffset,
+ (row) => row.id,
+ currentPage,
+ setCurrentPage,
+ );
+
+ assert.equal(middlePage.currentPage, 2);
+ assert.equal(middlePage.body.length, PAGINATED_LIST_REQUEST - 1);
+ middlePage.loadNext?.();
+ assert.equal(offset, PAGINATED_LIST_REQUEST);
+ assert.equal(currentPage, 3);
+
+ const lastPage = buildPaginatedResult(
+ [{ id: PAGINATED_LIST_REQUEST + 1 }],
+ offset,
+ setOffset,
+ (row) => row.id,
+ currentPage,
+ setCurrentPage,
+ );
+
+ assert.equal(lastPage.currentPage, 3);
+ assert.equal(lastPage.loadNext, undefined);
+ lastPage.loadFirst?.();
+ assert.equal(offset, undefined);
+ assert.equal(currentPage, 1);
+});
diff --git a/packages/libeufin-bank-webui/src/hooks/account.ts b/packages/libeufin-bank-webui/src/hooks/account.ts
@@ -1,6 +1,6 @@
/*
This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
+ (C) 2022-2026 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
@@ -23,7 +23,7 @@ import {
TalerError,
TalerHttpError,
} from "@gnu-taler/taler-util";
-import { useEffect, useState } from "preact/hooks";
+import { StateUpdater, useEffect, useState } from "preact/hooks";
import { useSessionState } from "./session.js";
// FIX default import https://github.com/microsoft/TypeScript/issues/49189
@@ -171,8 +171,12 @@ export function usePublicAccounts(
initial?: number,
) {
const [offset, setOffset] = useState<number | undefined>(initial);
+ const [currentPage, setCurrentPage] = useState(1);
- useEffect(() => setOffset(initial), [filterAccount, initial]);
+ useEffect(() => {
+ setOffset(initial);
+ setCurrentPage(1);
+ }, [filterAccount, initial]);
const {
lib: { bank: api },
@@ -217,6 +221,8 @@ export function usePublicAccounts(
offset,
setOffset,
(d) => d.row_id ?? 0,
+ currentPage,
+ setCurrentPage,
);
}
@@ -226,6 +232,8 @@ export function buildPaginatedResult<DataType, OffsetId>(
offset: OffsetId | undefined,
setOffset: (o: OffsetId | undefined) => void,
getId: (r: DataType) => OffsetId,
+ currentPage: number,
+ setCurrentPage: StateUpdater<number>,
): PaginatedResult<DataType[]> {
const isLastPage = data.length < PAGINATED_LIST_REQUEST;
const isFirstPage = offset === undefined;
@@ -240,17 +248,20 @@ export function buildPaginatedResult<DataType, OffsetId>(
case: "ok",
body: result,
response: dummyHttpResponse,
+ currentPage,
loadNext: isLastPage
? undefined
: () => {
if (!result.length) return;
const id = getId(result[result.length - 1]);
setOffset(id);
+ setCurrentPage((page) => page + 1);
},
loadFirst: isFirstPage
? undefined
: () => {
setOffset(undefined);
+ setCurrentPage(1);
},
};
}
diff --git a/packages/libeufin-bank-webui/src/hooks/regional.ts b/packages/libeufin-bank-webui/src/hooks/regional.ts
@@ -653,6 +653,7 @@ export function useConversionRateClasses() {
} = useBankCoreApiContext();
const [offset, setOffset] = useState<number | undefined>();
+ const [currentPage, setCurrentPage] = useState(1);
function fetcher([token, aid]: [AccessToken, number]) {
return api.listConversionRateClasses(token, {
@@ -686,6 +687,8 @@ export function useConversionRateClasses() {
offset,
setOffset,
(d) => d.conversion_rate_class_id,
+ currentPage,
+ setCurrentPage,
);
}
@@ -743,8 +746,12 @@ export function useConversionRateClassUsers(
} = useBankCoreApiContext();
const [offset, setOffset] = useState<number | undefined>();
+ const [currentPage, setCurrentPage] = useState(1);
- useEffect(() => setOffset(undefined), [classId, username]);
+ useEffect(() => {
+ setOffset(undefined);
+ setCurrentPage(1);
+ }, [classId, username]);
function fetcher([token, aid, username, classId]: [
AccessToken,
@@ -789,5 +796,7 @@ export function useConversionRateClassUsers(
offset,
setOffset,
(d) => d.row_id!,
+ currentPage,
+ setCurrentPage,
);
}
diff --git a/packages/taler-exchange-aml-webui/package.json b/packages/taler-exchange-aml-webui/package.json
@@ -25,20 +25,20 @@
"@headlessui/react": "^1.7.14",
"@heroicons/react": "^2.0.17",
"date-fns": "2.29.3",
- "history": "4.10.1",
"jed": "1.1.1",
"preact": "10.11.3",
- "swr": "2.2.2"
+ "swr": "2.2.2",
+ "wouter-preact": "^3.7.1"
},
"devDependencies": {
"@gnu-taler/pogen": "workspace:*",
"@tailwindcss/forms": "^0.5.3",
"@types/chai": "^4.3.0",
- "@types/history": "^4.7.8",
"@types/node": "^20.19.41",
"autoprefixer": "^10.4.14",
"chai": "^6.2.2",
"esbuild": "^0.28.0",
+ "happy-dom": "20.11.1",
"postcss": "^8.4.23",
"tailwindcss": "3.4.17",
"typescript": "7.0.2"
diff --git a/packages/taler-exchange-aml-webui/src/App.tsx b/packages/taler-exchange-aml-webui/src/App.tsx
@@ -20,17 +20,24 @@ import {
canonicalizeBaseUrl,
} from "@gnu-taler/taler-util";
import {
- BrowserHashNavigationProvider,
ExchangeApiProvider,
Loading,
NotificationProvider,
TranslationProvider,
+ useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { VNode, h } from "preact";
import { useEffect, useState } from "preact/hooks";
import { SWRConfig } from "swr";
+import { Router } from "wouter-preact";
+import { useHashLocation } from "wouter-preact/use-hash-location";
import { ExchangeAmlFrame } from "./ExchangeAmlFrame.js";
+import { AccessCheckStatus } from "./components/AccessCheckStatus.js";
import { Routing } from "./Routing.js";
+import {
+ AML_BASE_URL_OVERRIDE_KEY,
+ DeveloperWithoutExchange,
+} from "./pages/Developer.js";
import { UiFormsProvider } from "./context/ui-forms.js";
import {
UiSettings,
@@ -38,77 +45,118 @@ import {
fetchUiSettings,
} from "./context/ui-settings.js";
import { revalidateAccountInformation } from "./hooks/account.js";
-import { revalidateAccountDecisions } from "./hooks/decisions.js";
+import {
+ revalidateAccountDecisions,
+ revalidateAmlAccounts,
+} from "./hooks/decisions.js";
+import { revalidateCurrentLegitimizations } from "./hooks/legitimizations.js";
import { OfficerProvider } from "./hooks/officer.js";
import { usePreferences } from "./hooks/preferences.js";
+import { revalidateTopsServerStatistics } from "./hooks/server-info.js";
import { strings } from "./i18n/strings.js";
import "./scss/main.scss";
const WITH_LOCAL_STORAGE_CACHE = false;
+function useAmlHashLocation(): ReturnType<typeof useHashLocation> {
+ const [location, navigate] = useHashLocation();
+ return [location.split("?", 1)[0] || "/", navigate];
+}
+
export function App(): VNode {
const [settings, setSettings] = useState<UiSettings>();
const [{ preventCompression }] = usePreferences();
+ const [route] = useAmlHashLocation();
useEffect(() => {
fetchUiSettings(setSettings);
}, []);
- if (!settings) return <Loading />;
+ if (!settings) {
+ return (
+ <TranslationProvider source={strings}>
+ <Loading />
+ </TranslationProvider>
+ );
+ }
const baseUrl = getInitialBackendBaseURL(settings.backendBaseURL);
+ const developerRequested = route === "/dev";
return (
<UiSettingsProvider value={settings}>
<TranslationProvider source={strings}>
<NotificationProvider>
- <ExchangeApiProvider
- baseUrl={new URL("/", baseUrl)}
- frameOnError={ExchangeAmlFrame}
- evictors={{
- exchange: evictExchangeSwrCache,
- }}
- preventCompression={preventCompression}
- >
- <SWRConfig
- value={{
- provider: WITH_LOCAL_STORAGE_CACHE
- ? localStorageProvider
- : undefined,
- // normally, do not revalidate
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- revalidateIfStale: false,
- revalidateOnMount: undefined,
- focusThrottleInterval: undefined,
-
- // normally, do not refresh
- refreshInterval: undefined,
- dedupingInterval: 2000,
- refreshWhenHidden: false,
- refreshWhenOffline: false,
-
- // ignore errors
- shouldRetryOnError: false,
- errorRetryCount: 0,
- errorRetryInterval: undefined,
-
- // do not go to loading again if already has data
- keepPreviousData: true,
+ {developerRequested ? (
+ <ExchangeAmlFrame>
+ <DeveloperWithoutExchange
+ effectiveBaseUrl={new URL("/", baseUrl).href}
+ />
+ </ExchangeAmlFrame>
+ ) : (
+ <ExchangeApiProvider
+ baseUrl={new URL("/", baseUrl)}
+ frameOnError={ExchangeAmlFrame}
+ evictors={{
+ exchange: evictExchangeSwrCache,
}}
+ preventCompression={preventCompression}
+ compatibilityLoading={<CompatibilityCheck />}
>
- <BrowserHashNavigationProvider>
- <OfficerProvider>
- <UiFormsProvider>
- <Routing />
- </UiFormsProvider>
- </OfficerProvider>
- </BrowserHashNavigationProvider>
- </SWRConfig>
- </ExchangeApiProvider>
+ <SWRConfig
+ value={{
+ provider: WITH_LOCAL_STORAGE_CACHE
+ ? localStorageProvider
+ : undefined,
+ // normally, do not revalidate
+ revalidateOnFocus: false,
+ revalidateOnReconnect: false,
+ revalidateIfStale: false,
+ revalidateOnMount: undefined,
+ focusThrottleInterval: undefined,
+
+ // normally, do not refresh
+ refreshInterval: undefined,
+ dedupingInterval: 2000,
+ refreshWhenHidden: false,
+ refreshWhenOffline: false,
+
+ // ignore errors
+ shouldRetryOnError: false,
+ errorRetryCount: 0,
+ errorRetryInterval: undefined,
+
+ // do not go to loading again if already has data
+ keepPreviousData: true,
+ }}
+ >
+ <Router hook={useAmlHashLocation} hrefs={(href) => `#${href}`}>
+ <OfficerProvider>
+ <UiFormsProvider>
+ <Routing />
+ </UiFormsProvider>
+ </OfficerProvider>
+ </Router>
+ </SWRConfig>
+ </ExchangeApiProvider>
+ )}
</NotificationProvider>
</TranslationProvider>
</UiSettingsProvider>
);
}
+function CompatibilityCheck(): VNode {
+ const { i18n } = useTranslationContext();
+ return (
+ <AccessCheckStatus
+ title={<i18n.Translate>Checking compatibility</i18n.Translate>}
+ description={
+ <i18n.Translate>
+ Verifying that this web application is compatible with the exchange.
+ </i18n.Translate>
+ }
+ />
+ );
+}
+
function localStorageProvider(): Map<unknown, unknown> {
const map = new Map(JSON.parse(localStorage.getItem("app-cache") || "[]"));
@@ -124,7 +172,7 @@ function getInitialBackendBaseURL(
): string {
const overrideUrl =
typeof localStorage !== "undefined"
- ? localStorage.getItem("aml-base-url")
+ ? localStorage.getItem(AML_BASE_URL_OVERRIDE_KEY)
: undefined;
let result: string;
@@ -144,7 +192,7 @@ function getInitialBackendBaseURL(
}
try {
return canonicalizeBaseUrl(result);
- } catch (e) {
+ } catch {
// fall back
return canonicalizeBaseUrl(window.origin);
}
@@ -154,8 +202,13 @@ const evictExchangeSwrCache: CacheEvictor<TalerExchangeCacheEviction> = {
async notifySuccess(op) {
switch (op) {
case TalerExchangeCacheEviction.MAKE_AML_DECISION: {
- await revalidateAccountDecisions();
- await revalidateAccountInformation();
+ await Promise.all([
+ revalidateAccountDecisions(),
+ revalidateAccountInformation(),
+ revalidateAmlAccounts(),
+ revalidateCurrentLegitimizations(),
+ revalidateTopsServerStatistics(),
+ ]);
return;
}
case TalerExchangeCacheEviction.UPLOAD_KYC_FORM: {
diff --git a/packages/taler-exchange-aml-webui/src/ExchangeAmlFrame.tsx b/packages/taler-exchange-aml-webui/src/ExchangeAmlFrame.tsx
@@ -17,18 +17,15 @@ import {
Footer,
Header,
ToastBanner,
- useCommonPreferences,
useRenderErrorReport,
useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { ComponentChildren, VNode, h } from "preact";
-import { useUiSettingsContext } from "./context/ui-settings.js";
+import { useEffect, useRef } from "preact/hooks";
+import talerLogoDark from "../../../contrib/taler-assets/svg/logo/taler-logo-dark.svg";
import { OfficerState } from "./hooks/officer.js";
-import {
- getAllBooleanPreferences,
- getLabelForPreferences,
- usePreferences,
-} from "./hooks/preferences.js";
+
+const talerLogoUrl = new URL(talerLogoDark, import.meta.url).href;
const GIT_HASH = typeof __GIT_HASH__ !== "undefined" ? __GIT_HASH__ : undefined;
const VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : undefined;
@@ -39,133 +36,136 @@ export function ExchangeAmlFrame({
children,
officer,
NavigationBar: Navigation,
+ modal,
}: {
officer?: OfficerState;
children?: ComponentChildren;
NavigationBar?: () => VNode;
+ modal?: ComponentChildren;
}): VNode {
const { i18n } = useTranslationContext();
+ const dialogRef = useRef<HTMLDialogElement>(null);
+ const hasModal = Boolean(modal);
+ const hasNavigation = Navigation !== undefined;
+ useEffect(() => {
+ const dialog = dialogRef.current;
+ if (!hasModal || !dialog) return;
+ let active = true;
+ queueMicrotask(() => {
+ if (active && dialog.isConnected && !dialog.open) dialog.showModal();
+ });
+ return () => {
+ active = false;
+ if (dialog.open) dialog.close();
+ };
+ }, [hasModal]);
- const [{ showDebugInfo }, update] = useCommonPreferences();
const failed = useRenderErrorReport({
hash: __GIT_HASH__,
version: __VERSION__,
});
- const [preferences, updatePreferences] = usePreferences();
- const settings = useUiSettingsContext();
-
return (
- <div class="min-h-full flex flex-col m-0 bg-slate-200 min-h-screen">
- <div class="bg-indigo-600 pb-32">
+ <div class="aml-app min-h-screen flex flex-col m-0 bg-background text-onBackground dark:bg-darkBackground dark:text-darkOnBackground">
+ <div class="bg-primary dark:bg-darkPrimaryContainer">
<Header
- title="Exchange"
- iconLinkURL={settings.backendBaseURL ?? "#"}
- onLogout={
- officer?.state !== "ready"
- ? undefined
- : () => {
+ title="Exchange AML"
+ logoSrc={talerLogoUrl}
+ iconLinkURL="#/dashboard"
+ onLogout={undefined}
+ sites={[]}
+ showMenu={false}
+ actions={
+ officer?.state === "ready" ? (
+ <button
+ type="button"
+ onClick={() => {
officer.lock();
- }
+ }}
+ aria-label={i18n.str`Lock session`}
+ class="inline-flex min-h-11 min-w-11 items-center justify-center gap-2 rounded-md border border-white/50 px-2 text-sm font-semibold text-white hover:border-white/80 hover:bg-white/15 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white md:px-3"
+ >
+ <LockIcon />
+ <span class="hidden md:inline">
+ <i18n.Translate>Lock</i18n.Translate>
+ </span>
+ </button>
+ ) : undefined
}
- sites={[]}
- >
- <li>
- <div class="text-xs font-semibold leading-6 text-gray-400">
- <i18n.Translate>Preferences</i18n.Translate>
- </div>
- <ul role="list" class="space-y-1">
- {getAllBooleanPreferences().map((set) => {
- const isOn: boolean = !!preferences[set];
- return (
- <li key={set} class="mt-2 pl-2">
- <div class="flex items-center justify-between">
- <span class="flex flex-grow flex-col">
- <span
- class="text-sm text-black font-medium leading-6 "
- id="availability-label"
- >
- {getLabelForPreferences(set, i18n)}
- </span>
- </span>
- <button
- type="button"
- data-enabled={isOn}
- class="bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2"
- role="switch"
- aria-checked="false"
- aria-labelledby="availability-label"
- aria-describedby="availability-description"
- onClick={() => {
- updatePreferences(set, !isOn);
- }}
- >
- <span
- aria-hidden="true"
- data-enabled={isOn}
- class="translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
- ></span>
- </button>
- </div>
- </li>
- );
- })}
- <li class="mt-2 pl-2">
- <div class="flex items-center justify-between">
- <span class="flex flex-grow flex-col">
- <span
- class="text-sm text-black font-medium leading-6 "
- id="availability-label"
- >
- <i18n.Translate>Show debug information</i18n.Translate>
- </span>
- </span>
- <button
- type="button"
- name={`debug switch`}
- data-enabled={showDebugInfo}
- class="bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2"
- role="switch"
- aria-checked="false"
- aria-labelledby="availability-label"
- aria-describedby="availability-description"
- onClick={() => {
- update("showDebugInfo", !showDebugInfo);
- }}
- >
- <span
- aria-hidden="true"
- data-enabled={showDebugInfo}
- class="translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
- ></span>
- </button>
- </div>
- </li>
- </ul>
- </li>
- </Header>
+ />
</div>
- <div class="fixed z-20 w-full">
- <div class="mx-auto w-4/5">
- <ToastBanner />
+ {!hasModal ? (
+ <div class="pointer-events-none fixed z-20 w-full">
+ <div class="mx-auto w-4/5 [&>*]:pointer-events-auto">
+ <ToastBanner />
+ </div>
</div>
- </div>
+ ) : undefined}
- <div class="-mt-32 flex grow ">
+ <div class="flex grow">
{Navigation === undefined ? undefined : <Navigation />}
- <div class="flex mx-auto my-4 min-w-80">
- <main class="block rounded-lg bg-white px-5 py-6 shadow min-w-xl">
- {!failed ? children : undefined}
- </main>
+ <div
+ class={`flex min-w-0 flex-1 flex-col ${
+ hasNavigation
+ ? "pb-[calc(4.5rem+env(safe-area-inset-bottom))] sm:pb-0"
+ : ""
+ }`}
+ >
+ <div class="mx-auto my-4 w-full min-w-0 max-w-screen-2xl grow px-3 sm:px-5">
+ <main class="block w-full min-w-0 px-4 py-5 sm:px-6">
+ {!failed ? children : undefined}
+ </main>
+ </div>
+ <Footer
+ testingUrlKey="aml-base-url"
+ GIT_HASH={GIT_HASH}
+ VERSION={VERSION}
+ variant="compact"
+ />
</div>
</div>
- <Footer
- testingUrlKey="aml-base-url"
- GIT_HASH={GIT_HASH}
- VERSION={VERSION}
- />
+ {hasModal ? (
+ <dialog
+ ref={dialogRef}
+ aria-modal="true"
+ aria-labelledby="session-locked-title"
+ class="fixed inset-0 z-50 size-auto max-h-none max-w-none overflow-y-auto bg-transparent p-4 backdrop:bg-black/60"
+ {...({
+ onCancel: (event: Event) => event.preventDefault(),
+ } as object)}
+ >
+ <div class="flex min-h-full items-center justify-center">
+ <section class="w-full max-w-xl rounded-xl bg-white p-6 text-onBackground shadow-xl dark:bg-gray-900 dark:text-darkOnBackground">
+ <div class="space-y-4">
+ <ToastBanner compact />
+ {modal}
+ </div>
+ </section>
+ </div>
+ </dialog>
+ ) : undefined}
</div>
);
}
+
+function LockIcon(): VNode {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ viewBox="0 0 24 24"
+ stroke-width="1.75"
+ stroke="currentColor"
+ class="h-5 w-5 shrink-0"
+ aria-hidden="true"
+ >
+ <path
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ d="M16.5 10.5V6.75a4.5 4.5 0 0 0-9 0v3.75m-.75 0h10.5A2.25 2.25 0 0 1 19.5 12.75v6A2.25 2.25 0 0 1 17.25 21H6.75a2.25 2.25 0 0 1-2.25-2.25v-6a2.25 2.25 0 0 1 2.25-2.25Z"
+ />
+ </svg>
+ );
+}
diff --git a/packages/taler-exchange-aml-webui/src/Routing.test.tsx b/packages/taler-exchange-aml-webui/src/Routing.test.tsx
@@ -0,0 +1,105 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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 assert from "node:assert/strict";
+import test from "node:test";
+import { setupI18n } from "@gnu-taler/taler-util";
+import { h, render } from "preact";
+import { Router } from "wouter-preact";
+import { memoryLocation } from "wouter-preact/memory-location";
+
+setupI18n("en", {});
+
+async function installDom() {
+ const happyDomPackage = "happy-dom";
+ const { Window } = await import(happyDomPackage);
+ const window = new Window({ url: "https://aml.example/" });
+ for (const [key, value] of Object.entries({
+ window,
+ document: window.document,
+ navigator: window.navigator,
+ Node: window.Node,
+ Element: window.Element,
+ Event: window.Event,
+ HTMLElement: window.HTMLElement,
+ HTMLAnchorElement: window.HTMLAnchorElement,
+ MutationObserver: window.MutationObserver,
+ })) {
+ Object.defineProperty(globalThis, key, {
+ configurable: true,
+ writable: true,
+ value,
+ });
+ }
+ return window;
+}
+
+function linkWithText(
+ links: HTMLAnchorElement[],
+ text: string,
+): HTMLAnchorElement {
+ const link = links.find((candidate) => candidate.textContent === text);
+ assert.ok(link);
+ return link;
+}
+
+test("top-level pages are separate navigation destinations", async () => {
+ const window = await installDom();
+ const { Navigation } = await import("./Routing.js");
+ const container = window.document.createElement("div");
+ window.document.body.append(container);
+
+ function navigationLinksFor(path: string): HTMLAnchorElement[] {
+ const { hook } = memoryLocation({ path, static: true });
+ render(
+ <Router hook={hook}>
+ <Navigation />
+ </Router>,
+ container as unknown as Element,
+ );
+ return Array.from(container.querySelectorAll("a"));
+ }
+
+ let links = navigationLinksFor("/accounts");
+ assert.deepEqual(
+ links.map((link) => link.textContent),
+ [
+ "Dashboard",
+ "Accounts",
+ "Find account",
+ "Transfers",
+ "AML configuration",
+ "Session",
+ ],
+ );
+ assert.equal(linkWithText(links, "Accounts").dataset.selected, "true");
+ assert.equal(linkWithText(links, "Find account").dataset.selected, "false");
+
+ links = navigationLinksFor("/search");
+ assert.equal(linkWithText(links, "Accounts").dataset.selected, "false");
+ assert.equal(linkWithText(links, "Find account").dataset.selected, "true");
+
+ links = navigationLinksFor("/info");
+ assert.equal(
+ linkWithText(links, "AML configuration").dataset.selected,
+ "true",
+ );
+ assert.equal(linkWithText(links, "Accounts").dataset.selected, "false");
+
+ render(null, container as unknown as Element);
+ container.remove();
+ await window.happyDOM.abort();
+});
diff --git a/packages/taler-exchange-aml-webui/src/Routing.tsx b/packages/taler-exchange-aml-webui/src/Routing.tsx
@@ -16,373 +16,462 @@
import {
decodeCrockFromURI,
+ encodeCrockForURI,
+ AsyncButton,
+ Attention,
ErrorLoading,
FailLoading,
Loading,
- urlPattern,
- useCurrentLocation,
- useNavigationContext,
+ useExchangeApiContext,
useTranslationContext,
} from "@gnu-taler/web-util/browser";
-import { Fragment, h, VNode } from "preact";
+import { h, VNode } from "preact";
+import { useEffect } from "preact/hooks";
+import { Link, Redirect, Route, Switch, useLocation } from "wouter-preact";
import {
assertUnreachable,
encodeCrock,
HttpStatusCode,
+ LibtoolVersion,
Paytos,
TalerError,
+ TalerErrorCode,
} from "@gnu-taler/taler-util";
-import { useEffect } from "preact/hooks";
-import { HandleSessionNotReady } from "./components/HandleAccountNotReady.js";
+import { CreateSession } from "./components/CreateSession.js";
+import { AccountCaseShell } from "./components/AccountCaseShell.js";
+import { isWalletPaytoType } from "./components/AccountBadges.js";
+import { AccessCheckStatus } from "./components/AccessCheckStatus.js";
+import { OfficerEnrollment } from "./components/OfficerEnrollment.js";
+import { OfficerAccessFailure } from "./components/OfficerAccessFailure.js";
+import { UnlockSession } from "./components/UnlockSession.js";
import { ExchangeAmlFrame } from "./ExchangeAmlFrame.js";
+import { useUiSettingsContext } from "./context/ui-settings.js";
import {
- clearDecisionDraft,
- DecisionRequestProvider,
- readDecisionDraftTarget,
-} from "./hooks/decision-request.js";
+ OfficerInfoProvider,
+ useOfficerInfoContext,
+} from "./context/officer-info.js";
+import { DecisionRequestProvider } from "./hooks/decision-request.js";
import { useAccountActiveDecision } from "./hooks/decisions.js";
import { OfficerReady, useOfficer } from "./hooks/officer.js";
+import { useAmlOfficerInfo, useServerMeasures } from "./hooks/server-info.js";
import { AccountDetails } from "./pages/AccountDetails.js";
-import {
- AccountList,
- HomeIcon,
- PeopleIcon,
- SearchIcon,
- TransfersIcon,
-} from "./pages/AccountList.js";
+import { AccountDecisionHistory } from "./pages/AccountDecisionHistory.js";
+import { AccountList, PeopleIcon, TransfersIcon } from "./pages/AccountList.js";
import { Dashboard } from "./pages/Dashboard.js";
import { DecisionWizard, WizardSteps } from "./pages/DecisionWizard.js";
+import { Developer } from "./pages/Developer.js";
+import { Info } from "./pages/Info.js";
import { Profile } from "./pages/Profile.js";
import { Search } from "./pages/Search.js";
import { ShowCollectedInfo } from "./pages/ShowCollectedInfo.js";
import { Transfers } from "./pages/Transfers.js";
+import {
+ effectiveRuleLimits,
+ initialRuleDraft,
+} from "./utils/rule-defaults.js";
+
+const AML_OFFICER_RESOURCE_PROTOCOL = "40:0:0";
+
+const routes = {
+ dev: "/dev",
+ profile: "/profile",
+ dashboard: "/dashboard",
+ accounts: "/accounts",
+ search: "/search",
+ transfers: "/transfers",
+ info: "/info",
+ account: (cid: string) => `/account/${cid}`,
+ accountTransfers: (cid: string) => `/account/${cid}/transfers`,
+ accountDecisionHistory: (cid: string) => `/account/${cid}/history`,
+ showCollectedInfo: (cid: string, rowId: string) =>
+ `/show-collected/${cid}/${rowId}`,
+ decide: (cid: string, payto: string, step?: string) =>
+ `/decide/${cid}/${payto}${step ? `/${step}` : ""}`,
+};
-const TALER_SCREEN_ID = 126;
+function hashRoute(path: string): string {
+ return `#${path}`;
+}
+
+function currentHashParams(): URLSearchParams {
+ const queryStart = window.location.hash.indexOf("?");
+ const params = new URLSearchParams(window.location.search);
+ const hashParams = new URLSearchParams(
+ queryStart === -1 ? "" : window.location.hash.slice(queryStart + 1),
+ );
+ hashParams.forEach((value, key) => params.set(key, value));
+ return params;
+}
export function Routing(): VNode {
const session = useOfficer();
+ const [location] = useLocation();
if (session.state === "ready") {
+ return <OfficerAccessGate officer={session} />;
+ }
+ if (session.state === "locked") {
return (
- <ExchangeAmlFrame officer={session} NavigationBar={Navigation}>
- <PrivateRouting officer={session} />
+ <ExchangeAmlFrame officer={session}>
+ <UnlockSession officer={session} />
+ </ExchangeAmlFrame>
+ );
+ }
+ if (location === routes.dev) {
+ return (
+ <ExchangeAmlFrame officer={session}>
+ <Developer />
</ExchangeAmlFrame>
);
}
return (
- <ExchangeAmlFrame NavigationBar={Navigation}>
- <PublicRounting />
+ <ExchangeAmlFrame officer={session}>
+ <CreateSession officer={session} />
</ExchangeAmlFrame>
);
}
-const publicPages = {
- config: urlPattern(/\/config/, () => "#/config"),
- login: urlPattern(/\/login/, () => "#/login"),
-};
-
-function PublicRounting(): VNode {
+export function OfficerAccessGate({
+ officer,
+}: {
+ officer: OfficerReady;
+}): VNode {
const { i18n } = useTranslationContext();
- const location = useCurrentLocation(publicPages);
- const session = useOfficer();
+ const settings = useUiSettingsContext();
+ const { config, lib } = useExchangeApiContext();
+ const [location] = useLocation();
+ const compatible = LibtoolVersion.isCompatible(
+ AML_OFFICER_RESOURCE_PROTOCOL,
+ config.config.version,
+ );
+ const access = useAmlOfficerInfo(compatible);
+ const officerInfo =
+ access.result &&
+ !(access.result instanceof TalerError) &&
+ access.result.type === "ok"
+ ? access.result.body
+ : undefined;
+ useEffect(() => {
+ if (officerInfo) officer.rememberInfo?.(officerInfo);
+ }, [officer, officerInfo]);
+ const developerRequested = location === routes.dev;
- switch (location.name) {
- case undefined: {
- if (session.state !== "ready") {
- return <HandleSessionNotReady officer={session} />;
- } else {
- return <div />;
- }
- }
- case "config": {
- return (
- <Fragment>
- <div class="sm:mx-auto sm:w-full sm:max-w-sm">
- <h2 class="text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">{i18n.str`Welcome to the exchange configuration`}</h2>
- </div>
- </Fragment>
- );
- }
- case "login": {
- return (
- <Fragment>
- <div class="sm:mx-auto sm:w-full sm:max-w-sm">
- <h2 class="text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">{i18n.str`Welcome to the exchange configuration`}</h2>
- </div>
- </Fragment>
- );
- }
- default:
- assertUnreachable(location);
+ if (
+ developerRequested &&
+ (access.result === undefined ||
+ access.result instanceof TalerError ||
+ access.result.type === "fail")
+ ) {
+ return (
+ <ExchangeAmlFrame officer={officer}>
+ <Developer />
+ </ExchangeAmlFrame>
+ );
}
-}
-const privatePages = {
- profile: urlPattern(/\/profile/, () => "#/profile"),
- dashboard: urlPattern(/\/dashboard/, () => "#/dashboard"),
- statsDownload: urlPattern(/\/download-stats/, () => "#/download-stats"),
- /**
- * This 4 URL could be only one with multiple params
- */
- decideWithStep: urlPattern<{ cid: string; step: string }>(
- /\/decide\/(?<cid>[a-zA-Z0-9]+)\/(?<step>[a-z]+)/,
- ({ cid, step }) => `#/decide/${cid}/${step}`,
- ),
- decide: urlPattern<{ cid: string }>(
- /\/decide\/(?<cid>[a-zA-Z0-9]+)/,
- ({ cid }) => `#/decide/${cid}`,
- ),
- decideNewWithStep: urlPattern<{ cid: string; payto: string; step: string }>(
- /\/decide_new\/(?<cid>[a-zA-Z0-9]+)\/(?<payto>[a-zA-Z0-9]+)\/(?<step>[a-z]+)/,
- ({ cid, payto, step }) => `#/decide_new/${cid}/${payto}/${step}`,
- ),
- decideNew: urlPattern<{ cid: string; payto: string }>(
- /\/decide_new\/(?<cid>[a-zA-Z0-9]+)\/(?<payto>[a-zA-Z0-9]+)/,
- ({ cid, payto }) => `#/decide_new/${cid}/${payto}`,
- ),
- showCollectedInfo: urlPattern<{ cid: string; rowId: string }>(
- /\/show-collected\/(?<cid>[a-zA-Z0-9]+)\/(?<rowId>[0-9]+)/,
- ({ cid, rowId }) => `#/show-collected/${cid}/${rowId}`,
- ),
- search: urlPattern(/\/search/, () => "#/search"),
- transfersForAccount: urlPattern<{ cid: string }>(
- /\/transfers\/(?<cid>[a-zA-Z0-9]+)/,
- ({ cid }) => `#/transfers/${cid}`,
- ),
- transfers: urlPattern(/\/transfers/, () => "#/transfers"),
- accounts: urlPattern(/\/accounts/, () => "#/accounts"),
- account: urlPattern<{ cid: string }>(
- /\/account\/(?<cid>[a-zA-Z0-9]+)/,
- ({ cid }) => `#/account/${cid}`,
- ),
-};
+ if (!compatible) {
+ return (
+ <ExchangeAmlFrame officer={officer}>
+ <div class="space-y-4">
+ <Attention
+ type="danger"
+ title={i18n.str`This exchange is not compatible with the AML WebUI.`}
+ >
+ <i18n.Translate>
+ Officer identity and permissions require exchange protocol v40 or
+ newer.
+ </i18n.Translate>
+ </Attention>
+ <Link
+ href={routes.dev}
+ class="inline-flex rounded-md border border-outline px-4 py-2 text-sm font-semibold"
+ >
+ <i18n.Translate>Development settings</i18n.Translate>
+ </Link>
+ </div>
+ </ExchangeAmlFrame>
+ );
+ }
-function PrivateRouting({ officer }: { officer: OfficerReady }): VNode {
- const { navigateTo } = useNavigationContext();
- const location = useCurrentLocation(privatePages);
- useEffect(() => {
- if (location.name === undefined) {
- navigateTo(privatePages.dashboard.url({}));
- }
- }, [location]);
- switch (location.name) {
- case undefined: {
- return <Fragment />;
- }
- case "profile": {
- return <Profile />;
- }
- case "decide": {
- return (
- <DecisionPage
- officer={officer}
- account={location.values.cid}
- formId={
- location.params.formId ? location.params.formId[0] : undefined
- }
- onMove={(step) => {
- if (!step) {
- if (location.values.cid) {
- navigateTo(
- privatePages.account.url({ cid: location.values.cid }),
- );
- } else {
- navigateTo(privatePages.dashboard.url({}));
- }
- } else {
- navigateTo(
- privatePages.decideWithStep.url({
- cid: location.values.cid,
- step,
- }),
- );
- }
- }}
- />
- );
- }
- case "decideWithStep": {
- return (
- <DecisionPage
- officer={officer}
- account={location.values.cid}
- formId={
- location.params.formId ? location.params.formId[0] : undefined
- }
- step={location.values.step as WizardSteps}
- onMove={(step) => {
- if (!step) {
- if (location.values.cid) {
- navigateTo(
- privatePages.account.url({ cid: location.values.cid }),
- );
- } else {
- navigateTo(privatePages.dashboard.url({}));
- }
- } else {
- navigateTo(
- privatePages.decideWithStep.url({
- cid: location.values.cid,
- step,
- }),
- );
- }
- }}
- />
- );
- }
- case "decideNew": {
- return (
- <DecisionPage
- officer={officer}
- account={location.values.cid}
- newPayto={decodeCrockFromURI(location.values.payto)}
- formId={
- location.params.formId ? location.params.formId[0] : undefined
- }
- onMove={(step) => {
- if (!step) {
- if (location.values.cid) {
- navigateTo(
- privatePages.account.url({ cid: location.values.cid }),
- );
- } else {
- navigateTo(privatePages.dashboard.url({}));
- }
- } else {
- navigateTo(
- privatePages.decideNewWithStep.url({
- cid: location.values.cid,
- payto: location.values.payto,
- step,
- }),
- );
- }
- }}
- />
- );
- }
- case "decideNewWithStep": {
- return (
- <DecisionPage
- account={location.values.cid}
- officer={officer}
- newPayto={decodeCrockFromURI(location.values.payto)}
- formId={
- location.params.formId ? location.params.formId[0] : undefined
+ if (access.result === undefined) {
+ return (
+ <ExchangeAmlFrame officer={officer}>
+ <AccessCheckStatus
+ title={<i18n.Translate>Checking officer access</i18n.Translate>}
+ description={
+ <i18n.Translate>
+ Verifying that this public key is enrolled by the exchange.
+ </i18n.Translate>
}
- step={location.values.step as WizardSteps}
- onMove={(step) => {
- if (!step) {
- if (location.values.cid) {
- navigateTo(
- privatePages.account.url({ cid: location.values.cid }),
- );
- } else {
- navigateTo(privatePages.dashboard.url({}));
- }
- } else {
- navigateTo(
- privatePages.decideNewWithStep.url({
- cid: location.values.cid,
- payto: location.values.payto,
- step,
- }),
- );
- }
- }}
/>
- );
- }
- case "account": {
+ </ExchangeAmlFrame>
+ );
+ }
+ if (access.result instanceof TalerError) {
+ return (
+ <ExchangeAmlFrame officer={officer}>
+ <div class="space-y-4">
+ <ErrorLoading
+ title={i18n.str`Failed to check AML officer access.`}
+ error={access.result}
+ />
+ <AsyncButton
+ onClick={access.revalidate}
+ class="rounded-md bg-primary px-4 py-2 text-sm font-semibold text-onPrimary"
+ >
+ <i18n.Translate>Retry access check</i18n.Translate>
+ </AsyncButton>
+ <Link
+ href={routes.dev}
+ class="inline-flex rounded-md border border-outline px-4 py-2 text-sm font-semibold"
+ >
+ <i18n.Translate>Development settings</i18n.Translate>
+ </Link>
+ </div>
+ </ExchangeAmlFrame>
+ );
+ }
+ if (access.result.type === "fail") {
+ if (
+ access.result.case === HttpStatusCode.Forbidden &&
+ access.result.detail?.code !==
+ TalerErrorCode.EXCHANGE_GENERIC_AML_OFFICER_GET_SIGNATURE_INVALID
+ ) {
+ const url = new URL("./", lib.exchange.baseUrl);
+ const signupEmail = settings.signupEmail ?? `aml-signup@${url.hostname}`;
return (
- <AccountDetails
- account={location.values.cid}
- routeToShowTransfers={privatePages.transfersForAccount}
- routeToShowCollectedInfo={privatePages.showCollectedInfo}
- onNewDecision={() => {
- clearDecisionDraft(officer.session.id, location.values.cid);
- navigateTo(
- privatePages.decide.url({
- cid: location.values.cid,
- }),
- );
- }}
- />
+ <ExchangeAmlFrame officer={officer}>
+ <OfficerEnrollment
+ officer={officer}
+ signupEmail={signupEmail}
+ onRetry={access.revalidate}
+ />
+ </ExchangeAmlFrame>
);
}
- case "accounts": {
- return <AccountList routeToAccountById={privatePages.account} />;
- }
- case "search": {
- return (
+ const invalidSignature =
+ access.result.case === HttpStatusCode.Forbidden &&
+ access.result.detail?.code ===
+ TalerErrorCode.EXCHANGE_GENERIC_AML_OFFICER_GET_SIGNATURE_INVALID;
+ return (
+ <ExchangeAmlFrame officer={officer}>
+ <div class="space-y-4">
+ <OfficerAccessFailure
+ operation={access.result}
+ officer={officer}
+ invalidSignature={invalidSignature}
+ onRetry={access.revalidate}
+ />
+ <Link
+ href={routes.dev}
+ class="inline-flex rounded-md border border-outline px-4 py-2 text-sm font-semibold"
+ >
+ <i18n.Translate>Development settings</i18n.Translate>
+ </Link>
+ </div>
+ </ExchangeAmlFrame>
+ );
+ }
+ return (
+ <OfficerInfoProvider value={access.result.body}>
+ <ExchangeAmlFrame officer={officer} NavigationBar={Navigation}>
+ {access.result.body.read_only ? <ReadOnlyBanner /> : undefined}
+ <PrivateRouting officer={officer} />
+ </ExchangeAmlFrame>
+ </OfficerInfoProvider>
+ );
+}
+
+function ReadOnlyBanner(): VNode {
+ const { i18n } = useTranslationContext();
+ return (
+ <Attention type="info" title={i18n.str`Read-only officer access`}>
+ <i18n.Translate>
+ You can review AML information, but this officer key cannot submit
+ decisions.
+ </i18n.Translate>
+ </Attention>
+ );
+}
+
+const routeToAccountById = ({ cid }: { cid: string }) =>
+ hashRoute(routes.account(cid));
+const routeToShowCollectedInfo = ({
+ cid,
+ rowId,
+}: {
+ cid: string;
+ rowId: string;
+}) => hashRoute(routes.showCollectedInfo(cid, rowId));
+
+function PrivateRouting({ officer }: { officer: OfficerReady }): VNode {
+ const { i18n } = useTranslationContext();
+ const [, navigate] = useLocation();
+ const officerInfo = useOfficerInfoContext();
+ const fullPaytoParam = (): string | undefined => {
+ const encoded = currentHashParams().get("payto");
+ return encoded ? decodeCrockFromURI(encoded) : undefined;
+ };
+ const renderAccountCase = (
+ account: string,
+ activeView: "overview" | "transfers" | "history",
+ content: VNode,
+ ): VNode => (
+ <AccountCaseShell
+ account={account}
+ fullPayto={fullPaytoParam()}
+ activeView={activeView}
+ routeToAccounts={routes.accounts}
+ routeToOverview={routes.account(account)}
+ routeToTransfers={routes.accountTransfers(account)}
+ routeToHistory={routes.accountDecisionHistory(account)}
+ onNewDecision={(fullPayto) =>
+ navigate(routes.decide(account, encodeCrockForURI(fullPayto)))
+ }
+ >
+ {content}
+ </AccountCaseShell>
+ );
+ const renderDecision = (
+ params: { cid: string; payto: string },
+ currentStep?: string,
+ ) =>
+ officerInfo.read_only ? (
+ <div class="space-y-4">
+ <Attention type="warning" title={i18n.str`Read-only officer access`}>
+ <i18n.Translate>
+ This officer key cannot create or submit AML decisions.
+ </i18n.Translate>
+ </Attention>
+ <Link
+ href={routes.account(params.cid)}
+ class="inline-flex rounded-md border border-outline px-4 py-2 text-sm font-semibold"
+ >
+ <i18n.Translate>Return to account</i18n.Translate>
+ </Link>
+ </div>
+ ) : (
+ <DecisionPage
+ officer={officer}
+ account={params.cid}
+ fullPayto={decodeCrockFromURI(params.payto)}
+ formId={currentHashParams().get("formId") ?? undefined}
+ step={currentStep as WizardSteps | undefined}
+ onMove={(step) => {
+ navigate(
+ step
+ ? routes.decide(params.cid, params.payto, step)
+ : routes.account(params.cid),
+ );
+ }}
+ />
+ );
+
+ return (
+ <Switch>
+ <Route path={routes.profile} component={Profile} />
+ <Route path={routes.dev} component={Developer} />
+ <Route path="/decide/:cid/:payto/:step">
+ {(params) => renderDecision(params, params.step)}
+ </Route>
+ <Route path="/decide/:cid/:payto">
+ {(params) => renderDecision(params)}
+ </Route>
+ <Route path="/account/:cid/history">
+ {(params) =>
+ renderAccountCase(
+ params.cid,
+ "history",
+ <AccountDecisionHistory
+ account={params.cid}
+ routeToShowCollectedInfo={routeToShowCollectedInfo}
+ />,
+ )
+ }
+ </Route>
+ <Route path="/account/:cid/transfers">
+ {(params) =>
+ renderAccountCase(
+ params.cid,
+ "transfers",
+ <Transfers
+ routeToAccountById={routeToAccountById}
+ account={params.cid}
+ embedded
+ />,
+ )
+ }
+ </Route>
+ <Route path="/account/:cid">
+ {(params) =>
+ renderAccountCase(
+ params.cid,
+ "overview",
+ <AccountDetails
+ account={params.cid}
+ fullPayto={fullPaytoParam()}
+ routeToShowCollectedInfo={routeToShowCollectedInfo}
+ />,
+ )
+ }
+ </Route>
+ <Route path={routes.accounts}>
+ <AccountList routeToAccountById={routeToAccountById} />
+ </Route>
+ <Route path={routes.search}>
<Search
- routeToAccountById={privatePages.account}
+ routeToAccountById={routeToAccountById}
onNewDecision={(account, payto) => {
- clearDecisionDraft(officer.session.id, account);
- navigateTo(
- privatePages.decideNew.url({
- cid: account,
- payto: payto,
- }),
- );
+ navigate(routes.decide(account, payto));
}}
/>
- );
- }
- case "statsDownload": {
- return <div>not yet implemented</div>;
- }
- case "dashboard": {
- return <Dashboard />;
- }
- case "transfers": {
- return <Transfers routeToAccountById={privatePages.account} />;
- }
- case "transfersForAccount": {
- return (
- <Transfers
- routeToAccountById={privatePages.account}
- account={location.values.cid}
- />
- );
- }
- case "showCollectedInfo": {
- return (
- <ShowCollectedInfo
- routeToAccountById={privatePages.account}
- routeToShowCollectedInfo={privatePages.showCollectedInfo}
- account={location.values.cid}
- rowId={Number.parseInt(location.values.rowId, 10)}
- />
- );
- }
-
- default:
- assertUnreachable(location);
- }
+ </Route>
+ <Route path={routes.dashboard} component={Dashboard} />
+ <Route path="/transfers/:cid">
+ {(params) => <Redirect to={routes.accountTransfers(params.cid)} />}
+ </Route>
+ <Route path={routes.transfers}>
+ <Transfers routeToAccountById={routeToAccountById} />
+ </Route>
+ <Route path={routes.info} component={Info} />
+ <Route path="/show-collected/:cid/:rowId">
+ {(params) => (
+ <ShowCollectedInfo
+ routeToAccountById={routeToAccountById}
+ routeToShowCollectedInfo={routeToShowCollectedInfo}
+ account={params.cid}
+ rowId={Number.parseInt(params.rowId, 10)}
+ />
+ )}
+ </Route>
+ <Route>
+ <Redirect to={routes.dashboard} />
+ </Route>
+ </Switch>
+ );
}
function DecisionPage({
account,
- newPayto,
+ fullPayto,
step,
formId,
onMove,
officer,
}: {
account: string;
- newPayto?: string;
+ fullPayto: string;
step?: WizardSteps;
formId: string | undefined;
officer: OfficerReady;
onMove: (n: WizardSteps | undefined) => void;
}): VNode {
const { i18n } = useTranslationContext();
- const active = useAccountActiveDecision(newPayto ? undefined : account);
+ const active = useAccountActiveDecision(account);
+ const measures = useServerMeasures();
- if (!newPayto && active === undefined) return <Loading />;
+ if (active === undefined) return <Loading />;
if (active instanceof TalerError) {
return (
<ErrorLoading
@@ -421,111 +510,165 @@ function DecisionPage({
}
const original = active?.type === "ok" ? active.body : undefined;
- const storedTarget = readDecisionDraftTarget(officer.session.id, account);
- const targetPayto =
- newPayto ?? original?.full_payto ?? storedTarget?.fullPayto;
- if (targetPayto) {
- const parsed = Paytos.fromString(targetPayto);
- const targetHash =
- parsed.tag === "ok"
- ? encodeCrock(Paytos.hashFull(Paytos.toNormalizedString(parsed.value)))
- : undefined;
- if (targetHash !== account) {
+ const targetPayto = fullPayto;
+ const parsed = Paytos.fromString(fullPayto);
+ const targetHash =
+ parsed.tag === "ok"
+ ? encodeCrock(Paytos.hashFull(Paytos.toNormalizedString(parsed.value)))
+ : undefined;
+ if (parsed.tag !== "ok" || targetHash !== account) {
+ return (
+ <div class="p-4 text-red-700">
+ <i18n.Translate>
+ The payto URI does not belong to this account. Return to the account
+ search and start the decision again.
+ </i18n.Translate>
+ </div>
+ );
+ }
+
+ let initialLimits = original?.limits;
+ if (initialLimits === undefined) {
+ if (measures === undefined) return <Loading />;
+ if (measures instanceof TalerError) {
return (
- <div class="p-4 text-red-700">
- <i18n.Translate>
- The payto URI does not belong to this account. Return to the account
- search and start the decision again.
- </i18n.Translate>
- </div>
+ <ErrorLoading
+ title={i18n.str`Failed to load available measures.`}
+ error={measures}
+ />
);
}
- }
- if (!original && !targetPayto) {
- return (
- <div class="p-4">
- <p class="text-red-700">
- <i18n.Translate>
- This account has no active decision and its payto URI is unknown.
- Start the decision from the account search so the account type can
- be determined safely.
- </i18n.Translate>
- </p>
- <button
- class="mt-4 rounded-md bg-indigo-700 px-3 py-2 text-sm text-white"
- onClick={() => onMove(undefined)}
- >
- <i18n.Translate>Return to account</i18n.Translate>
- </button>
- </div>
+ if (measures.type === "fail") {
+ return (
+ <FailLoading
+ operation={measures}
+ title={i18n.str`Failed to load available measures.`}
+ translate={(failure) => {
+ switch (failure.case) {
+ case HttpStatusCode.Forbidden:
+ return (
+ <i18n.Translate>
+ The officer session is invalid.
+ </i18n.Translate>
+ );
+ case HttpStatusCode.NotFound:
+ return (
+ <i18n.Translate>
+ The measures endpoint was not found.
+ </i18n.Translate>
+ );
+ case HttpStatusCode.Conflict:
+ return (
+ <i18n.Translate>
+ The officer session is disabled.
+ </i18n.Translate>
+ );
+ default:
+ return assertUnreachable(failure.case);
+ }
+ }}
+ />
+ );
+ }
+ initialLimits = effectiveRuleLimits(
+ undefined,
+ measures.body,
+ isWalletPaytoType(parsed.value.targetType),
);
}
return (
<DecisionRequestProvider
key={`${officer.session.id}:${account}`}
- target={{
- officerId: officer.session.id,
- account,
- fullPayto: targetPayto,
- }}
initial={{
original,
- custom_measures: original?.limits.custom_measures,
+ ...initialRuleDraft(initialLimits),
}}
>
- <DecisionWizard
+ <AccountCaseShell
+ presentation="decision"
account={account}
- newPayto={targetPayto}
- step={step}
- formId={formId}
- onMove={onMove}
- officer={officer}
- />
+ fullPayto={targetPayto}
+ routeToAccount={routes.account(account)}
+ newAccount={!original}
+ >
+ <DecisionWizard
+ account={account}
+ fullPayto={targetPayto}
+ newAccount={!original}
+ step={step}
+ formId={formId}
+ onMove={onMove}
+ officer={officer}
+ />
+ </AccountCaseShell>
</DecisionRequestProvider>
);
}
-function Navigation(): VNode {
+export function Navigation(): VNode {
const { i18n } = useTranslationContext();
const pageList = [
{
- route: privatePages.dashboard,
- Icon: PeopleIcon,
+ route: routes.dashboard,
+ Icon: DashboardIcon,
label: i18n.str`Dashboard`,
+ selected: (location: string) => location === routes.dashboard,
},
- { route: privatePages.accounts, Icon: HomeIcon, label: i18n.str`Accounts` },
{
- route: privatePages.transfers,
+ route: routes.accounts,
+ Icon: PeopleIcon,
+ label: i18n.str`Accounts`,
+ selected: (location: string) =>
+ location === routes.accounts || location.startsWith("/account/"),
+ },
+ {
+ route: routes.search,
+ Icon: SearchIcon,
+ label: i18n.str`Find account`,
+ selected: (location: string) => location === routes.search,
+ },
+ {
+ route: routes.transfers,
Icon: TransfersIcon,
label: i18n.str`Transfers`,
+ selected: (location: string) => location.startsWith("/transfers"),
},
{
- route: privatePages.search,
- Icon: SearchIcon,
- label: i18n.str`Search`,
+ route: routes.info,
+ Icon: ConfigurationIcon,
+ label: i18n.str`AML configuration`,
+ selected: (location: string) => location === routes.info,
+ },
+ {
+ route: routes.profile,
+ Icon: SessionIcon,
+ label: i18n.str`Session`,
+ selected: (location: string) => location === routes.profile,
},
- { route: privatePages.profile, Icon: PeopleIcon, label: i18n.str`Profile` },
];
- const { path } = useNavigationContext();
+ const [location] = useLocation();
return (
- <div class="hidden sm:block min-w-min bg-indigo-600 divide-y rounded-r-lg divide-cyan-800 overflow-y-auto overflow-x-clip">
- <nav class="flex flex-1 flex-col mx-4 mt-4 mb-2">
- <ul role="list" class="flex flex-1 flex-col gap-y-7">
+ <div class="fixed inset-x-0 bottom-0 z-30 border-t border-white/20 bg-primary pb-[max(.5rem,env(safe-area-inset-bottom))] pt-1 shadow-[0_-2px_8px_rgba(15,23,42,.16)] sm:static sm:z-auto sm:w-40 sm:shrink-0 sm:border-r sm:border-t-0 sm:border-white/20 sm:pb-0 sm:pt-0 sm:shadow-none dark:bg-darkPrimaryContainer">
+ <nav
+ aria-label={i18n.str`AML navigation`}
+ class="mx-2 flex flex-1 flex-col sm:mx-4 sm:mb-2 sm:mt-4"
+ >
+ <ul class="flex flex-1 flex-col gap-y-7">
<li>
- <ul role="list" class="-mx-2 space-y-1">
+ <ul class="flex justify-around sm:-mx-2 sm:block sm:space-y-1">
{pageList.map((p, idx) => {
if (!p) return undefined;
return (
- <li key={idx}>
- <a
- href={p.route.url({})}
- data-selected={path == p.route.url({})}
- class="data-[selected=true]:bg-indigo-700 pr-4 data-[selected=true]:text-white text-indigo-200 hover:text-white hover:bg-indigo-700 group flex gap-x-3 rounded-md p-2 text-sm leading-6 font-semibold"
+ <li class="flex-1 sm:block" key={idx}>
+ <Link
+ href={p.route}
+ data-selected={p.selected(location)}
+ class="group flex min-h-12 flex-col items-center justify-center gap-x-3 rounded-md px-2 py-1.5 text-xs font-semibold leading-6 text-white/80 hover:bg-white/10 hover:text-white data-[selected=true]:bg-primaryContainer data-[selected=true]:text-onPrimaryContainer sm:min-h-0 sm:flex-row sm:justify-start sm:p-2 sm:text-sm"
>
{p.Icon && <p.Icon />}
- <span class="hidden md:inline">{p.label}</span>
- </a>
+ <span>{p.label}</span>
+ </Link>
</li>
);
})}
@@ -536,3 +679,88 @@ function Navigation(): VNode {
</div>
);
}
+
+function DashboardIcon(): VNode {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ viewBox="0 0 24 24"
+ stroke-width="1.5"
+ stroke="currentColor"
+ class="h-6 w-6 shrink-0"
+ aria-hidden="true"
+ >
+ <path
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ d="M3.75 3.75h6v6h-6v-6Zm10.5 0h6v6h-6v-6Zm-10.5 10.5h6v6h-6v-6Zm10.5 0h6v6h-6v-6Z"
+ />
+ </svg>
+ );
+}
+
+function SearchIcon(): VNode {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ viewBox="0 0 24 24"
+ stroke-width="1.5"
+ stroke="currentColor"
+ class="h-6 w-6 shrink-0"
+ aria-hidden="true"
+ >
+ <path
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ d="m21 21-4.35-4.35m0 0A7.5 7.5 0 1 0 6.04 6.04a7.5 7.5 0 0 0 10.61 10.61Z"
+ />
+ </svg>
+ );
+}
+
+function SessionIcon(): VNode {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ viewBox="0 0 24 24"
+ stroke-width="1.5"
+ stroke="currentColor"
+ class="h-6 w-6 shrink-0"
+ aria-hidden="true"
+ >
+ <path
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ d="M15.75 5.25a3 3 0 0 1 3 3m3 0a6 6 0 0 1-7.029 5.912c-.563-.097-1.159.026-1.563.43L10.5 17.25H8.25v2.25H6v2.25H2.25v-2.818c0-.597.237-1.17.659-1.591l6.499-6.499c.404-.404.527-1 .43-1.563A6 6 0 1 1 21.75 8.25Z"
+ />
+ </svg>
+ );
+}
+
+function ConfigurationIcon(): VNode {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ viewBox="0 0 24 24"
+ stroke-width="1.5"
+ stroke="currentColor"
+ class="h-6 w-6 shrink-0"
+ aria-hidden="true"
+ >
+ <path
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.592c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.325.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 0 1 1.37.49l1.296 2.247a1.125 1.125 0 0 1-.26 1.431l-1.003.827c-.293.241-.438.613-.43.992a6.759 6.759 0 0 1 0 .255c-.008.378.137.75.43.991l1.003.827c.424.35.534.955.26 1.431l-1.296 2.247a1.125 1.125 0 0 1-1.37.49l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 0 1-.22.128c-.331.183-.581.495-.644.869l-.213 1.281c-.09.542-.56.94-1.11.94h-2.592c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.063-.374-.313-.686-.645-.87a6.52 6.52 0 0 1-.22-.127c-.325-.196-.72-.257-1.075-.124l-1.217.456a1.125 1.125 0 0 1-1.37-.49l-1.296-2.247a1.125 1.125 0 0 1 .26-1.431l1.003-.827c.293-.241.438-.613.43-.992a6.759 6.759 0 0 1 0-.255c.008-.378-.137-.75-.43-.991l-1.003-.827a1.125 1.125 0 0 1-.26-1.431l1.296-2.247a1.125 1.125 0 0 1 1.37-.49l1.217.456c.355.133.75.072 1.076-.124.072-.044.146-.086.22-.128.331-.183.581-.495.644-.869l.213-1.281Z"
+ />
+ <path
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"
+ />
+ </svg>
+ );
+}
diff --git a/packages/taler-exchange-aml-webui/src/components/AccessCheckStatus.tsx b/packages/taler-exchange-aml-webui/src/components/AccessCheckStatus.tsx
@@ -0,0 +1,29 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import { Loading } from "@gnu-taler/web-util/browser";
+import { ComponentChildren, h, VNode } from "preact";
+
+export function AccessCheckStatus({
+ title,
+ description,
+}: {
+ title: ComponentChildren;
+ description: ComponentChildren;
+}): VNode {
+ return (
+ <div class="mx-auto max-w-xl py-10 text-center">
+ <h1 class="text-xl font-semibold text-gray-900 dark:text-gray-100">
+ {title}
+ </h1>
+ <p class="mt-2 text-sm text-gray-600 dark:text-gray-300">{description}</p>
+ <Loading />
+ </div>
+ );
+}
diff --git a/packages/taler-exchange-aml-webui/src/components/AccountBadges.test.ts b/packages/taler-exchange-aml-webui/src/components/AccountBadges.test.ts
@@ -0,0 +1,64 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+import { PaytoType, setupI18n } from "@gnu-taler/taler-util";
+import assert from "node:assert/strict";
+import test from "node:test";
+import { h, render } from "preact";
+import { AccountHeaderBadges, isWalletPaytoType } from "./AccountBadges.js";
+
+setupI18n("en", {});
+
+async function renderBadges(underInvestigation: boolean) {
+ const happyDomPackage = "happy-dom";
+ const { Window } = await import(happyDomPackage);
+ const window = new Window({ url: "https://aml.example/" });
+ for (const [key, value] of Object.entries({
+ window,
+ document: window.document,
+ Node: window.Node,
+ Element: window.Element,
+ })) {
+ Object.defineProperty(globalThis, key, {
+ configurable: true,
+ writable: true,
+ value,
+ });
+ }
+ const container = window.document.createElement("div");
+ render(
+ h(AccountHeaderBadges, { isWallet: true, underInvestigation }),
+ container as unknown as Element,
+ );
+ return { container, window };
+}
+
+test("only Taler reserve payto targets are wallet accounts", () => {
+ assert.equal(isWalletPaytoType(PaytoType.TalerReserve), true);
+ assert.equal(isWalletPaytoType(PaytoType.TalerReserveHttp), true);
+ assert.equal(isWalletPaytoType(PaytoType.IBAN), false);
+ assert.equal(isWalletPaytoType(PaytoType.Bitcoin), false);
+ assert.equal(isWalletPaytoType(undefined), false);
+});
+
+test("account header badges show investigation status only when active", async () => {
+ let view = await renderBadges(false);
+ assert.match(view.container.textContent, /Wallet account/);
+ assert.equal(
+ view.container.querySelector("[data-under-investigation]"),
+ null,
+ );
+ render(null, view.container as unknown as Element);
+ await view.window.happyDOM.abort();
+
+ view = await renderBadges(true);
+ assert.match(view.container.textContent, /Wallet account/);
+ assert.match(view.container.textContent, /Under investigation/);
+ render(null, view.container as unknown as Element);
+ await view.window.happyDOM.abort();
+});
diff --git a/packages/taler-exchange-aml-webui/src/components/AccountBadges.tsx b/packages/taler-exchange-aml-webui/src/components/AccountBadges.tsx
@@ -0,0 +1,105 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+import { PaytoType } from "@gnu-taler/taler-util";
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
+import { ComponentChildren, VNode, h } from "preact";
+
+export function isWalletPaytoType(type: PaytoType | undefined): boolean {
+ return type === PaytoType.TalerReserve || type === PaytoType.TalerReserveHttp;
+}
+
+export function AccountClassificationBadge({
+ isWallet,
+}: {
+ isWallet: boolean;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ return (
+ <span
+ data-account-classification={isWallet ? "wallet" : "bank"}
+ class="inline-flex rounded-full border border-gray-400 bg-gray-50 px-2.5 py-1 text-xs font-semibold text-gray-800 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-200"
+ >
+ {isWallet ? i18n.str`Wallet account` : i18n.str`Bank account`}
+ </span>
+ );
+}
+
+export function UnderInvestigationBadge(): VNode {
+ const { i18n } = useTranslationContext();
+ return (
+ <span
+ data-under-investigation
+ class="inline-flex rounded-full border border-amber-700 bg-amber-50 px-2.5 py-1 text-xs font-semibold text-amber-950 dark:border-amber-500 dark:bg-amber-950 dark:text-amber-100"
+ >
+ <i18n.Translate>Under investigation</i18n.Translate>
+ </span>
+ );
+}
+
+export function StatusBadge({
+ tone,
+ children,
+}: {
+ tone: "positive" | "warning" | "danger" | "neutral";
+ children: ComponentChildren;
+}): VNode {
+ const styles = {
+ positive:
+ "border-green-700 bg-green-50 text-green-900 dark:border-green-500 dark:bg-green-950 dark:text-green-100",
+ warning:
+ "border-amber-700 bg-amber-50 text-amber-950 dark:border-amber-500 dark:bg-amber-950 dark:text-amber-100",
+ danger:
+ "border-red-700 bg-red-50 text-red-900 dark:border-red-500 dark:bg-red-950 dark:text-red-100",
+ neutral:
+ "border-gray-400 bg-gray-50 text-gray-800 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-200",
+ };
+ return (
+ <span
+ class={`rounded-full border px-2.5 py-1 text-xs font-semibold ${styles[tone]}`}
+ >
+ {children}
+ </span>
+ );
+}
+
+export function AccountHeaderBadges({
+ isWallet,
+ underInvestigation,
+ highRisk = false,
+ notOpened = false,
+}: {
+ isWallet: boolean | undefined;
+ underInvestigation: boolean;
+ highRisk?: boolean;
+ notOpened?: boolean;
+}): VNode | null {
+ const { i18n } = useTranslationContext();
+ if (
+ isWallet === undefined &&
+ !underInvestigation &&
+ !highRisk &&
+ !notOpened
+ ) {
+ return null;
+ }
+ return (
+ <div class="flex flex-wrap gap-2">
+ {isWallet === undefined ? undefined : (
+ <AccountClassificationBadge isWallet={isWallet} />
+ )}
+ {notOpened ? (
+ <StatusBadge tone="neutral">{i18n.str`Not opened`}</StatusBadge>
+ ) : undefined}
+ {underInvestigation ? <UnderInvestigationBadge /> : undefined}
+ {highRisk ? (
+ <StatusBadge tone="danger">{i18n.str`High risk`}</StatusBadge>
+ ) : undefined}
+ </div>
+ );
+}
diff --git a/packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx b/packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx
@@ -0,0 +1,485 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+import {
+ CustomerAccountSummary,
+ HttpStatusCode,
+ OfficerSession,
+ Paytos,
+ Result,
+ TalerAmlProperties,
+ TalerError,
+ TranslatedString,
+ assertUnreachable,
+} from "@gnu-taler/taler-util";
+import {
+ AsyncButton,
+ CopyButton,
+ encodeCrockForURI,
+ useExchangeApiContext,
+ useNotificationContext,
+ useNotifiedOperation,
+ useTranslationContext,
+} from "@gnu-taler/web-util/browser";
+import { format } from "date-fns";
+import { ComponentChildren, VNode, createContext, h } from "preact";
+import { useContext, useEffect, useState } from "preact/hooks";
+import { Link } from "wouter-preact";
+import { useOfficerInfoContext } from "../context/officer-info.js";
+import {
+ revalidateAmlAccounts,
+ useAccountActiveDecision,
+ useAmlAccount,
+} from "../hooks/decisions.js";
+import { useOfficer } from "../hooks/officer.js";
+import { AccountHeaderBadges, isWalletPaytoType } from "./AccountBadges.js";
+import { PaytoTargetDetails, PaytoTargetType } from "./PaytoTargetDetails.js";
+import {
+ AccountLifecycleDetails,
+ AccountSummaryBadges,
+ accountIdentity,
+} from "./AccountSummary.js";
+
+export type AccountCaseView = "overview" | "transfers" | "history";
+
+export interface AccountCaseContextValue {
+ account: string;
+ targetIsWallet: boolean | undefined;
+ classificationPending: boolean;
+ summary: CustomerAccountSummary | undefined;
+ summaryLoading: boolean;
+ summaryFailed: boolean;
+ retrySummary: () => void;
+}
+
+const AccountCaseContext = createContext<AccountCaseContextValue | undefined>(
+ undefined,
+);
+
+export function useAccountCaseContext(): AccountCaseContextValue | undefined {
+ return useContext(AccountCaseContext);
+}
+
+interface AccountCaseShellCommonProps {
+ account: string;
+ fullPayto?: string;
+ children: ComponentChildren;
+}
+
+interface AccountCasePresentationProps extends AccountCaseShellCommonProps {
+ presentation?: "case";
+ activeView: AccountCaseView;
+ routeToAccounts: string;
+ routeToOverview: string;
+ routeToTransfers: string;
+ routeToHistory: string;
+ onNewDecision: (fullPayto: string) => void;
+}
+
+interface AccountDecisionPresentationProps extends AccountCaseShellCommonProps {
+ presentation: "decision";
+ routeToAccount: string;
+ newAccount: boolean;
+}
+
+export type AccountCaseShellProps =
+ | AccountCasePresentationProps
+ | AccountDecisionPresentationProps;
+
+export function AccountCaseShell(props: AccountCaseShellProps): VNode {
+ const { account, fullPayto, children } = props;
+ const decisionPresentation = props.presentation === "decision";
+ const { i18n } = useTranslationContext();
+ const active = useAccountActiveDecision(account);
+ const summary = useAmlAccount(account);
+ const officer = useOfficer();
+ const officerInfo = useOfficerInfoContext();
+ const session = officer.state === "ready" ? officer.session : undefined;
+ const { lib } = useExchangeApiContext();
+ const { showError } = useNotificationContext();
+ const [downloadStarted, setDownloadStarted] = useState(false);
+
+ const activeDecision =
+ active && !(active instanceof TalerError) && active.type === "ok"
+ ? active.body
+ : undefined;
+ const summaryRecord =
+ summary && !(summary instanceof TalerError) && summary.type === "ok"
+ ? summary.body
+ : undefined;
+ const summaryFailed =
+ summary instanceof TalerError ||
+ (summary !== undefined && summary.type === "fail");
+ const decisionTargetPayto =
+ fullPayto ?? summaryRecord?.full_payto ?? activeDecision?.full_payto;
+ const parsedTarget = decisionTargetPayto
+ ? Result.orUndefined(Paytos.fromString(decisionTargetPayto))
+ : undefined;
+ const targetIsWallet =
+ parsedTarget !== undefined
+ ? isWalletPaytoType(parsedTarget.targetType)
+ : activeDecision?.is_wallet;
+ const customerLabel =
+ activeDecision?.properties?.[TalerAmlProperties.CUSTOMER_LABEL];
+ const receiverName = parsedTarget?.params["receiver-name"]?.trim();
+ const caseTitle =
+ (summaryRecord ? accountIdentity(summaryRecord).primary : undefined) ||
+ (typeof customerLabel === "string" && customerLabel.trim()) ||
+ receiverName ||
+ parsedTarget?.displayName ||
+ i18n.str`Account case`;
+
+ const downloadPdf = useNotifiedOperation<
+ Awaited<ReturnType<typeof lib.exchange.getAmlAttributesForAccountAsPdf>>,
+ [OfficerSession, string]
+ >(
+ (_ct, officerSession: OfficerSession, accountId: string) =>
+ lib.exchange.getAmlAttributesForAccountAsPdf(officerSession, accountId),
+ {
+ onSuccess: (result) => {
+ const time = format(new Date(), "yyyyMMdd_HHmmss");
+ const pdfBytes = new Uint8Array(result.byteLength);
+ pdfBytes.set(result);
+ const url = URL.createObjectURL(
+ new Blob([pdfBytes.buffer], { type: "application/pdf" }),
+ );
+ const download = document.createElement("a");
+ download.href = url;
+ download.download = `aml_file_${time}_${account}.pdf`;
+ download.hidden = true;
+ document.body.append(download);
+ download.click();
+ download.remove();
+ window.setTimeout(() => URL.revokeObjectURL(url), 0);
+ setDownloadStarted(true);
+ },
+ onFail: showError(i18n.str`Failed to download AML file.`, (fail) => {
+ switch (fail.case) {
+ case HttpStatusCode.NoContent:
+ return i18n.str`No AML file is available for this account.`;
+ case HttpStatusCode.Forbidden:
+ return i18n.str`Authorization denied for this session. Contact the administrator.`;
+ case HttpStatusCode.NotFound:
+ return i18n.str`The account or session was not found.`;
+ case HttpStatusCode.Conflict:
+ return i18n.str`The session is disabled. Contact the administrator.`;
+ case HttpStatusCode.NotImplemented:
+ return i18n.str`The exchange does not support PDF reports.`;
+ default:
+ return assertUnreachable(fail.case);
+ }
+ }),
+ },
+ );
+
+ useEffect(() => {
+ if (!downloadStarted) return;
+ const timer = setTimeout(() => setDownloadStarted(false), 4_000);
+ return () => clearTimeout(timer);
+ }, [downloadStarted]);
+
+ const newDecisionUnavailable = officerInfo.read_only
+ ? i18n.str`Read-only officers cannot create AML decisions.`
+ : !decisionTargetPayto
+ ? i18n.str`A payto URI is required to create a new decision.`
+ : undefined;
+
+ const withPayto = (route: string): string =>
+ decisionTargetPayto
+ ? `${route}?payto=${encodeCrockForURI(decisionTargetPayto)}`
+ : route;
+
+ const backRoute = decisionPresentation
+ ? props.routeToAccount
+ : props.routeToAccounts;
+
+ return (
+ <article class="mx-auto max-w-6xl">
+ <header>
+ <Link
+ href={backRoute}
+ class="inline-flex min-h-10 items-center rounded-md text-sm font-semibold text-primary hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary dark:text-darkPrimary"
+ >
+ <span aria-hidden="true">←</span>
+ <span class="ml-2">
+ {decisionPresentation ? (
+ <i18n.Translate>Back to account</i18n.Translate>
+ ) : (
+ <i18n.Translate>Back to accounts</i18n.Translate>
+ )}
+ </span>
+ </Link>
+
+ <div class="mt-3 grid gap-5 lg:grid-cols-[minmax(0,1fr)_auto] lg:items-start">
+ <div class="min-w-0 space-y-3">
+ <div>
+ <p class="text-sm font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
+ {decisionPresentation ? (
+ <i18n.Translate>New AML decision</i18n.Translate>
+ ) : (
+ <i18n.Translate>Account case</i18n.Translate>
+ )}
+ </p>
+ <h1 class="mt-1 break-words text-3xl font-bold tracking-tight text-gray-950 dark:text-gray-50">
+ {caseTitle}
+ </h1>
+ </div>
+ {summaryRecord ? (
+ <AccountSummaryBadges record={summaryRecord} />
+ ) : (
+ <AccountHeaderBadges
+ isWallet={targetIsWallet}
+ underInvestigation={activeDecision?.to_investigate === true}
+ highRisk={
+ activeDecision?.properties?.[
+ TalerAmlProperties.HIGH_RISK_CUSTOMER
+ ] === true
+ }
+ notOpened={decisionPresentation && props.newAccount}
+ />
+ )}
+ {summaryRecord ? (
+ <div class="flex flex-wrap items-start gap-x-5 gap-y-1 text-sm text-gray-600 dark:text-gray-300">
+ <span>
+ <i18n.Translate>
+ File no. {summaryRecord.rowid}
+ </i18n.Translate>
+ </span>
+ <AccountLifecycleDetails
+ record={summaryRecord}
+ showNotOpened={false}
+ />
+ </div>
+ ) : undefined}
+ </div>
+
+ {decisionPresentation ? undefined : (
+ <div class="grid gap-2 sm:grid-cols-2 lg:min-w-max">
+ <button
+ type="button"
+ aria-disabled={newDecisionUnavailable ? "true" : undefined}
+ aria-describedby={
+ newDecisionUnavailable
+ ? "new-decision-unavailable-explanation"
+ : undefined
+ }
+ onClick={() => {
+ if (decisionTargetPayto && !newDecisionUnavailable) {
+ props.onNewDecision(decisionTargetPayto);
+ }
+ }}
+ class={`inline-flex min-h-11 items-center justify-center rounded-md px-4 py-2 text-sm font-semibold focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary ${
+ newDecisionUnavailable
+ ? "cursor-not-allowed bg-gray-200 text-gray-600 dark:bg-gray-800 dark:text-gray-400"
+ : "bg-primary text-white hover:bg-primary/90 dark:bg-darkPrimary dark:text-gray-950"
+ }`}
+ >
+ <i18n.Translate>New decision</i18n.Translate>
+ </button>
+ <AsyncButton
+ disabled={!session}
+ onClick={
+ !session ? undefined : () => downloadPdf.run(session, account)
+ }
+ class="inline-flex min-h-11 items-center justify-center rounded-md border border-gray-400 bg-white px-4 py-2 text-sm font-semibold text-gray-900 hover:bg-gray-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary disabled:cursor-not-allowed disabled:bg-gray-100 disabled:text-gray-500 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100 dark:hover:bg-gray-800 dark:disabled:bg-gray-800 dark:disabled:text-gray-400"
+ >
+ <span class="inline-flex items-center justify-center gap-2">
+ <DownloadIcon />
+ <span>
+ <i18n.Translate>Download AML file (PDF)</i18n.Translate>
+ </span>
+ </span>
+ </AsyncButton>
+ </div>
+ )}
+ </div>
+
+ {newDecisionUnavailable ? (
+ <span id="new-decision-unavailable-explanation" class="sr-only">
+ {newDecisionUnavailable}
+ </span>
+ ) : undefined}
+ <span role="status" aria-live="polite" class="sr-only">
+ {downloadStarted ? i18n.str`AML file download started.` : undefined}
+ </span>
+
+ {summaryFailed ? (
+ <div class="mt-4 flex flex-wrap items-center gap-3 rounded-md border border-amber-300 bg-amber-50 px-3 py-2 text-sm text-amber-950 dark:border-amber-700 dark:bg-amber-950 dark:text-amber-100">
+ <span>
+ <i18n.Translate>
+ Current account status could not be loaded.
+ </i18n.Translate>
+ </span>
+ <button
+ type="button"
+ class="min-h-9 rounded-md px-2 font-semibold underline hover:no-underline"
+ onClick={() => revalidateAmlAccounts()}
+ >
+ <i18n.Translate>Try again</i18n.Translate>
+ </button>
+ </div>
+ ) : undefined}
+
+ <section
+ aria-labelledby="account-identifiers-heading"
+ class="mt-3 border-t border-gray-200 pt-3 dark:border-gray-700"
+ >
+ <h2
+ id="account-identifiers-heading"
+ class="flex min-w-0 flex-wrap items-baseline gap-x-1.5 text-sm font-semibold text-gray-800 dark:text-gray-200"
+ >
+ <span>
+ <i18n.Translate>Account identifiers</i18n.Translate>
+ </span>
+ <PaytoTargetType paytoUri={decisionTargetPayto} />
+ </h2>
+ <div class="mt-2">
+ <PaytoTargetDetails paytoUri={decisionTargetPayto} />
+ </div>
+ <details class="mt-1 text-sm text-gray-700 dark:text-gray-300">
+ <summary class="min-h-10 cursor-pointer rounded-md py-1.5 font-semibold text-primary hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary dark:text-darkPrimary">
+ <i18n.Translate>Technical identifiers</i18n.Translate>
+ </summary>
+ <dl class="mt-1 space-y-2 rounded-md bg-gray-50 p-2.5 dark:bg-gray-900">
+ <Identifier
+ label={i18n.str`Full payto URI`}
+ value={decisionTargetPayto}
+ fallback={i18n.str`Unavailable`}
+ copyLabel={i18n.str`Copy payto URI`}
+ />
+ <Identifier
+ label={i18n.str`Normalized payto hash`}
+ value={account}
+ copyLabel={i18n.str`Copy normalized payto hash`}
+ />
+ {summaryRecord ? (
+ <Identifier
+ label={i18n.str`File number`}
+ value={String(summaryRecord.rowid)}
+ copyLabel={i18n.str`Copy file number`}
+ />
+ ) : undefined}
+ </dl>
+ </details>
+ </section>
+
+ {decisionPresentation ? undefined : (
+ <nav
+ aria-label={i18n.str`Account case views`}
+ class="mt-5 grid grid-cols-3 border-b border-gray-300 dark:border-gray-700"
+ >
+ <CaseTab
+ label={i18n.str`Overview`}
+ href={withPayto(props.routeToOverview)}
+ selected={props.activeView === "overview"}
+ />
+ <CaseTab
+ label={i18n.str`Transfers`}
+ href={withPayto(props.routeToTransfers)}
+ selected={props.activeView === "transfers"}
+ />
+ <CaseTab
+ label={i18n.str`Decision history`}
+ href={withPayto(props.routeToHistory)}
+ selected={props.activeView === "history"}
+ />
+ </nav>
+ )}
+ </header>
+
+ <div class="space-y-10 py-8">
+ <AccountCaseContext.Provider
+ value={{
+ account,
+ targetIsWallet,
+ classificationPending:
+ summary === undefined &&
+ active === undefined &&
+ targetIsWallet === undefined,
+ summary: summaryRecord,
+ summaryLoading: summary === undefined,
+ summaryFailed,
+ retrySummary: revalidateAmlAccounts,
+ }}
+ >
+ {children}
+ </AccountCaseContext.Provider>
+ </div>
+ </article>
+ );
+}
+
+function CaseTab({
+ label,
+ href,
+ selected,
+}: {
+ label: TranslatedString;
+ href: string;
+ selected: boolean;
+}): VNode {
+ return (
+ <Link
+ href={href}
+ aria-current={selected ? "page" : undefined}
+ data-selected={selected}
+ class="flex min-h-12 items-center justify-center border-b-2 border-transparent px-2 py-3 text-center text-sm font-semibold text-gray-600 hover:text-primary focus-visible:outline focus-visible:outline-2 focus-visible:outline-inset focus-visible:outline-primary data-[selected=true]:border-primary data-[selected=true]:text-primary dark:text-gray-300 dark:hover:text-darkPrimary dark:data-[selected=true]:border-darkPrimary dark:data-[selected=true]:text-darkPrimary"
+ >
+ {label}
+ </Link>
+ );
+}
+
+function Identifier({
+ label,
+ value,
+ fallback,
+ copyLabel,
+}: {
+ label: TranslatedString;
+ value?: string;
+ fallback?: TranslatedString;
+ copyLabel: TranslatedString;
+}): VNode {
+ return (
+ <div class="grid gap-x-3 gap-y-0.5 sm:grid-cols-[8rem_minmax(0,1fr)]">
+ <dt class="font-semibold">{label}</dt>
+ <dd class="flex min-w-0 items-center gap-2">
+ <code class="min-w-0 break-all">{value ?? fallback}</code>
+ {value ? (
+ <CopyButton
+ class="inline-flex min-h-10 min-w-10 shrink-0 items-center justify-center rounded-md hover:bg-gray-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary dark:hover:bg-gray-800"
+ getContent={() => value}
+ >
+ <span class="sr-only">{copyLabel}</span>
+ </CopyButton>
+ ) : undefined}
+ </dd>
+ </div>
+ );
+}
+
+function DownloadIcon(): VNode {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ viewBox="0 0 24 24"
+ stroke-width="1.75"
+ stroke="currentColor"
+ class="size-5 shrink-0"
+ aria-hidden="true"
+ >
+ <path
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5m-4.5-4.5L12 16.5m0 0L7.5 12m4.5 4.5V3"
+ />
+ </svg>
+ );
+}
diff --git a/packages/taler-exchange-aml-webui/src/components/AccountSummary.test.tsx b/packages/taler-exchange-aml-webui/src/components/AccountSummary.test.tsx
@@ -0,0 +1,72 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+import { CustomerAccountSummary, setupI18n } from "@gnu-taler/taler-util";
+import assert from "node:assert/strict";
+import test from "node:test";
+import { h, render } from "preact";
+import {
+ AccountLifecycleDetails,
+ AccountSummaryBadges,
+ AccountSummaryNotes,
+} from "./AccountSummary.js";
+
+setupI18n("en", {});
+
+async function installDom() {
+ const happyDomPackage = "happy-dom";
+ const { Window } = await import(happyDomPackage);
+ const window = new Window({ url: "https://aml.example/" });
+ for (const [key, value] of Object.entries({
+ window,
+ document: window.document,
+ Node: window.Node,
+ Element: window.Element,
+ })) {
+ Object.defineProperty(globalThis, key, {
+ configurable: true,
+ writable: true,
+ value,
+ });
+ }
+ return window;
+}
+
+test("account summary shows lifecycle, risk, investigation and both note types", async () => {
+ const window = await installDom();
+ const record: CustomerAccountSummary = {
+ h_payto: "1111111111111111111111111111111111111111111111111111" as never,
+ full_payto:
+ "payto://iban/CH9300762011623852957?receiver-name=Example" as never,
+ high_risk: true,
+ comments: "Officer-authored note",
+ system_note: "BELOW_ACCOUNT_OPENING_THRESHOLD",
+ rowid: 1 as never,
+ open_time: { t_s: "never" },
+ close_time: { t_s: "never" },
+ to_investigate: true,
+ };
+ const container = window.document.createElement("div");
+ render(
+ <div>
+ <AccountSummaryBadges record={record} />
+ <AccountLifecycleDetails record={record} showNotOpened={false} />
+ <AccountSummaryNotes record={record} />
+ </div>,
+ container as unknown as Element,
+ );
+ assert.match(container.textContent, /Bank account/);
+ assert.match(container.textContent, /Not opened/);
+ assert.match(container.textContent, /Under investigation/);
+ assert.match(container.textContent, /High risk/);
+ assert.match(container.textContent, /Officer-authored note/);
+ assert.match(container.textContent, /Transactions remain below/);
+ assert.equal(container.textContent?.match(/Not opened/g)?.length, 1);
+ render(null, container as unknown as Element);
+ await window.happyDOM.abort();
+});
diff --git a/packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx b/packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx
@@ -0,0 +1,161 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+import {
+ AbsoluteTime,
+ CustomerAccountSummary,
+ Paytos,
+} from "@gnu-taler/taler-util";
+import { Time, useTranslationContext } from "@gnu-taler/web-util/browser";
+import { VNode, h } from "preact";
+import {
+ AccountClassificationBadge,
+ StatusBadge,
+ UnderInvestigationBadge,
+ isWalletPaytoType,
+} from "./AccountBadges.js";
+
+const LEGACY_BELOW_THRESHOLD_COMMENT =
+ "transacted amounts below limits that trigger account opening";
+
+export function accountIdentity(record: CustomerAccountSummary): {
+ primary: string;
+ secondary?: string;
+} {
+ const uri = Paytos.asString(record.full_payto);
+ const label = record.customer_label?.trim();
+ const receiverName = uri.params["receiver-name"]?.trim();
+ if (label) {
+ return {
+ primary: label,
+ secondary:
+ receiverName && receiverName !== label ? receiverName : undefined,
+ };
+ }
+ return {
+ primary: receiverName || uri.displayName,
+ secondary: receiverName ? uri.displayName : undefined,
+ };
+}
+
+export function AccountLifecycleDetails({
+ record,
+ showNotOpened = true,
+}: {
+ record: CustomerAccountSummary;
+ showNotOpened?: boolean;
+}): VNode | null {
+ const { i18n } = useTranslationContext();
+ const opened = AbsoluteTime.fromProtocolTimestamp(record.open_time);
+ const closed = AbsoluteTime.fromProtocolTimestamp(record.close_time);
+ if (AbsoluteTime.isNever(opened)) {
+ return showNotOpened ? <span>{i18n.str`Not opened`}</span> : null;
+ }
+ return (
+ <dl class="space-y-1">
+ <div>
+ <dt class="inline font-semibold">
+ <i18n.Translate>Opened:</i18n.Translate>{" "}
+ </dt>
+ <dd class="inline">
+ <Time timestamp={opened} format="PPp" />
+ </dd>
+ </div>
+ {!AbsoluteTime.isNever(closed) ? (
+ <div>
+ <dt class="inline font-semibold">
+ <i18n.Translate>Closed:</i18n.Translate>{" "}
+ </dt>
+ <dd class="inline">
+ <Time timestamp={closed} format="PPp" />
+ </dd>
+ </div>
+ ) : undefined}
+ </dl>
+ );
+}
+
+export function AccountSummaryBadges({
+ record,
+}: {
+ record: CustomerAccountSummary;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ const opened = record.open_time.t_s !== "never";
+ const closed = record.close_time.t_s !== "never";
+ const targetType = Paytos.asString(record.full_payto).targetType;
+ return (
+ <div class="flex flex-wrap gap-2">
+ <AccountClassificationBadge isWallet={isWalletPaytoType(targetType)} />
+ <StatusBadge tone={opened && !closed ? "positive" : "neutral"}>
+ {opened
+ ? closed
+ ? i18n.str`Closed`
+ : i18n.str`Open`
+ : i18n.str`Not opened`}
+ </StatusBadge>
+ {record.to_investigate ? <UnderInvestigationBadge /> : undefined}
+ {record.high_risk ? (
+ <StatusBadge tone="danger">
+ <i18n.Translate>High risk</i18n.Translate>
+ </StatusBadge>
+ ) : undefined}
+ </div>
+ );
+}
+
+export function AccountSummaryNotes({
+ record,
+ showEmpty = false,
+}: {
+ record: CustomerAccountSummary;
+ showEmpty?: boolean;
+}): VNode | null {
+ const { i18n } = useTranslationContext();
+ const legacySystemNote =
+ record.system_note === undefined &&
+ record.comments === LEGACY_BELOW_THRESHOLD_COMMENT;
+ const comment = legacySystemNote ? undefined : record.comments?.trim();
+ const systemNote = legacySystemNote
+ ? "BELOW_ACCOUNT_OPENING_THRESHOLD"
+ : record.system_note;
+ if (!comment && !systemNote) {
+ return showEmpty ? (
+ <span class="text-gray-500 dark:text-gray-400">{i18n.str`No note`}</span>
+ ) : null;
+ }
+ return (
+ <div class="space-y-2">
+ {comment ? (
+ <div>
+ <p class="line-clamp-2 break-words">{comment}</p>
+ {comment.length > 120 ? (
+ <details class="mt-1">
+ <summary class="min-h-8 cursor-pointer py-1 font-semibold text-primary hover:underline dark:text-darkPrimary">
+ <i18n.Translate>Show full note</i18n.Translate>
+ </summary>
+ <p class="mt-1 whitespace-pre-wrap break-words">{comment}</p>
+ </details>
+ ) : undefined}
+ </div>
+ ) : undefined}
+ {systemNote === "BELOW_ACCOUNT_OPENING_THRESHOLD" ? (
+ <div class="rounded-md border border-blue-200 bg-blue-50 p-2 text-blue-950 dark:border-blue-800 dark:bg-blue-950 dark:text-blue-100">
+ <p class="font-semibold">
+ <i18n.Translate>System information</i18n.Translate>
+ </p>
+ <p class="mt-1">
+ <i18n.Translate>
+ Transactions remain below the threshold that opens an AML file.
+ </i18n.Translate>
+ </p>
+ </div>
+ ) : undefined}
+ </div>
+ );
+}
diff --git a/packages/taler-exchange-aml-webui/src/components/ConfirmationModal.tsx b/packages/taler-exchange-aml-webui/src/components/ConfirmationModal.tsx
@@ -0,0 +1,105 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import { ComponentChildren, h, VNode } from "preact";
+import { useEffect, useRef } from "preact/hooks";
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
+
+export function ConfirmationModal({
+ open,
+ title,
+ children,
+ confirmLabel,
+ onClose,
+ onConfirm,
+}: {
+ open: boolean;
+ title: ComponentChildren;
+ children: ComponentChildren;
+ confirmLabel: ComponentChildren;
+ onClose: () => void;
+ onConfirm: () => void;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ const dialogRef = useRef<HTMLDialogElement>(null);
+
+ useEffect(() => {
+ const dialog = dialogRef.current;
+ if (!dialog) return;
+ if (open && !dialog.open) dialog.showModal();
+ if (!open && dialog.open) dialog.close();
+ }, [open]);
+
+ return (
+ <dialog
+ ref={dialogRef}
+ aria-modal="true"
+ aria-labelledby="confirmation-modal-title"
+ aria-describedby="confirmation-modal-description"
+ class="fixed inset-0 z-50 size-auto max-h-none max-w-none overflow-y-auto bg-transparent p-4 backdrop:bg-black/60"
+ {...({
+ onCancel: (event: Event) => {
+ event.preventDefault();
+ onClose();
+ },
+ } as object)}
+ >
+ <button
+ type="button"
+ aria-hidden="true"
+ tabIndex={-1}
+ onClick={onClose}
+ class="fixed inset-0 cursor-default"
+ />
+ <div class="pointer-events-none relative flex min-h-full items-center justify-center">
+ <section class="pointer-events-auto w-full max-w-md rounded-xl border border-gray-100 bg-white p-6 text-onBackground shadow-xl dark:border-gray-800 dark:bg-gray-900 dark:text-darkOnBackground">
+ <div class="flex items-start justify-between gap-4 border-b border-gray-200 pb-3 dark:border-gray-700">
+ <h2
+ id="confirmation-modal-title"
+ class="text-lg font-bold text-gray-900 dark:text-gray-100"
+ >
+ {title}
+ </h2>
+ <button
+ type="button"
+ onClick={onClose}
+ class="-mr-1 rounded-md p-1 text-gray-500 hover:bg-gray-100 hover:text-gray-800 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary dark:hover:bg-gray-800 dark:hover:text-gray-100"
+ aria-label={i18n.str`Close`}
+ >
+ <span aria-hidden="true">✕</span>
+ </button>
+ </div>
+ <div
+ id="confirmation-modal-description"
+ class="pt-4 text-sm leading-6 text-gray-700 dark:text-gray-300"
+ >
+ {children}
+ </div>
+ <div class="flex flex-wrap items-center justify-end gap-3 pt-6">
+ <button
+ type="button"
+ autofocus
+ onClick={onClose}
+ class="rounded-md border border-outline px-4 py-2 text-sm font-semibold hover:bg-surfaceContainer focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary"
+ >
+ <i18n.Translate>Cancel</i18n.Translate>
+ </button>
+ <button
+ type="button"
+ onClick={onConfirm}
+ class="rounded-md border border-error px-4 py-2 text-sm font-semibold text-error hover:bg-errorContainer focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-error dark:border-red-300 dark:text-red-300 dark:hover:bg-red-950/50"
+ >
+ {confirmLabel}
+ </button>
+ </div>
+ </section>
+ </div>
+ </dialog>
+ );
+}
diff --git a/packages/taler-exchange-aml-webui/src/components/CreateSession.tsx b/packages/taler-exchange-aml-webui/src/components/CreateSession.tsx
@@ -19,6 +19,7 @@ import {
FormUI,
InternationalizationAPI,
useForm,
+ useExchangeApiContext,
useNotifiedOperation,
useTranslationContext,
} from "@gnu-taler/web-util/browser";
@@ -83,7 +84,9 @@ export function CreateSession({
officer: OfficerNotFound;
}): VNode {
const { i18n } = useTranslationContext();
+ const { lib } = useExchangeApiContext();
const [settings] = usePreferences();
+ const exchangeBaseUrl = new URL("/", lib.exchange.baseUrl).href;
const design = createAccountForm(i18n, settings.allowInsecurePassword);
@@ -97,24 +100,40 @@ export function CreateSession({
[Password]
>((_ct, password: Password) => officer.create(password));
+ const submitCreate = () => {
+ if (status.status === "fail") return Promise.resolve();
+ return create.run(asPassword(status.result.password));
+ };
+
return (
<div class="flex min-h-full flex-col ">
<div class="sm:mx-auto sm:w-full sm:max-w-md">
<h2 class="mt-6 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">
<i18n.Translate>Create session</i18n.Translate>
</h2>
+ <p class="mt-2 break-all text-center font-mono text-sm text-gray-600">
+ {exchangeBaseUrl}
+ </p>
</div>
- <div class="mt-10 sm:mx-auto sm:w-full sm:max-w-[480px] ">
- <FormUI design={design} model={handler} focus />
+ <div class="mt-10 sm:mx-auto sm:w-full sm:max-w-[480px]">
+ <FormUI
+ design={design}
+ model={handler}
+ focus
+ onSubmit={() => void submitCreate()}
+ />
<div class="mt-8">
<AsyncButton
submit
- class="disabled:opacity-50 disabled:cursor-default flex w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
+ class="disabled:cursor-not-allowed disabled:bg-gray-200 disabled:text-gray-700 disabled:hover:bg-gray-200 flex w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
onClick={
status.status === "fail"
? undefined
- : () => create.run(asPassword(status.result.password))
+ : (event) => {
+ event.preventDefault();
+ return submitCreate();
+ }
}
>
<i18n.Translate>Create</i18n.Translate>
diff --git a/packages/taler-exchange-aml-webui/src/components/DecisionHistory.stories.tsx b/packages/taler-exchange-aml-webui/src/components/DecisionHistory.stories.tsx
@@ -0,0 +1,258 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import {
+ AbsoluteTime,
+ AmlDecision,
+ AmlSpaDialect,
+ AmountString,
+ AvailableMeasureSummary,
+ LegitimizationMeasures,
+ LimitOperationType,
+} from "@gnu-taler/taler-util";
+import * as tests from "@gnu-taler/web-util/testing";
+import { ShowDecisionLimitInfo } from "./ShowDecisionLimitInfo.js";
+import { ShowLegistimizationInfo } from "./ShowLegitimizationInfo.js";
+
+export default { title: "decision history" };
+
+const now = Date.now();
+const since = AbsoluteTime.fromMilliseconds(now - 24 * 60 * 60 * 1000);
+const timestamp = (milliseconds: number) =>
+ ({
+ t_s: Math.floor(milliseconds / 1000),
+ }) as const;
+
+const rules = [
+ {
+ operation_type: LimitOperationType.withdraw,
+ threshold: "TESTKUDOS:1000" as AmountString,
+ timeframe: { d_us: 30 * 24 * 60 * 60 * 1_000_000 },
+ measures: ["enhanced-due-diligence"],
+ display_priority: 20,
+ exposed: true,
+ is_and_combinator: false,
+ },
+];
+
+const serverMeasures = {
+ roots: {
+ "standard-monitoring": {
+ check_name: "skip",
+ prog_name: "review-documents",
+ },
+ },
+ checks: {
+ "identity-form": {
+ description: "Identity document form",
+ requires: [],
+ outputs: ["identity"],
+ fallback: "manual-review",
+ },
+ "terms-review": {
+ description: "Updated terms review",
+ requires: [],
+ outputs: [],
+ fallback: "manual-review",
+ },
+ },
+ programs: {
+ "review-documents": {
+ description: "Review submitted documents",
+ context: [],
+ inputs: ["identity"],
+ },
+ },
+ default_rules: [],
+} as unknown as AvailableMeasureSummary;
+
+const account = "1111111111111111111111111111111111111111111111111111";
+const routeToShowCollectedInfo = ({
+ cid,
+ rowId,
+}: {
+ cid: string;
+ rowId: string;
+}) => `/account/${cid}/attributes/${rowId}`;
+const fullDecision: AmlDecision = {
+ h_payto: account as never,
+ full_payto: "payto://iban/CH9300762011623852957",
+ is_wallet: false,
+ rowid: 54 as never,
+ justification: "Enhanced review required after a change in ownership.",
+ new_measures: "+enhanced-due-diligence standard-monitoring",
+ decider_pub: "OFFICERPUB0123456789012345678901234567890123456789012",
+ decider_name: "Alex Compliance",
+ kyc_attributes_rowid: 18 as never,
+ decision_time: timestamp(now - 24 * 60 * 60 * 1000),
+ properties: { high_risk: true, business_domain: "Wholesale trade" },
+ limits: {
+ expiration_time: timestamp(now + 30 * 24 * 60 * 60 * 1000),
+ successor_measure: "standard-monitoring",
+ rules,
+ custom_measures: {
+ "enhanced-due-diligence": {
+ check_name: "identity-form",
+ prog_name: "review-documents",
+ operation_type: LimitOperationType.withdraw,
+ context: { requested_document: "proof-of-address" },
+ },
+ },
+ },
+ to_investigate: true,
+ is_active: true,
+};
+
+const identityMeasure = {
+ check_name: "identity-form",
+ prog_name: "review-documents",
+ context: { requested_document: "proof-of-address" },
+};
+const termsMeasure = {
+ check_name: "terms-review",
+ context: { tos_version: "2026-08" },
+};
+
+function legitimization(
+ measures: LegitimizationMeasures["measures"],
+ isAnd: boolean,
+ verboten = false,
+): LegitimizationMeasures {
+ return {
+ measures,
+ is_and_combinator: isAnd,
+ verboten,
+ };
+}
+
+export const FullCurrentDecision = tests.createExample(ShowDecisionLimitInfo, {
+ decision: fullDecision,
+ dialect: AmlSpaDialect.TOPS,
+ serverMeasures,
+ account,
+ routeToShowCollectedInfo,
+ presentation: "static",
+});
+
+export const FullHistoricalDecision = tests.createExample(
+ ShowDecisionLimitInfo,
+ {
+ decision: { ...fullDecision, rowid: 53 as never, is_active: false },
+ dialect: AmlSpaDialect.TOPS,
+ serverMeasures,
+ account,
+ routeToShowCollectedInfo,
+ presentation: "history-disclosure",
+ },
+);
+
+export const NoImmediateMeasure = tests.createExample(ShowDecisionLimitInfo, {
+ decision: { ...fullDecision, new_measures: undefined },
+ dialect: AmlSpaDialect.TOPS,
+ serverMeasures,
+ account,
+ routeToShowCollectedInfo,
+ presentation: "static",
+});
+
+export const UnresolvedMeasure = tests.createExample(ShowDecisionLimitInfo, {
+ decision: { ...fullDecision, new_measures: "removed-measure" },
+ dialect: AmlSpaDialect.TOPS,
+ serverMeasures,
+ account,
+ routeToShowCollectedInfo,
+ presentation: "static",
+});
+
+export const AutomatedHistoricalDecision = tests.createExample(
+ ShowDecisionLimitInfo,
+ {
+ decision: {
+ ...fullDecision,
+ rowid: 52 as never,
+ decider_pub: undefined,
+ decider_name: undefined,
+ is_active: false,
+ limits: {
+ ...fullDecision.limits,
+ expiration_time: timestamp(now - 60 * 60 * 1000),
+ },
+ },
+ dialect: AmlSpaDialect.TOPS,
+ serverMeasures,
+ account,
+ routeToShowCollectedInfo,
+ presentation: "history-disclosure",
+ },
+);
+
+export const MeasureMetadataUnavailable = tests.createExample(
+ ShowDecisionLimitInfo,
+ {
+ decision: {
+ ...fullDecision,
+ limits: { ...fullDecision.limits, custom_measures: {} },
+ },
+ dialect: AmlSpaDialect.TOPS,
+ serverMeasuresUnavailable: true,
+ account,
+ routeToShowCollectedInfo,
+ presentation: "static",
+ },
+);
+
+export const MeasureMetadataLoading = tests.createExample(
+ ShowDecisionLimitInfo,
+ {
+ decision: {
+ ...fullDecision,
+ limits: { ...fullDecision.limits, custom_measures: {} },
+ },
+ dialect: AmlSpaDialect.TOPS,
+ serverMeasuresLoading: true,
+ account,
+ routeToShowCollectedInfo,
+ presentation: "static",
+ },
+);
+
+export const PendingAnyMeasure = tests.createExample(ShowLegistimizationInfo, {
+ since,
+ startOpen: true,
+ legitimization: legitimization([identityMeasure, termsMeasure], false),
+ completed: false,
+ serverMeasures,
+});
+
+export const PendingAllMeasures = tests.createExample(ShowLegistimizationInfo, {
+ since,
+ startOpen: true,
+ legitimization: legitimization([identityMeasure, termsMeasure], true),
+ completed: false,
+ serverMeasures,
+});
+
+export const Completed = tests.createExample(ShowLegistimizationInfo, {
+ since,
+ startOpen: false,
+ legitimization: legitimization([identityMeasure], false),
+ completed: true,
+ serverMeasures,
+});
+
+export const CategoricallyForbidden = tests.createExample(
+ ShowLegistimizationInfo,
+ {
+ since,
+ startOpen: true,
+ legitimization: legitimization([], false, true),
+ completed: false,
+ serverMeasures,
+ },
+);
diff --git a/packages/taler-exchange-aml-webui/src/components/DecisionProperties.tsx b/packages/taler-exchange-aml-webui/src/components/DecisionProperties.tsx
@@ -0,0 +1,96 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+import {
+ AccountProperties,
+ AmlSpaDialect,
+ TranslatedString,
+} from "@gnu-taler/taler-util";
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
+import { VNode, h } from "preact";
+import { propertiesByDialect } from "../pages/decision/Properties.js";
+
+export function DecisionProperties({
+ properties,
+ dialect,
+}: {
+ properties?: AccountProperties;
+ dialect: AmlSpaDialect;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ const entries = Object.entries(properties ?? {}).filter(
+ ([, value]) => value !== null && value !== undefined,
+ );
+ const configured = new Map(
+ propertiesByDialect(i18n, dialect)
+ .filter(
+ (property): property is typeof property & { id: string } =>
+ "id" in property,
+ )
+ .map((property) => [
+ property.id,
+ {
+ label: property.label,
+ description: property.help ?? property.tooltip,
+ },
+ ]),
+ );
+ if (!entries.length) {
+ return (
+ <p class="text-sm text-gray-600 dark:text-gray-300">
+ <i18n.Translate>No account properties were recorded.</i18n.Translate>
+ </p>
+ );
+ }
+ return (
+ <dl class="divide-y divide-gray-200 border-y border-gray-200 text-sm dark:divide-gray-700 dark:border-gray-700">
+ {entries.map(([key, value]) => {
+ const metadata = configured.get(key);
+ return (
+ <div
+ key={key}
+ class="grid gap-2 py-3 sm:grid-cols-[minmax(12rem,2fr)_minmax(0,3fr)] sm:gap-6"
+ >
+ <dt>
+ <span class="block font-semibold text-gray-900 dark:text-gray-100">
+ {metadata?.label ?? humanizeIdentifier(key)}
+ </span>
+ {metadata?.description ? (
+ <span class="mt-1 block text-xs text-gray-500 dark:text-gray-400">
+ {metadata.description}
+ </span>
+ ) : undefined}
+ <code class="mt-1 block break-all text-xs text-gray-500 dark:text-gray-400">
+ {key}
+ </code>
+ </dt>
+ <dd class="whitespace-pre-wrap break-words text-gray-800 dark:text-gray-200">
+ {propertyValue(value, i18n)}
+ </dd>
+ </div>
+ );
+ })}
+ </dl>
+ );
+}
+
+function humanizeIdentifier(value: string): string {
+ const words = value.replace(/[_-]+/g, " ").trim().toLocaleLowerCase();
+ return words ? words.charAt(0).toLocaleUpperCase() + words.slice(1) : value;
+}
+
+function propertyValue(
+ value: unknown,
+ i18n: ReturnType<typeof useTranslationContext>["i18n"],
+): string | TranslatedString {
+ if (typeof value === "boolean") return value ? i18n.str`Yes` : i18n.str`No`;
+ if (typeof value === "string" || typeof value === "number") {
+ return String(value);
+ }
+ return JSON.stringify(value);
+}
diff --git a/packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx b/packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx
@@ -0,0 +1,55 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+import { AbsoluteTime, Duration } from "@gnu-taler/taler-util";
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
+import { VNode, h } from "preact";
+
+export function ExpirationShortcuts({
+ onChange,
+ referenceNow,
+}: {
+ onChange: (expiration: AbsoluteTime) => void;
+ referenceNow: AbsoluteTime;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ return (
+ <div class="mb-3">
+ <span class="mr-3 text-sm font-medium">
+ <i18n.Translate>Expiration shortcuts</i18n.Translate>
+ </span>
+ <div class="inline-flex flex-wrap gap-2">
+ {(
+ [
+ [i18n.str`In a week`, Duration.fromSpec({ days: 7 })],
+ [i18n.str`In a month`, Duration.fromSpec({ months: 1 })],
+ [i18n.str`In a year`, Duration.fromSpec({ years: 1 })],
+ ] as const
+ ).map(([label, duration]) => (
+ <button
+ key={label}
+ type="button"
+ onClick={() =>
+ onChange(AbsoluteTime.addDuration(referenceNow, duration))
+ }
+ class="rounded-md bg-white px-3 py-2 text-sm ring-1 ring-gray-300 hover:bg-gray-50 dark:bg-gray-950 dark:ring-gray-700 dark:hover:bg-gray-900"
+ >
+ {label}
+ </button>
+ ))}
+ <button
+ type="button"
+ onClick={() => onChange(AbsoluteTime.never())}
+ class="rounded-md bg-white px-3 py-2 text-sm ring-1 ring-gray-300 hover:bg-gray-50 dark:bg-gray-950 dark:ring-gray-700 dark:hover:bg-gray-900"
+ >
+ <i18n.Translate>Never</i18n.Translate>
+ </button>
+ </div>
+ </div>
+ );
+}
diff --git a/packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx b/packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx
@@ -14,7 +14,7 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import { useTranslationContext } from "@gnu-taler/web-util/browser";
-import { Fragment, h, VNode } from "preact";
+import { ComponentChildren, Fragment, h, VNode } from "preact";
import {
MeasureInfo,
UiMeasureInformation,
@@ -26,10 +26,12 @@ export function CurrentMeasureTable({
measures,
onSelect,
hideMeasureNames,
+ actionLabel,
}: {
measures: UiMeasureInformation;
hideMeasureNames?: boolean;
onSelect?: (m: MeasureInfo) => void;
+ actionLabel?: ComponentChildren;
}): VNode {
const { i18n } = useTranslationContext();
return (
@@ -38,10 +40,10 @@ export function CurrentMeasureTable({
<div class="mt-4 flow-root">
<div class="sm:flex sm:items-center">
<div class="sm:flex-auto">
- <h1 class="text-base font-semibold text-gray-900">
+ <h4 class="text-base font-semibold text-gray-900 dark:text-gray-100">
<i18n.Translate>Forms</i18n.Translate>
- </h1>
- <p class="mt-2 text-sm text-gray-700">
+ </h4>
+ <p class="mt-2 text-sm text-gray-700 dark:text-gray-300">
<i18n.Translate>
Measures used to gather information about the customer.
</i18n.Translate>
@@ -49,14 +51,16 @@ export function CurrentMeasureTable({
</div>
</div>
- <div class="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
- <div class="overflow-hidden shadow ring-1 ring-black/5 sm:rounded-lg">
- <table class="min-w-full divide-y divide-gray-300">
- <thead class="bg-gray-50">
+ <div class="min-w-full py-2 align-middle">
+ <div class="overflow-x-auto rounded-lg border border-gray-200 dark:border-gray-700">
+ <table class="min-w-[42rem] divide-y divide-gray-300 dark:divide-gray-700">
+ <thead class="bg-gray-50 dark:bg-gray-900">
<tr>
{onSelect ? (
<th scope="col" class="relative p-2 ">
- <span class="sr-only">Select</span>
+ <span class="sr-only">
+ <i18n.Translate>Select</i18n.Translate>
+ </span>
</th>
) : (
<Fragment />
@@ -64,57 +68,59 @@ export function CurrentMeasureTable({
{hideMeasureNames ? undefined : (
<th
scope="col"
- class="p-2 text-left text-sm font-semibold text-gray-900 sm:pl-6"
+ class="p-2 text-left text-sm font-semibold text-gray-900 sm:pl-6 dark:text-gray-100"
>
<i18n.Translate>Name</i18n.Translate>
</th>
)}
<th
scope="col"
- class="p-2 text-left text-sm font-semibold text-gray-900"
+ class="p-2 text-left text-sm font-semibold text-gray-900 dark:text-gray-100"
>
<i18n.Translate>Check</i18n.Translate>
</th>
<th
scope="col"
- class="p-2 text-left text-sm font-semibold text-gray-900"
+ class="p-2 text-left text-sm font-semibold text-gray-900 dark:text-gray-100"
>
<i18n.Translate>Program</i18n.Translate>
</th>
<th
scope="col"
- class="p-2 text-left text-sm font-semibold text-gray-900"
+ class="p-2 text-left text-sm font-semibold text-gray-900 dark:text-gray-100"
>
<i18n.Translate>Context</i18n.Translate>
</th>
</tr>
</thead>
- <tbody class="divide-y divide-gray-200 bg-white">
+ <tbody class="divide-y divide-gray-200 bg-white dark:divide-gray-700 dark:bg-gray-950">
{measures.forms.map((m, k) => {
return (
- <tr key={k}>
+ <tr class="even:bg-gray-50 dark:even:bg-gray-900" key={k}>
{!onSelect ? undefined : (
<td class="relative whitespace-nowrap p-2 text-right text-sm font-medium ">
<button
onClick={() => onSelect(m)}
- class="rounded-md w-fit border-0 p-1 mr-1 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
+ class="min-h-10 rounded-md bg-primary px-3 py-2 text-sm font-semibold text-onPrimary hover:bg-primary/90 dark:bg-darkPrimary dark:text-darkOnPrimary"
>
- <i18n.Translate>Modify</i18n.Translate>
+ {actionLabel ?? (
+ <i18n.Translate>Modify</i18n.Translate>
+ )}
</button>
</td>
)}
{hideMeasureNames ? undefined : (
- <td class="whitespace-nowrap p-2 text-sm font-medium text-gray-900 ">
+ <td class="whitespace-nowrap p-2 text-sm font-medium text-gray-900 dark:text-gray-100">
{m.name}
</td>
)}
- <td class="p-2 text-sm text-gray-500">
+ <td class="p-2 text-sm text-gray-500 dark:text-gray-300">
{m.check?.description ?? ""}
</td>
- <td class="p-2 text-sm text-gray-500">
+ <td class="p-2 text-sm text-gray-500 dark:text-gray-300">
{m.program?.description}
</td>
- <td class="whitespace-nowrap p-2 text-sm text-gray-500">
+ <td class="whitespace-nowrap p-2 text-sm text-gray-500 dark:text-gray-300">
{Object.keys(m.context ?? {}).join(", ")}
</td>
</tr>
@@ -131,25 +137,28 @@ export function CurrentMeasureTable({
<div class="mt-4 flow-root">
<div class="sm:flex sm:items-center">
<div class="sm:flex-auto">
- <h1 class="text-base font-semibold text-gray-900">
- <i18n.Translate>Info</i18n.Translate>
- </h1>
- <p class="mt-2 text-sm text-gray-700">
+ <h4 class="text-base font-semibold text-gray-900 dark:text-gray-100">
+ <i18n.Translate>Information</i18n.Translate>
+ </h4>
+ <p class="mt-2 text-sm text-gray-700 dark:text-gray-300">
<i18n.Translate>
- Will show information to the user.
+ Shows information to the customer without running an AML
+ program.
</i18n.Translate>
</p>
</div>
</div>
- <div class="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
- <div class="overflow-hidden shadow ring-1 ring-black/5 sm:rounded-lg">
- <table class="min-w-full divide-y divide-gray-300">
- <thead class="bg-gray-50">
+ <div class="min-w-full py-2 align-middle">
+ <div class="overflow-x-auto rounded-lg border border-gray-200 dark:border-gray-700">
+ <table class="min-w-[36rem] divide-y divide-gray-300 dark:divide-gray-700">
+ <thead class="bg-gray-50 dark:bg-gray-900">
<tr>
{onSelect ? (
<th scope="col" class="relative p-2 ">
- <span class="sr-only">Select</span>
+ <span class="sr-only">
+ <i18n.Translate>Select</i18n.Translate>
+ </span>
</th>
) : (
<Fragment />
@@ -157,50 +166,52 @@ export function CurrentMeasureTable({
{hideMeasureNames ? undefined : (
<th
scope="col"
- class="p-2 text-left text-sm font-semibold text-gray-900 sm:pl-6"
+ class="p-2 text-left text-sm font-semibold text-gray-900 sm:pl-6 dark:text-gray-100"
>
<i18n.Translate>Name</i18n.Translate>
</th>
)}
<th
scope="col"
- class="p-2 text-left text-sm font-semibold text-gray-900 sm:pl-6"
+ class="p-2 text-left text-sm font-semibold text-gray-900 sm:pl-6 dark:text-gray-100"
>
<i18n.Translate>Check</i18n.Translate>
</th>
<th
scope="col"
- class="p-2 text-left text-sm font-semibold text-gray-900"
+ class="p-2 text-left text-sm font-semibold text-gray-900 dark:text-gray-100"
>
<i18n.Translate>Context</i18n.Translate>
</th>
</tr>
</thead>
- <tbody class="divide-y divide-gray-200 bg-white">
+ <tbody class="divide-y divide-gray-200 bg-white dark:divide-gray-700 dark:bg-gray-950">
{measures.info.map((m, k) => {
return (
- <tr key={k}>
+ <tr class="even:bg-gray-50 dark:even:bg-gray-900" key={k}>
{onSelect ? (
<td class="relative whitespace-nowrap p-2 text-right text-sm font-medium ">
<button
onClick={() => onSelect(m)}
- class="rounded-md w-fit border-0 p-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
+ class="min-h-10 rounded-md bg-primary px-3 py-2 text-sm font-semibold text-onPrimary hover:bg-primary/90 dark:bg-darkPrimary dark:text-darkOnPrimary"
>
- <i18n.Translate>Modify</i18n.Translate>
+ {actionLabel ?? (
+ <i18n.Translate>Modify</i18n.Translate>
+ )}
</button>
</td>
) : (
<Fragment />
)}
{hideMeasureNames ? undefined : (
- <td class="whitespace-nowrap p-2 text-sm font-medium text-gray-900 sm:pl-6">
+ <td class="whitespace-nowrap p-2 text-sm font-medium text-gray-900 sm:pl-6 dark:text-gray-100">
{m.name}
</td>
)}
- <td class="whitespace-nowrap p-2 text-sm text-gray-500">
+ <td class="whitespace-nowrap p-2 text-sm text-gray-500 dark:text-gray-300">
{m.checkName}
</td>
- <td class="whitespace-nowrap p-2 text-sm text-gray-500">
+ <td class="whitespace-nowrap p-2 text-sm text-gray-500 dark:text-gray-300">
{Object.keys(m.context ?? {}).join(", ")}
</td>
</tr>
@@ -217,10 +228,10 @@ export function CurrentMeasureTable({
<div class="mt-4 flow-root">
<div class="sm:flex sm:items-center">
<div class="sm:flex-auto">
- <h1 class="text-base font-semibold text-gray-900">
+ <h4 class="text-base font-semibold text-gray-900 dark:text-gray-100">
<i18n.Translate>Instant measures</i18n.Translate>
- </h1>
- <p class="mt-2 text-sm text-gray-700">
+ </h4>
+ <p class="mt-2 text-sm text-gray-700 dark:text-gray-300">
<i18n.Translate>
Triggered immediately without customer interaction.
</i18n.Translate>
@@ -228,14 +239,16 @@ export function CurrentMeasureTable({
</div>
</div>
- <div class="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
- <div class="overflow-hidden shadow ring-1 ring-black/5 sm:rounded-lg">
- <table class="min-w-full divide-y divide-gray-300">
- <thead class="bg-gray-50">
+ <div class="min-w-full py-2 align-middle">
+ <div class="overflow-x-auto rounded-lg border border-gray-200 dark:border-gray-700">
+ <table class="min-w-[42rem] divide-y divide-gray-300 dark:divide-gray-700">
+ <thead class="bg-gray-50 dark:bg-gray-900">
<tr>
{onSelect ? (
<th scope="col" class="relative p-2 ">
- <span class="sr-only">Select</span>
+ <span class="sr-only">
+ <i18n.Translate>Select</i18n.Translate>
+ </span>
</th>
) : (
<Fragment />
@@ -243,59 +256,61 @@ export function CurrentMeasureTable({
{hideMeasureNames ? undefined : (
<th
scope="col"
- class="p-2 text-left text-sm font-semibold text-gray-900 sm:pl-6"
+ class="p-2 text-left text-sm font-semibold text-gray-900 sm:pl-6 dark:text-gray-100"
>
<i18n.Translate>Name</i18n.Translate>
</th>
)}
<th
scope="col"
- class="p-2 text-left text-sm font-semibold text-gray-900"
+ class="p-2 text-left text-sm font-semibold text-gray-900 dark:text-gray-100"
>
<i18n.Translate>Program</i18n.Translate>
</th>
<th
scope="col"
- class="p-2 text-left text-sm font-semibold text-gray-900"
+ class="p-2 text-left text-sm font-semibold text-gray-900 dark:text-gray-100"
>
<i18n.Translate>Input requirement</i18n.Translate>
</th>
<th
scope="col"
- class="p-2 text-left text-sm font-semibold text-gray-900"
+ class="p-2 text-left text-sm font-semibold text-gray-900 dark:text-gray-100"
>
<i18n.Translate>Context</i18n.Translate>
</th>
</tr>
</thead>
- <tbody class="divide-y divide-gray-200 bg-white">
+ <tbody class="divide-y divide-gray-200 bg-white dark:divide-gray-700 dark:bg-gray-950">
{measures.procedures.map((m, k) => {
return (
- <tr key={k}>
+ <tr class="even:bg-gray-50 dark:even:bg-gray-900" key={k}>
{onSelect ? (
<td class="relative whitespace-nowrap p-2 text-right text-sm font-medium ">
<button
onClick={() => onSelect(m)}
- class="rounded-md w-fit border-0 p-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
+ class="min-h-10 rounded-md bg-primary px-3 py-2 text-sm font-semibold text-onPrimary hover:bg-primary/90 dark:bg-darkPrimary dark:text-darkOnPrimary"
>
- <i18n.Translate>Modify</i18n.Translate>
+ {actionLabel ?? (
+ <i18n.Translate>Modify</i18n.Translate>
+ )}
</button>
</td>
) : (
<Fragment />
)}
{hideMeasureNames ? undefined : (
- <td class="whitespace-nowrap p-2 text-sm font-medium text-gray-900 sm:pl-6">
+ <td class="whitespace-nowrap p-2 text-sm font-medium text-gray-900 sm:pl-6 dark:text-gray-100">
{m.name}
</td>
)}
- <td class="whitespace-nowrap p-2 text-sm text-gray-500">
+ <td class="whitespace-nowrap p-2 text-sm text-gray-500 dark:text-gray-300">
{m.program.description}
</td>
- <td class="whitespace-nowrap p-2 text-sm text-gray-500">
+ <td class="whitespace-nowrap p-2 text-sm text-gray-500 dark:text-gray-300">
{m.program.inputs.join(",")}
</td>
- <td class="whitespace-nowrap p-2 text-sm text-gray-500">
+ <td class="whitespace-nowrap p-2 text-sm text-gray-500 dark:text-gray-300">
{Object.keys(m.context ?? {}).join(", ")}
</td>
</tr>
diff --git a/packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx b/packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx
@@ -38,11 +38,19 @@ import {
} from "@gnu-taler/web-util/browser";
import { Fragment, h, VNode } from "preact";
import { useState } from "preact/hooks";
+import { BUILT_IN_SKIP_CHECK } from "../utils/measure-check.js";
import { useCurrentDecisionRequest } from "../hooks/decision-request.js";
import { useServerMeasures } from "../hooks/server-info.js";
const TALER_SCREEN_ID = 122;
+const primaryButtonClass =
+ "min-h-11 rounded-md bg-primary px-4 py-2 text-sm font-semibold text-onPrimary hover:bg-primary/90 disabled:cursor-not-allowed disabled:bg-gray-200 disabled:text-gray-700 disabled:hover:bg-gray-200 dark:bg-darkPrimary dark:text-darkOnPrimary dark:disabled:bg-gray-700 dark:disabled:text-gray-300";
+const secondaryButtonClass =
+ "min-h-11 rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-semibold text-gray-800 hover:bg-gray-50 dark:border-gray-600 dark:bg-gray-950 dark:text-gray-100 dark:hover:bg-gray-900";
+const dangerButtonClass =
+ "min-h-11 rounded-md border border-red-400 bg-white px-4 py-2 text-sm font-semibold text-red-700 hover:bg-red-50 dark:border-red-700 dark:bg-gray-950 dark:text-red-300 dark:hover:bg-red-950/30";
+
export type MeasureDefinition = {
name: string;
program: string;
@@ -178,6 +186,8 @@ function NormalMeasureForm({
names.checks,
summary,
!addingNew,
+ Object.keys(request.custom_measures ?? {}),
+ initial?.name,
);
const form = useForm<MeasureDefinition>(design, initial ?? {});
@@ -188,7 +198,7 @@ function NormalMeasureForm({
const newMeasure = form.status.result as MeasureDefinition;
const currentMeasures = { ...request.custom_measures };
currentMeasures[newMeasure.name] = {
- check_name: newMeasure.check,
+ check_name: newMeasure.check ?? BUILT_IN_SKIP_CHECK,
prog_name: newMeasure.program,
context: (newMeasure.context ?? []).reduce(
(prev, cur) => {
@@ -211,7 +221,7 @@ function NormalMeasureForm({
const CURRENT_MEASURES = { ...request.custom_measures };
CURRENT_MEASURES[newMeasure.name] = {
- check_name: newMeasure.check,
+ check_name: newMeasure.check ?? BUILT_IN_SKIP_CHECK,
prog_name: newMeasure.program,
context: (newMeasure.context ?? []).reduce(
(prev, cur) => {
@@ -240,48 +250,66 @@ function NormalMeasureForm({
}
}
- return (
- <Fragment>
- <FormUI design={design} model={form.model} />
-
- <button
- onClick={() => {
- onCancel();
- }}
- class="m-4 rounded-md w-fit border-1 px-3 py-2 text-center text-sm shadow-sm "
- >
- <i18n.Translate>Cancel</i18n.Translate>
- </button>
+ const submitMeasure = () => {
+ if (form.status.status === "fail") return;
+ if (addingNew) addNewCustomMeasure();
+ else updateCurrentCustomMeasure();
+ };
- {addingNew ? (
- <button
- disabled={form.status.status === "fail"}
- onClick={addNewCustomMeasure}
- class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700 disabled:bg-gray-600"
- >
- <i18n.Translate>Add</i18n.Translate>
+ return (
+ <div class="space-y-6">
+ <div>
+ <h3 class="text-base font-semibold text-gray-950 dark:text-gray-50">
+ {addingNew ? (
+ <i18n.Translate>Create custom measure</i18n.Translate>
+ ) : (
+ <i18n.Translate>Edit custom measure</i18n.Translate>
+ )}
+ </h3>
+ <p class="mt-1 text-sm text-gray-600 dark:text-gray-300">
+ <i18n.Translate>
+ Combine a customer check with an AML program, or use SKIP to run a
+ program immediately. Context values must satisfy the selected check
+ and program requirements.
+ </i18n.Translate>
+ </p>
+ </div>
+ <FormUI design={design} model={form.model} onSubmit={submitMeasure} />
+ <div class="flex flex-wrap gap-3 border-t border-gray-200 pt-5 dark:border-gray-700">
+ <button type="button" onClick={onCancel} class={secondaryButtonClass}>
+ <i18n.Translate>Cancel</i18n.Translate>
</button>
- ) : (
- <Fragment>
+ {addingNew ? (
<button
+ type="button"
disabled={form.status.status === "fail"}
- onClick={updateCurrentCustomMeasure}
- class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700 disabled:bg-gray-600"
- >
- <i18n.Translate>Update</i18n.Translate>
- </button>
-
- <button
- onClick={removeCustomMeasure}
- class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700 disabled:bg-gray-600"
+ onClick={addNewCustomMeasure}
+ class={primaryButtonClass}
>
- <i18n.Translate>Remove</i18n.Translate>
+ <i18n.Translate>Add custom measure</i18n.Translate>
</button>
- </Fragment>
- )}
-
+ ) : (
+ <Fragment>
+ <button
+ type="button"
+ disabled={form.status.status === "fail"}
+ onClick={updateCurrentCustomMeasure}
+ class={primaryButtonClass}
+ >
+ <i18n.Translate>Save changes</i18n.Translate>
+ </button>
+ <button
+ type="button"
+ onClick={removeCustomMeasure}
+ class={dangerButtonClass}
+ >
+ <i18n.Translate>Remove custom measure</i18n.Translate>
+ </button>
+ </Fragment>
+ )}
+ </div>
<DescribeMeasure measure={form.status.result} summary={summary} />
- </Fragment>
+ </div>
);
}
function VerificationMeasureForm({
@@ -311,6 +339,8 @@ function VerificationMeasureForm({
summary,
!addingNew,
challengeType,
+ Object.keys(request.custom_measures ?? {}),
+ initial?.name,
);
const initAddr = (initial?.context ?? []).find(
@@ -319,11 +349,14 @@ function VerificationMeasureForm({
let readOnly: boolean | undefined;
let rest = {};
- if (initAddr && initAddr.value) {
- const va = JSON.parse(initAddr.value);
- readOnly = va.read_only;
- delete va.read_only;
- rest = { ...va };
+ if (initAddr?.value) {
+ const parsed = parseJsonValue(initAddr.value);
+ if (isObjectRecord(parsed)) {
+ const { read_only: parsedReadOnly, ...address } = parsed;
+ readOnly =
+ typeof parsedReadOnly === "boolean" ? parsedReadOnly : undefined;
+ rest = address;
+ }
}
const template: Partial<VerificationMeasureDefinition> = {
@@ -422,48 +455,50 @@ function VerificationMeasureForm({
}
}
- return (
- <Fragment>
- <FormUI design={design} model={form.model} />
-
- <button
- onClick={() => {
- onCancel();
- }}
- class="m-4 rounded-md w-fit border-1 px-3 py-2 text-center text-sm shadow-sm "
- >
- <i18n.Translate>Cancel</i18n.Translate>
- </button>
+ const submitMeasure = () => {
+ if (form.status.status === "fail") return;
+ if (addingNew) addNewCustomMeasure();
+ else updateCurrentCustomMeasure();
+ };
- {addingNew ? (
- <button
- disabled={form.status.status === "fail"}
- onClick={addNewCustomMeasure}
- class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700 disabled:bg-gray-600"
- >
- <i18n.Translate>Add</i18n.Translate>
+ return (
+ <div class="space-y-6">
+ <FormUI design={design} model={form.model} onSubmit={submitMeasure} />
+ <div class="flex flex-wrap gap-3 border-t border-gray-200 pt-5 dark:border-gray-700">
+ <button type="button" onClick={onCancel} class={secondaryButtonClass}>
+ <i18n.Translate>Cancel</i18n.Translate>
</button>
- ) : (
- <Fragment>
+ {addingNew ? (
<button
+ type="button"
disabled={form.status.status === "fail"}
- onClick={updateCurrentCustomMeasure}
- class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700 disabled:bg-gray-600"
+ onClick={addNewCustomMeasure}
+ class={primaryButtonClass}
>
- <i18n.Translate>Update</i18n.Translate>
+ <i18n.Translate>Add custom measure</i18n.Translate>
</button>
-
- <button
- onClick={removeCustomMeasure}
- class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700 disabled:bg-gray-600"
- >
- <i18n.Translate>Remove</i18n.Translate>
- </button>
- </Fragment>
- )}
-
+ ) : (
+ <Fragment>
+ <button
+ type="button"
+ disabled={form.status.status === "fail"}
+ onClick={updateCurrentCustomMeasure}
+ class={primaryButtonClass}
+ >
+ <i18n.Translate>Save changes</i18n.Translate>
+ </button>
+ <button
+ type="button"
+ onClick={removeCustomMeasure}
+ class={dangerButtonClass}
+ >
+ <i18n.Translate>Remove custom measure</i18n.Translate>
+ </button>
+ </Fragment>
+ )}
+ </div>
<DescribeMeasure measure={form.status.result} summary={summary} />
- </Fragment>
+ </div>
);
}
@@ -484,9 +519,15 @@ function MeasureForm({
onChanged: (name: string) => void;
onRemoved: (name: string) => void;
}) {
- const challengeType = (initial?.context ?? []).find(
+ const challengeTypeEntry = (initial?.context ?? []).find(
(c) => c.key === "challenge-type",
);
+ const parsedChallengeType = challengeTypeEntry
+ ? parseJsonValue(challengeTypeEntry.value)
+ : undefined;
+ const challengeType = isChallengeType(parsedChallengeType)
+ ? parsedChallengeType
+ : undefined;
const measureIsVerificationType = challengeType !== undefined;
const [formType, setFormType] = useState<"verification" | "normal">(
measureIsVerificationType ? "verification" : "normal",
@@ -496,24 +537,25 @@ function MeasureForm({
switch (formType) {
case "verification": {
- const cType = !challengeType
- ? undefined
- : JSON.parse(challengeType.value);
+ if (!challengeType) {
+ return null;
+ }
return (
- <div>
- <h2 class="mt-4 mb-2">
- <i18n.Translate>
- Configure verification type: {cType}
- </i18n.Translate>
- </h2>
+ <div class="space-y-5">
<div>
+ <h3 class="text-base font-semibold text-gray-950 dark:text-gray-50">
+ <i18n.Translate>
+ Configure {challengeType} verification
+ </i18n.Translate>
+ </h3>
<button
+ type="button"
onClick={async () => {
setFormType("normal");
}}
- class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
+ class="mt-3 text-sm font-semibold text-primary hover:underline dark:text-darkPrimary"
>
- <i18n.Translate>Show complete form</i18n.Translate>
+ <i18n.Translate>Use advanced measure editor</i18n.Translate>
</button>
</div>
@@ -525,26 +567,24 @@ function MeasureForm({
summary={summary}
addingNew={addingNew}
initial={initial}
- challengeType={cType}
+ challengeType={challengeType}
/>
</div>
);
}
case "normal": {
return (
- <div>
- <h2 class="mt-4 mb-2">
- <i18n.Translate>Configure measure</i18n.Translate>
- </h2>
+ <div class="space-y-5">
{measureIsVerificationType ? (
<div>
<button
+ type="button"
onClick={async () => {
setFormType("verification");
}}
- class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
+ class="text-sm font-semibold text-primary hover:underline dark:text-darkPrimary"
>
- <i18n.Translate>Show as verification</i18n.Translate>
+ <i18n.Translate>Use guided verification editor</i18n.Translate>
</button>
</div>
) : undefined}
@@ -573,6 +613,8 @@ const formDesign = (
checks: { key: string; value: KycCheckInformation }[],
summary: AvailableMeasureSummary,
cantChangeName: boolean,
+ customNames: string[],
+ currentName?: string,
): FormDesign => ({
type: "single-column",
fields: [
@@ -585,7 +627,8 @@ const formDesign = (
validator(value) {
return !value
? i18n.str`Required`
- : summary.roots[value]
+ : summary.roots[value] ||
+ (value !== currentName && customNames.includes(value))
? i18n.str`There is already a measure with that name`
: undefined;
},
@@ -600,7 +643,7 @@ const formDesign = (
label: m.key,
};
}),
- help: i18n.str`Only required when no check is specified`,
+ help: i18n.str`Runs immediately for SKIP measures, or after a successful check. It may be omitted for a check that only presents or collects information.`,
validator(value, form) {
return !value
? !form.check
@@ -614,7 +657,7 @@ const formDesign = (
type: "selectOne",
id: "check",
label: i18n.str`Check`,
- help: i18n.str`Without a check the program will run automatically`,
+ help: i18n.str`The customer-facing check to perform before the program. Leave empty to use SKIP and run the program immediately.`,
choices: checks.map((m) => {
return {
value: m.key,
@@ -637,6 +680,7 @@ const formDesign = (
type: "array",
id: "context",
label: i18n.str`Context`,
+ help: i18n.str`Configuration values required by the selected check or program. Property names and value types must match the exchange configuration.`,
labelFieldId: "key",
fields: [
{
@@ -690,6 +734,9 @@ function programAndCheckMatch(
checkName: string | undefined,
): TranslatedString | undefined {
const program = summary.programs[progName];
+ if (!program) {
+ return i18n.str`Program "${progName}" is not available`;
+ }
if (checkName === undefined) {
if (program.inputs.length > 0) {
return i18n.str`There are unsatisfied inputs: ${program.inputs.join(
@@ -699,6 +746,9 @@ function programAndCheckMatch(
return undefined;
}
const check = summary.checks[checkName];
+ if (!check) {
+ return i18n.str`Check "${checkName}" is not available`;
+ }
const missing = program.inputs.filter((d) => {
return check.outputs.indexOf(d) === -1;
});
@@ -718,6 +768,9 @@ function checkAndcontextMatch(
return undefined;
}
const check = summary.checks[checkName];
+ if (!check) {
+ return i18n.str`Check "${checkName}" is not available`;
+ }
const output = !context ? [] : context.map((d) => d.key);
const missing = check.requires.filter((d) => {
return output.indexOf(d) === -1;
@@ -735,6 +788,9 @@ function programAndContextMatch(
context: { key: string; value: string }[] | undefined,
): TranslatedString | undefined {
const check = summary.programs[program];
+ if (!check) {
+ return i18n.str`Program "${program}" is not available`;
+ }
const output = !context ? [] : context.map((d) => d.key);
const missing = check.context.filter((d) => {
return output.indexOf(d) === -1;
@@ -745,6 +801,24 @@ function programAndContextMatch(
return;
}
+function parseJsonValue(value: string): unknown {
+ try {
+ return JSON.parse(value);
+ } catch {
+ return undefined;
+ }
+}
+
+function isObjectRecord(value: unknown): value is Record<string, unknown> {
+ return typeof value === "object" && value !== null && !Array.isArray(value);
+}
+
+function isChallengeType(
+ value: unknown,
+): value is "email" | "phone" | "postal" {
+ return value === "email" || value === "phone" || value === "postal";
+}
+
function getJsonError(str: string) {
try {
JSON.parse(str);
@@ -762,7 +836,7 @@ function getJsonError(str: string) {
// check the function validateContextValueByType
function getContextValueByType(type: string, value: string) {
if (type === "number") {
- return Number.parseInt(value, 10);
+ return Number(value);
}
if (type === "boolean") {
return value === "true" ? true : value === "false" ? false : undefined;
@@ -773,8 +847,6 @@ function getContextValueByType(type: string, value: string) {
return value;
}
-const REGEX_NUMER = /^[0-9]*$/;
-
function validateContextValueByType(
i18n: InternationalizationAPI,
type: string,
@@ -782,16 +854,12 @@ function validateContextValueByType(
) {
if (!value) return i18n.str`Can't be empty`;
if (type === "number") {
- const num = Number.parseInt(value, 10);
- return !REGEX_NUMER.test(value)
- ? i18n.str`It should be a number`
- : Number.isNaN(num)
- ? i18n.str`Not a number`
- : !Number.isFinite(num)
- ? i18n.str`It should be finite`
- : !Number.isSafeInteger(num)
- ? i18n.str`It should be a safe integer`
- : undefined;
+ const num = Number(value);
+ return Number.isNaN(num)
+ ? i18n.str`Not a number`
+ : !Number.isFinite(num)
+ ? i18n.str`It should be finite`
+ : undefined;
}
if (type === "boolean") {
if (value === "true" || value === "false") return undefined;
@@ -816,40 +884,41 @@ function DescribeProgram({
}): VNode {
const { i18n } = useTranslationContext();
return (
- <div class="rounded-lg bg-gray-150 ring-1 shadow-lg border-indigo-700 border ring-gray-900/5 ">
- <dl class="flex flex-wrap">
- <div class="flex-auto pt-4 pl-4 bg-indigo-600 rounded-t-lg">
- <dt class="text-sm/6 text-white">
+ <div class="rounded-lg border border-gray-200 bg-gray-50 p-4 dark:border-gray-700 dark:bg-gray-900/60">
+ <dl class="grid gap-4 text-sm sm:grid-cols-2">
+ <div class="sm:col-span-2">
+ <dt class="font-medium text-gray-600 dark:text-gray-300">
<i18n.Translate>Program</i18n.Translate>
</dt>
- <dd class="mt-1 text-base font-semibold text-white">{name}</dd>
+ <dd class="mt-1 font-mono font-semibold text-gray-950 dark:text-gray-100">
+ {name}
+ </dd>
</div>
- <div class="mt-4 flex w-full flex-none gap-x-4 px-6">
- <dt class="flex-none text-gray-500">
+ <div class="sm:col-span-2">
+ <dt class="font-medium text-gray-600 dark:text-gray-300">
<i18n.Translate>Description</i18n.Translate>
</dt>
- <dd class="text-sm/6 ">
- <i18n.Translate>{program.description}</i18n.Translate>
+ <dd class="mt-1 text-gray-950 dark:text-gray-100">
+ {program.description}
</dd>
</div>
- <div class="mt-2 flex w-full flex-none gap-x-4 border-t border-gray-900/5 px-6 pt-2">
- <dt class="flex-none text-gray-500">
+ <div>
+ <dt class="font-medium text-gray-600 dark:text-gray-300">
<i18n.Translate>Context</i18n.Translate>
</dt>
- <dd class="text-sm/6 font-medium text-gray-900">
- <pre>{program.context.join(",")}</pre>
+ <dd class="mt-1 break-words font-mono text-gray-950 dark:text-gray-100">
+ {program.context.length ? program.context.join(", ") : "—"}
</dd>
</div>
- <div class="mt-4 flex w-full flex-none gap-x-4 px-6">
- <dt class="flex-none text-gray-500">
+ <div>
+ <dt class="font-medium text-gray-600 dark:text-gray-300">
<i18n.Translate>Inputs</i18n.Translate>
</dt>
- <dd class="text-sm/6 ">
- <pre class="whitespace-pre-wrap">{program.inputs.join(",")}</pre>
+ <dd class="mt-1 break-words font-mono text-gray-950 dark:text-gray-100">
+ {program.inputs.length ? program.inputs.join(", ") : "—"}
</dd>
</div>
</dl>
- <div class="px-4 pb-2"></div>
</div>
);
}
@@ -862,48 +931,49 @@ function DescribeCheck({
}): VNode {
const { i18n } = useTranslationContext();
return (
- <div class="mt-6 rounded-lg bg-gray-150 ring-1 shadow-lg border-indigo-700 border ring-gray-900/5 ">
- <dl class="flex flex-wrap">
- <div class="flex-auto pt-4 pl-4 bg-indigo-600 rounded-t-lg">
- <dt class="text-sm/6 text-white">
+ <div class="rounded-lg border border-gray-200 bg-gray-50 p-4 dark:border-gray-700 dark:bg-gray-900/60">
+ <dl class="grid gap-4 text-sm sm:grid-cols-2">
+ <div class="sm:col-span-2">
+ <dt class="font-medium text-gray-600 dark:text-gray-300">
<i18n.Translate>Check</i18n.Translate>
</dt>
- <dd class="mt-1 text-base font-semibold text-white">{name}</dd>
+ <dd class="mt-1 font-mono font-semibold text-gray-950 dark:text-gray-100">
+ {name}
+ </dd>
</div>
- <div class="mt-4 flex w-full flex-none gap-x-4 px-6">
- <dt class="flex-none text-gray-500">Description</dt>
- <dd class="text-sm/6 ">
- <i18n.Translate>{check.description}</i18n.Translate>
+ <div class="sm:col-span-2">
+ <dt class="font-medium text-gray-600 dark:text-gray-300">
+ <i18n.Translate>Description</i18n.Translate>
+ </dt>
+ <dd class="mt-1 text-gray-950 dark:text-gray-100">
+ {check.description}
</dd>
</div>
- <div class="mt-2 flex w-full flex-none gap-x-4 border-t border-gray-900/5 px-6 pt-2">
- <dt class="flex-none text-gray-500">
- <i18n.Translate>Output</i18n.Translate>
+ <div>
+ <dt class="font-medium text-gray-600 dark:text-gray-300">
+ <i18n.Translate>Outputs</i18n.Translate>
</dt>
- <dd class="text-sm/6 font-medium ">
- <pre class="whitespace-break-spaces">
- {check.outputs.join(", ")}
- </pre>
+ <dd class="mt-1 break-words font-mono text-gray-950 dark:text-gray-100">
+ {check.outputs.length ? check.outputs.join(", ") : "—"}
</dd>
</div>
- <div class="mt-4 flex w-full flex-none gap-x-4 px-6">
- <dt class="flex-none text-gray-500">
- <i18n.Translate>Requires</i18n.Translate>
+ <div>
+ <dt class="font-medium text-gray-600 dark:text-gray-300">
+ <i18n.Translate>Required context</i18n.Translate>
</dt>
- <dd class="text-sm/6 ">
- <pre>{check.requires.join(",")}</pre>
+ <dd class="mt-1 break-words font-mono text-gray-950 dark:text-gray-100">
+ {check.requires.length ? check.requires.join(", ") : "—"}
</dd>
</div>
- <div class="mt-4 flex w-full flex-none gap-x-4 px-6">
- <dt class="flex-none text-gray-500">
+ <div class="sm:col-span-2">
+ <dt class="font-medium text-gray-600 dark:text-gray-300">
<i18n.Translate>Fallback</i18n.Translate>
</dt>
- <dd class="text-sm/6 ">
- <pre>{check.fallback}</pre>
+ <dd class="mt-1 font-mono text-gray-950 dark:text-gray-100">
+ {check.fallback || "—"}
</dd>
</div>
</dl>
- <div class="px-4 pb-2"></div>
</div>
);
}
@@ -918,26 +988,24 @@ function DescribeContext({
}): VNode {
const { i18n } = useTranslationContext();
return (
- <div class="mt-6 rounded-lg bg-gray-150 ring-1 shadow-lg border-indigo-700 border ring-gray-900/5 ">
- <dl class="flex flex-wrap">
- <div class="flex-auto pt-4 pl-4 bg-indigo-600 rounded-t-lg">
- <dt class="text-sm/6 text-white">
- <i18n.Translate>Context</i18n.Translate>
- </dt>
- <dd class="mt-1 text-base font-semibold text-white"></dd>
- </div>
+ <div class="rounded-lg border border-gray-200 bg-gray-50 p-4 dark:border-gray-700 dark:bg-gray-900/60">
+ <h4 class="font-semibold text-gray-950 dark:text-gray-100">
+ <i18n.Translate>Context values</i18n.Translate>
+ </h4>
+ <dl class="mt-3 grid gap-3 text-sm sm:grid-cols-2">
{context.map(({ key, value }) => {
return (
- <div key={key} class="mt-4 flex w-full flex-none gap-x-4 px-6">
- <dt class="flex-none text-gray-500">{key}</dt>
- <dd class="text-sm/6 ">
- <i18n.Translate>{value}</i18n.Translate>
+ <div key={key} class="min-w-0">
+ <dt class="break-all font-mono font-medium text-gray-600 dark:text-gray-300">
+ {key}
+ </dt>
+ <dd class="mt-1 break-all font-mono text-gray-950 dark:text-gray-100">
+ {value}
</dd>
</div>
);
})}
</dl>
- <div class="px-4 pb-2"></div>
</div>
);
}
@@ -966,12 +1034,22 @@ function DescribeMeasure({
? []
: (measure.context as MeasureDefinition["context"]);
- return (
- <Fragment>
- <h2 class="mt-4 mb-2">
- <i18n.Translate>Description</i18n.Translate>
- </h2>
+ if (!program && !check && !context.length) {
+ return <Fragment />;
+ }
+ return (
+ <section class="space-y-4 border-t border-gray-200 pt-5 dark:border-gray-700">
+ <div>
+ <h3 class="text-base font-semibold text-gray-950 dark:text-gray-50">
+ <i18n.Translate>Selected pipeline</i18n.Translate>
+ </h3>
+ <p class="mt-1 text-sm text-gray-600 dark:text-gray-300">
+ <i18n.Translate>
+ Review how the exchange will execute this measure.
+ </i18n.Translate>
+ </p>
+ </div>
{!program || !programName ? undefined : (
<DescribeProgram name={programName} program={program} />
)}
@@ -981,7 +1059,7 @@ function DescribeMeasure({
{!context || !context.length ? undefined : (
<DescribeContext context={context} />
)}
- </Fragment>
+ </section>
);
}
@@ -990,6 +1068,8 @@ const verificationFormDesign = (
summary: AvailableMeasureSummary,
cantChangeName: boolean,
challengeType: "email" | "phone" | "postal",
+ customNames: string[],
+ currentName?: string,
): FormDesign => {
const em =
challengeType === "email"
@@ -1026,7 +1106,8 @@ const verificationFormDesign = (
validator(value) {
return !value
? i18n.str`Required`
- : summary.roots[value]
+ : summary.roots[value] ||
+ (value !== currentName && customNames.includes(value))
? i18n.str`There is already a measure with that name`
: undefined;
},
diff --git a/packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx b/packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx
@@ -0,0 +1,99 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import { OperationFail } from "@gnu-taler/taler-util";
+import {
+ AsyncButton,
+ Attention,
+ useTranslationContext,
+} from "@gnu-taler/web-util/browser";
+import { Fragment, h, VNode } from "preact";
+import { useState } from "preact/hooks";
+import { OfficerReady } from "../hooks/officer.js";
+import { ConfirmationModal } from "./ConfirmationModal.js";
+
+export function OfficerAccessFailure({
+ invalidSignature,
+ officer,
+ operation,
+ onRetry,
+}: {
+ invalidSignature: boolean;
+ officer: OfficerReady;
+ operation: OperationFail<unknown>;
+ onRetry: () => Promise<void>;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ const [confirmDiscard, setConfirmDiscard] = useState(false);
+ const technicalDetails = JSON.stringify(operation, null, 2);
+
+ return (
+ <>
+ <div class="space-y-4">
+ <Attention
+ type="danger"
+ title={i18n.str`Failed to check AML officer access.`}
+ >
+ <p>
+ {invalidSignature ? (
+ <i18n.Translate>
+ This officer key cannot authenticate with the exchange. Retry
+ the check or discard the key and create a new session.
+ </i18n.Translate>
+ ) : (
+ <i18n.Translate>
+ The exchange rejected the officer access check.
+ </i18n.Translate>
+ )}
+ </p>
+ <details class="mt-3">
+ <summary class="min-h-11 cursor-pointer py-2 font-semibold underline">
+ <i18n.Translate>Technical details</i18n.Translate>
+ </summary>
+ <pre class="max-h-72 overflow-auto whitespace-pre-wrap break-words rounded-md bg-white/70 p-3 text-xs text-black">
+ {technicalDetails}
+ </pre>
+ </details>
+ </Attention>
+ <div class="flex flex-wrap gap-3">
+ <AsyncButton
+ onClick={onRetry}
+ class="rounded-md bg-primary px-4 py-2 text-sm font-semibold text-onPrimary"
+ >
+ <i18n.Translate>Retry access check</i18n.Translate>
+ </AsyncButton>
+ {invalidSignature ? (
+ <button
+ type="button"
+ onClick={() => setConfirmDiscard(true)}
+ class="rounded-md px-4 py-2 text-sm font-semibold text-error hover:bg-errorContainer"
+ >
+ <i18n.Translate>Discard this key</i18n.Translate>
+ </button>
+ ) : undefined}
+ </div>
+ </div>
+ <ConfirmationModal
+ open={confirmDiscard}
+ title={<i18n.Translate>Confirmation required</i18n.Translate>}
+ confirmLabel={<i18n.Translate>Discard this key</i18n.Translate>}
+ onClose={() => setConfirmDiscard(false)}
+ onConfirm={() => {
+ setConfirmDiscard(false);
+ void officer.forget();
+ }}
+ >
+ <i18n.Translate>
+ Discarding this key removes the officer session from this browser. You
+ will need to create a new key to use the AML WebUI again.
+ </i18n.Translate>
+ </ConfirmationModal>
+ </>
+ );
+}
diff --git a/packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.test.ts b/packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.test.ts
@@ -0,0 +1,46 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import assert from "node:assert/strict";
+import test from "node:test";
+import {
+ ACCESS_RETRY_INTERVAL_MS,
+ scheduleAccessRetries,
+} from "./OfficerEnrollment.js";
+
+test("officer enrollment retries access every ten seconds", async () => {
+ let callback: (() => void) | undefined;
+ let delay: number | undefined;
+ let cleared = false;
+ let retries = 0;
+ const handle = 17 as unknown as ReturnType<typeof setInterval>;
+ const stop = scheduleAccessRetries(
+ async () => {
+ retries++;
+ },
+ (nextCallback, nextDelay) => {
+ callback = nextCallback;
+ delay = nextDelay;
+ return handle;
+ },
+ (clearedHandle) => {
+ assert.equal(clearedHandle, handle);
+ cleared = true;
+ },
+ );
+
+ assert.equal(delay, ACCESS_RETRY_INTERVAL_MS);
+ assert.ok(callback);
+ callback();
+ await Promise.resolve();
+ assert.equal(retries, 1);
+
+ stop();
+ assert.equal(cleared, true);
+});
diff --git a/packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx b/packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx
@@ -0,0 +1,169 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import {
+ AsyncButton,
+ CopyButton,
+ Time,
+ useTranslationContext,
+} from "@gnu-taler/web-util/browser";
+import { AbsoluteTime } from "@gnu-taler/taler-util";
+import { Fragment, h, VNode } from "preact";
+import { useCallback, useEffect, useRef, useState } from "preact/hooks";
+import { OfficerReady } from "../hooks/officer.js";
+import { ConfirmationModal } from "./ConfirmationModal.js";
+
+export function OfficerEnrollment({
+ officer,
+ signupEmail,
+ onRetry,
+}: {
+ officer: OfficerReady;
+ signupEmail: string;
+ onRetry: () => Promise<void>;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ const publicKey = officer.session.id;
+ const [confirmDiscard, setConfirmDiscard] = useState(false);
+ const [checking, setChecking] = useState(false);
+ const [lastCheckedAt, setLastCheckedAt] = useState<AbsoluteTime>();
+ const checkingRef = useRef(false);
+ const enrollmentSubject = i18n.str`AML officer enrollment request`;
+ const enrollmentBody = i18n.str`Please enroll this AML officer public key:\n\n${publicKey}`;
+
+ const retryAccessCheck = useCallback(async (): Promise<void> => {
+ if (checkingRef.current) return;
+ checkingRef.current = true;
+ setChecking(true);
+ try {
+ await onRetry();
+ } finally {
+ checkingRef.current = false;
+ setChecking(false);
+ setLastCheckedAt(AbsoluteTime.now());
+ }
+ }, [onRetry]);
+
+ useEffect(() => {
+ return scheduleAccessRetries(retryAccessCheck);
+ }, [retryAccessCheck]);
+
+ return (
+ <>
+ <section
+ class="mx-auto max-w-2xl py-8"
+ aria-labelledby="enrollment-title"
+ >
+ <h1
+ id="enrollment-title"
+ class="text-3xl font-bold tracking-tight text-gray-900"
+ >
+ <i18n.Translate>Officer key awaiting enrollment</i18n.Translate>
+ </h1>
+ <p class="mt-4 text-base leading-7 text-gray-700">
+ <i18n.Translate>
+ This browser has created an AML officer key, but the exchange has
+ not granted it access. Ask the exchange operator or administrator to
+ enroll the public key below.
+ </i18n.Translate>
+ </p>
+ <div class="mt-6 rounded-lg border border-outlineVariant bg-surfaceContainer p-4">
+ <p class="text-sm font-semibold text-onSurface">
+ <i18n.Translate>AML officer public key</i18n.Translate>
+ </p>
+ <div class="mt-2 flex items-start gap-2">
+ <code class="min-w-0 flex-1 break-all text-sm">{publicKey}</code>
+ <CopyButton class="shrink-0" getContent={() => publicKey}>
+ <span class="sr-only">
+ <i18n.Translate>Copy AML officer public key</i18n.Translate>
+ </span>
+ </CopyButton>
+ </div>
+ </div>
+ <p class="mt-4 text-sm text-gray-600">
+ <i18n.Translate>
+ Access is checked automatically every 10 seconds. You can also retry
+ now after the operator confirms enrollment.
+ </i18n.Translate>
+ </p>
+ <div class="mt-6 flex flex-wrap items-start gap-3">
+ <div>
+ <AsyncButton
+ onClick={retryAccessCheck}
+ class="rounded-md bg-primary px-4 py-2 text-sm font-semibold text-onPrimary"
+ >
+ <i18n.Translate>Retry access check</i18n.Translate>
+ </AsyncButton>
+ <div aria-live="polite" class="mt-2 min-h-5 text-sm text-gray-600">
+ {checking ? (
+ <span class="inline-flex items-center gap-2">
+ <span
+ aria-hidden="true"
+ class="size-2 animate-pulse rounded-full bg-primary"
+ />
+ <i18n.Translate>Checking officer access</i18n.Translate>
+ </span>
+ ) : lastCheckedAt ? (
+ <i18n.Translate>
+ Last checked at <Time timestamp={lastCheckedAt} format="pp" />
+ </i18n.Translate>
+ ) : undefined}
+ </div>
+ </div>
+ <a
+ href={`mailto:${signupEmail}?subject=${encodeURIComponent(enrollmentSubject)}&body=${encodeURIComponent(enrollmentBody)}`}
+ class="rounded-md border border-outline px-4 py-2 text-sm font-semibold"
+ >
+ <i18n.Translate>Request enrollment</i18n.Translate>
+ </a>
+ <button
+ type="button"
+ onClick={() => setConfirmDiscard(true)}
+ class="rounded-md px-4 py-2 text-sm font-semibold text-error hover:bg-errorContainer focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-error"
+ >
+ <i18n.Translate>Discard this key</i18n.Translate>
+ </button>
+ </div>
+ </section>
+ <ConfirmationModal
+ open={confirmDiscard}
+ title={<i18n.Translate>Confirmation required</i18n.Translate>}
+ confirmLabel={<i18n.Translate>Discard this key</i18n.Translate>}
+ onClose={() => setConfirmDiscard(false)}
+ onConfirm={() => {
+ setConfirmDiscard(false);
+ void officer.forget();
+ }}
+ >
+ <i18n.Translate>
+ Discarding this key removes the officer session from this browser. You
+ will need to create a new key to use the AML WebUI again.
+ </i18n.Translate>
+ </ConfirmationModal>
+ </>
+ );
+}
+
+export const ACCESS_RETRY_INTERVAL_MS = 10_000;
+
+type IntervalHandle = ReturnType<typeof setInterval>;
+
+export function scheduleAccessRetries(
+ retry: () => Promise<void>,
+ setTimer: (
+ callback: () => void,
+ delay: number,
+ ) => IntervalHandle = setInterval,
+ clearTimer: (handle: IntervalHandle) => void = clearInterval,
+): () => void {
+ const interval = setTimer(() => {
+ void retry();
+ }, ACCESS_RETRY_INTERVAL_MS);
+ return () => clearTimer(interval);
+}
diff --git a/packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.stories.tsx b/packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.stories.tsx
@@ -0,0 +1,104 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+import * as tests from "@gnu-taler/web-util/testing";
+import { VNode, h } from "preact";
+import {
+ PaytoTargetCompact,
+ PaytoTargetDetails,
+ PaytoTargetType,
+} from "./PaytoTargetDetails.js";
+
+export default { title: "payto target details" };
+
+const reserveKey = "0".repeat(52);
+const datasets: Array<{ title: string; paytoUri?: string }> = [
+ {
+ title: "IBAN with account holder and BIC",
+ paytoUri:
+ "payto://iban/POFICHBEXXX/CH9300762011623852957?receiver-name=Example%20Trading%20AG",
+ },
+ {
+ title: "IBAN without optional metadata",
+ paytoUri: "payto://iban/DE89370400440532013000",
+ },
+ {
+ title: "Taler bank",
+ paytoUri:
+ "payto://x-taler-bank/bank.example/customers/alice?receiver-name=Alice",
+ },
+ {
+ title: "Cyclos",
+ paytoUri:
+ "payto://cyclos/demo.cyclos.org/31000163100000000?receiver-name=John%20Doe",
+ },
+ {
+ title: "Bitcoin",
+ paytoUri: "payto://bitcoin/bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
+ },
+ {
+ title: "Ethereum",
+ paytoUri: "payto://ethereum/0x0102030405060708090a0b0c0d0e0f1011121314",
+ },
+ {
+ title: "Taler reserve",
+ paytoUri: `payto://taler-reserve/exchange.example/${reserveKey}`,
+ },
+ {
+ title: "Taler reserve over HTTP",
+ paytoUri: `payto://taler-reserve-http/exchange.example/${reserveKey}`,
+ },
+ {
+ title: "Void target",
+ paytoUri: "payto://void/test-account?receiver-name=Test",
+ },
+ {
+ title: "Unsupported target",
+ paytoUri: "payto://example-network/customer-42",
+ },
+ { title: "Invalid target", paytoUri: "not a payto URI" },
+ { title: "Missing target" },
+];
+
+function DatasetGallery(): VNode {
+ return (
+ <div class="grid gap-4 lg:grid-cols-2">
+ {datasets.map((dataset) => (
+ <article
+ key={dataset.title}
+ class="min-w-0 rounded-lg border border-gray-300 bg-white p-4 dark:border-gray-700 dark:bg-gray-950"
+ >
+ <h2 class="mb-4 font-semibold text-gray-950 dark:text-gray-50">
+ {dataset.title}
+ </h2>
+ <h3 class="mb-2 text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
+ Compact rendering
+ </h3>
+ <div class="mb-4 rounded-md bg-gray-50 p-3 dark:bg-gray-900">
+ <PaytoTargetCompact
+ paytoUri={dataset.paytoUri}
+ routeToAccountById={({ cid }) => `#/account/${cid}`}
+ />
+ </div>
+ <h3 class="mb-2 text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
+ Full rendering
+ </h3>
+ <div class="rounded-md bg-gray-50 p-3 dark:bg-gray-900">
+ <h4 class="mb-2 flex min-w-0 flex-wrap items-baseline gap-x-1.5 text-sm font-semibold text-gray-800 dark:text-gray-200">
+ <span>Account identifiers</span>
+ <PaytoTargetType paytoUri={dataset.paytoUri} />
+ </h4>
+ <PaytoTargetDetails paytoUri={dataset.paytoUri} />
+ </div>
+ </article>
+ ))}
+ </div>
+ );
+}
+
+export const VariousPaymentTargets = tests.createExample(DatasetGallery, {});
diff --git a/packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.test.ts b/packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.test.ts
@@ -0,0 +1,187 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+import { i18n, setupI18n } from "@gnu-taler/taler-util";
+import assert from "node:assert/strict";
+import test from "node:test";
+import { h, render } from "preact";
+import {
+ PaytoTargetCompact,
+ PaytoTargetDetails,
+ PaytoTargetType,
+ getPaytoTargetPresentation,
+} from "./PaytoTargetDetails.js";
+
+setupI18n("en", {});
+
+async function renderPaytoTargets(paytoUri: string) {
+ const happyDomPackage = "happy-dom";
+ const { Window } = await import(happyDomPackage);
+ const window = new Window({ url: "https://aml.example/" });
+ for (const [key, value] of Object.entries({
+ window,
+ document: window.document,
+ Node: window.Node,
+ Element: window.Element,
+ })) {
+ Object.defineProperty(globalThis, key, {
+ configurable: true,
+ writable: true,
+ value,
+ });
+ }
+ const container = window.document.createElement("div");
+ render(
+ h(
+ "div",
+ null,
+ h(PaytoTargetCompact, { paytoUri }),
+ h(
+ "section",
+ { id: "full-details" },
+ h(PaytoTargetType, { paytoUri }),
+ h(PaytoTargetDetails, { paytoUri }),
+ ),
+ ),
+ container as unknown as Element,
+ );
+ return { container, window };
+}
+
+test("payto targets use readable type-specific fields", () => {
+ const iban = getPaytoTargetPresentation(
+ "payto://iban/CH9300762011623852957?receiver-name=Alice&bic=POFICHBEXXX",
+ i18n,
+ );
+ assert.equal(iban?.label, "IBAN");
+ assert.equal(iban?.accountHolder, "Alice");
+ assert.equal(iban?.summary, "CH93 0076 2011 6238 5295 7");
+ assert.ok(iban?.normalizedPaytoHash);
+ assert.deepEqual(iban?.fields, [
+ { label: "Account holder", value: "Alice" },
+ { label: "IBAN", value: "CH93 0076 2011 6238 5295 7" },
+ { label: "BIC", value: "POFICHBEXXX" },
+ ]);
+
+ const talerBank = getPaytoTargetPresentation(
+ "payto://x-taler-bank/bank.example/customers/alice?receiver-name=Alice",
+ i18n,
+ );
+ assert.equal(talerBank?.label, "Taler bank");
+ assert.deepEqual(talerBank?.fields, [
+ { label: "Account holder", value: "Alice" },
+ { label: "Bank", value: "bank.example/customers" },
+ { label: "Account", value: "alice" },
+ ]);
+
+ const bitcoin = getPaytoTargetPresentation(
+ "payto://bitcoin/bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
+ i18n,
+ );
+ assert.deepEqual(bitcoin?.fields, [
+ {
+ label: "Bitcoin address",
+ value: "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
+ },
+ ]);
+
+ const cyclos = getPaytoTargetPresentation(
+ "payto://cyclos/demo.cyclos.org/31000163100000000?receiver-name=John%20Doe",
+ i18n,
+ );
+ assert.equal(cyclos?.label, "Cyclos");
+ assert.deepEqual(cyclos?.fields, [
+ { label: "Account holder", value: "John Doe" },
+ { label: "Bank", value: "https://demo.cyclos.org/" },
+ { label: "Account", value: "31000163100000000" },
+ ]);
+
+ const ethereum = getPaytoTargetPresentation(
+ "payto://ethereum/0x0102030405060708090a0b0c0d0e0f1011121314",
+ i18n,
+ );
+ assert.equal(ethereum?.label, "Ethereum");
+ assert.deepEqual(ethereum?.fields, [
+ {
+ label: "Ethereum address",
+ value: "0x0102030405060708090a0b0c0d0e0f1011121314",
+ },
+ ]);
+});
+
+test("reserve, generic, and unavailable targets have useful fallbacks", () => {
+ const reserveKey = "0".repeat(52);
+ const reserve = getPaytoTargetPresentation(
+ `payto://taler-reserve/exchange.example/${reserveKey}`,
+ i18n,
+ );
+ assert.equal(reserve?.label, "Taler reserve");
+ assert.deepEqual(reserve?.fields, [
+ { label: "Exchange", value: "https://exchange.example/" },
+ { label: "Reserve public key", value: reserveKey },
+ ]);
+
+ const httpReserve = getPaytoTargetPresentation(
+ `payto://taler-reserve-http/exchange.example/${reserveKey}`,
+ i18n,
+ );
+ assert.equal(httpReserve?.label, "Taler reserve (HTTP)");
+ assert.deepEqual(httpReserve?.fields, [
+ { label: "Exchange", value: "http://exchange.example/" },
+ { label: "Reserve public key", value: reserveKey },
+ ]);
+
+ const voidTarget = getPaytoTargetPresentation(
+ "payto://void/test-account?receiver-name=Test",
+ i18n,
+ );
+ assert.equal(voidTarget?.label, "Test account");
+ assert.deepEqual(voidTarget?.fields, [
+ { label: "Account holder", value: "Test" },
+ { label: "Account", value: "void(test-account)" },
+ ]);
+
+ const generic = getPaytoTargetPresentation(
+ "payto://example-network/customer-42",
+ i18n,
+ );
+ assert.equal(generic?.label, "EXAMPLE-NETWORK");
+ assert.equal(generic?.summary, "customer-42");
+ assert.equal(generic?.normalizedPaytoHash, undefined);
+ assert.deepEqual(generic?.fields, [
+ { label: "Account", value: "customer-42" },
+ ]);
+
+ assert.equal(getPaytoTargetPresentation("not a payto URI", i18n), undefined);
+ assert.equal(getPaytoTargetPresentation(undefined, i18n), undefined);
+});
+
+test("compact and full renderings use an accessible inline type", async () => {
+ const { container, window } = await renderPaytoTargets(
+ "payto://iban/CH9300762011623852957?receiver-name=Alice&bic=POFICHBEXXX",
+ );
+ const typeLabels = container.querySelectorAll("[data-payto-target-type]");
+ assert.equal(typeLabels.length, 2);
+ for (const typeLabel of typeLabels) {
+ assert.equal(
+ typeLabel.querySelector("[aria-hidden=true]")?.textContent,
+ "· IBAN",
+ );
+ assert.equal(
+ typeLabel.querySelector(".sr-only")?.textContent,
+ "Payment target type: IBAN",
+ );
+ }
+ assert.equal(
+ container.querySelector("#full-details dl [data-payto-target-type]"),
+ null,
+ );
+ assert.equal(container.querySelectorAll("button").length, 0);
+ render(null, container as unknown as Element);
+ await window.happyDOM.abort();
+});
diff --git a/packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx b/packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx
@@ -0,0 +1,245 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+import {
+ Paytos,
+ PaytoType,
+ Result,
+ TranslatedString,
+ encodeCrock,
+} from "@gnu-taler/taler-util";
+import {
+ encodeCrockForURI,
+ useTranslationContext,
+} from "@gnu-taler/web-util/browser";
+import { VNode, h } from "preact";
+
+export interface PaytoTargetField {
+ label: TranslatedString;
+ value: string;
+}
+
+export interface PaytoTargetPresentation {
+ label: TranslatedString | string;
+ fields: PaytoTargetField[];
+ accountHolder?: string;
+ summary: string;
+ normalizedPaytoHash?: string;
+}
+
+type I18n = ReturnType<typeof useTranslationContext>["i18n"];
+
+function PaytoTargetTypeLabel({
+ label,
+ i18n,
+}: {
+ label: TranslatedString | string;
+ i18n: I18n;
+}): VNode {
+ return (
+ <span
+ data-payto-target-type
+ class="inline-flex shrink-0 text-xs font-normal text-gray-500 dark:text-gray-400"
+ >
+ <span aria-hidden="true">· {label}</span>
+ <span class="sr-only">
+ {i18n.str`Payment target type`}: {label}
+ </span>
+ </span>
+ );
+}
+
+export function PaytoTargetType({
+ paytoUri,
+}: {
+ paytoUri?: string;
+}): VNode | null {
+ const { i18n } = useTranslationContext();
+ const presentation = getPaytoTargetPresentation(paytoUri, i18n);
+ return presentation ? (
+ <PaytoTargetTypeLabel label={presentation.label} i18n={i18n} />
+ ) : null;
+}
+
+export function getPaytoTargetPresentation(
+ paytoUri: string | undefined,
+ i18n: I18n,
+): PaytoTargetPresentation | undefined {
+ if (!paytoUri) return undefined;
+ const parsed = Paytos.fromString(paytoUri, { allowUnsupported: true });
+ if (Result.isError(parsed)) return undefined;
+
+ const payto = parsed.value;
+ const fields: PaytoTargetField[] = [];
+ const accountHolder = Paytos.getAccountHolder(payto)?.trim();
+ if (accountHolder) {
+ fields.push({ label: i18n.str`Account holder`, value: accountHolder });
+ }
+
+ let normalizedPaytoHash: string | undefined;
+ if (payto.targetType !== undefined) {
+ try {
+ normalizedPaytoHash = encodeCrock(Paytos.hashNormalized(paytoUri));
+ } catch {
+ // A malformed target must not prevent the surrounding page from rendering.
+ }
+ }
+
+ const present = (
+ label: TranslatedString | string,
+ summary = payto.displayName,
+ ): PaytoTargetPresentation => ({
+ label,
+ fields,
+ accountHolder,
+ summary,
+ normalizedPaytoHash,
+ });
+
+ switch (payto.targetType) {
+ case PaytoType.IBAN: {
+ const iban = Paytos.getAccountNumber(payto);
+ if (iban) fields.push({ label: i18n.str`IBAN`, value: iban });
+ const bic = Paytos.getBic(payto);
+ if (bic) fields.push({ label: i18n.str`BIC`, value: bic });
+ return present(i18n.str`IBAN`, iban ?? payto.displayName);
+ }
+ case PaytoType.TalerBank: {
+ const bank = Paytos.getBankHost(payto);
+ if (bank) fields.push({ label: i18n.str`Bank`, value: bank });
+ fields.push({ label: i18n.str`Account`, value: payto.account });
+ return present(i18n.str`Taler bank`);
+ }
+ case PaytoType.Cyclos:
+ fields.push({ label: i18n.str`Bank`, value: payto.url });
+ fields.push({ label: i18n.str`Account`, value: payto.account });
+ return present(i18n.str`Cyclos`);
+ case PaytoType.Bitcoin:
+ fields.push({
+ label: i18n.str`Bitcoin address`,
+ value: payto.address,
+ });
+ if (payto.reservePub) {
+ fields.push({
+ label: i18n.str`Reserve public key`,
+ value: encodeCrock(payto.reservePub),
+ });
+ }
+ return present(i18n.str`Bitcoin`);
+ case PaytoType.Ethereum:
+ fields.push({
+ label: i18n.str`Ethereum address`,
+ value: payto.address,
+ });
+ return present(i18n.str`Ethereum`);
+ case PaytoType.TalerReserve:
+ case PaytoType.TalerReserveHttp:
+ fields.push({ label: i18n.str`Exchange`, value: payto.exchange });
+ fields.push({
+ label: i18n.str`Reserve public key`,
+ value: encodeCrock(payto.reservePub),
+ });
+ return present(
+ payto.targetType === PaytoType.TalerReserve
+ ? i18n.str`Taler reserve`
+ : i18n.str`Taler reserve (HTTP)`,
+ );
+ case PaytoType.Void:
+ fields.push({
+ label: i18n.str`Account`,
+ value: payto.displayName,
+ });
+ return present(i18n.str`Test account`);
+ case undefined:
+ fields.push({
+ label: i18n.str`Account`,
+ value: payto.displayName,
+ });
+ return present(payto.target.toUpperCase());
+ }
+}
+
+export function PaytoTargetCompact({
+ paytoUri,
+ routeToAccountById,
+}: {
+ paytoUri?: string;
+ routeToAccountById?: (params: { cid: string }) => string;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ const presentation = getPaytoTargetPresentation(paytoUri, i18n);
+
+ if (!presentation) {
+ return (
+ <span class="text-sm text-gray-500 dark:text-gray-400">
+ <i18n.Translate>Account details unavailable</i18n.Translate>
+ </span>
+ );
+ }
+
+ const content = (
+ <span class="flex min-w-0 flex-col gap-0.5">
+ <span class="flex min-w-0 flex-wrap items-baseline gap-x-1.5 gap-y-0.5">
+ <span class="break-all font-medium text-gray-900 dark:text-gray-100">
+ {presentation.accountHolder ?? presentation.summary}
+ </span>
+ <PaytoTargetTypeLabel label={presentation.label} i18n={i18n} />
+ </span>
+ {presentation.accountHolder &&
+ presentation.accountHolder !== presentation.summary ? (
+ <span class="break-all text-xs text-gray-500 dark:text-gray-400">
+ {presentation.summary}
+ </span>
+ ) : undefined}
+ </span>
+ );
+
+ if (!routeToAccountById || !paytoUri || !presentation.normalizedPaytoHash) {
+ return content;
+ }
+
+ return (
+ <a
+ href={`${routeToAccountById({
+ cid: presentation.normalizedPaytoHash,
+ })}?payto=${encodeCrockForURI(paytoUri)}`}
+ class="block rounded-sm hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary"
+ >
+ {content}
+ </a>
+ );
+}
+
+export function PaytoTargetDetails({ paytoUri }: { paytoUri?: string }): VNode {
+ const { i18n } = useTranslationContext();
+ const presentation = getPaytoTargetPresentation(paytoUri, i18n);
+
+ if (!presentation) {
+ return (
+ <p class="text-sm text-gray-500 dark:text-gray-400">
+ <i18n.Translate>Account details unavailable</i18n.Translate>
+ </p>
+ );
+ }
+
+ return (
+ <dl class="space-y-2 text-sm text-gray-700 dark:text-gray-300">
+ {presentation.fields.map((field, index) => (
+ <div
+ key={`${field.label}-${index}`}
+ class="grid gap-x-3 gap-y-0.5 sm:grid-cols-[8rem_minmax(0,1fr)]"
+ >
+ <dt class="font-semibold">{field.label}</dt>
+ <dd class="min-w-0">
+ <span class="min-w-0 break-all">{field.value}</span>
+ </dd>
+ </div>
+ ))}
+ </dl>
+ );
+}
diff --git a/packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx b/packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx
@@ -17,8 +17,10 @@ import {
amountFractionalBase,
AmountJson,
Amounts,
+ InternationalizationAPI,
KycRule,
LimitOperationType,
+ TranslatedString,
} from "@gnu-taler/taler-util";
import {
Attention,
@@ -38,12 +40,12 @@ export function RulesInfo({
rules,
onEdit,
onRemove,
- onNew,
+ editable = false,
}: {
rules: KycRule[];
- onNew?: () => void;
onEdit?: (k: KycRule, idx: number) => void;
onRemove?: (k: KycRule, idx: number) => void;
+ editable?: boolean;
}): VNode {
const { i18n } = useTranslationContext();
const { config } = useExchangeApiContext();
@@ -59,31 +61,23 @@ export function RulesInfo({
This means that no operation has any limit.
</i18n.Translate>
</Attention>
- {!onNew ? undefined : (
- <button
- onClick={() => {
- onNew();
- }}
- class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700 disabled:bg-gray-600"
- >
- <i18n.Translate>Add custom rule</i18n.Translate>
- </button>
- )}
</div>
);
}
const theRules = rules.map((r, idx): KycRuleWithIdx => ({ ...r, idx }));
- const sorted = theRules.sort((a, b) => {
- return sortKycRules(a, b);
- });
+ const sorted = editable
+ ? theRules
+ : theRules.sort((a, b) => {
+ return sortKycRules(a, b);
+ });
const hasActions = !!onEdit || !!onRemove;
return (
<Fragment>
- <div class="">
+ <div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-300">
<thead class="bg-gray-50">
<tr>
@@ -105,36 +99,24 @@ export function RulesInfo({
>
<i18n.Translate>Escalation</i18n.Translate>
</th>
+ <th
+ scope="col"
+ class="relative py-3.5 pl-3 pr-4 sm:pr-6 text-left"
+ >
+ <i18n.Translate>Visibility</i18n.Translate>
+ </th>
+ <th
+ scope="col"
+ class="relative py-3.5 pl-3 pr-4 sm:pr-6 text-right"
+ >
+ <i18n.Translate>Priority</i18n.Translate>
+ </th>
{!hasActions ? undefined : (
<th
scope="col"
class="relative py-3.5 pl-3 pr-4 sm:pr-6 text-right"
>
- {!onNew ? undefined : (
- <button
- onClick={() => {
- onNew();
- }}
- class="rounded-md w-fit border-0 p-1 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700 disabled:bg-gray-600"
- >
- <i18n.Translate>
- <svg
- xmlns="http://www.w3.org/2000/svg"
- fill="none"
- viewBox="0 0 24 24"
- stroke-width="1.5"
- stroke="currentColor"
- class="size-6"
- >
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- d="M12 4.5v15m7.5-7.5h-15"
- />
- </svg>
- </i18n.Translate>
- </button>
- )}
+ <i18n.Translate>Actions</i18n.Translate>
</th>
)}
</tr>
@@ -144,49 +126,12 @@ export function RulesInfo({
{sorted.map((r, k) => {
return (
<tr class="even:bg-gray-200 " key={k}>
- <td class="flex whitespace-nowrap py-2 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6 text-left">
- <span class="mx-2">
- {r.exposed ? (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- fill="none"
- viewBox="0 0 24 24"
- stroke-width="1.5"
- stroke="currentColor"
- class="size-6"
- >
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z"
- />
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"
- />
- </svg>
- ) : (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- fill="none"
- viewBox="0 0 24 24"
- stroke-width="1.5"
- stroke="currentColor"
- class="size-6 text-gray-500"
- >
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- d="M3.98 8.223A10.477 10.477 0 0 0 1.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.451 10.451 0 0 1 12 4.5c4.756 0 8.773 3.162 10.065 7.498a10.522 10.522 0 0 1-4.293 5.774M6.228 6.228 3 3m3.228 3.228 3.65 3.65m7.894 7.894L21 21m-3.228-3.228-3.65-3.65m0 0a3 3 0 1 0-4.243-4.243m4.242 4.242L9.88 9.88"
- />
- </svg>
- )}
- </span>
- <span>{r.operation_type}</span>
+ <td class="whitespace-nowrap py-2 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6 text-left">
+ {labelForOperationType(r.operation_type, i18n)}
</td>
<td class=" relative whitespace-nowrap py-2 pl-3 pr-4 text-sm font-medium sm:pr-6 text-right">
- {r.timeframe.d_us === "forever" ? (
+ {r.timeframe.d_us === "forever" ||
+ r.timeframe.d_us === 0 ? (
<RenderAmount
value={Amounts.parseOrThrow(r.threshold)}
spec={config.config.currency_specification}
@@ -208,19 +153,46 @@ export function RulesInfo({
)}
</td>
<td class=" relative whitespace-nowrap py-2 pl-3 pr-4 text-sm font-medium sm:pr-6 text-right">
- {r.is_and_combinator ? (
+ <div class="flex flex-wrap justify-end gap-1">
<span class="text-gray-500">
- <i18n.Translate>(all)</i18n.Translate>
+ {r.measures.some(isVerbotenMeasure) ? (
+ <i18n.Translate>Block operation</i18n.Translate>
+ ) : r.is_and_combinator ? (
+ <i18n.Translate>All required:</i18n.Translate>
+ ) : (
+ <i18n.Translate>Any one:</i18n.Translate>
+ )}
</span>
+ {r.measures.some(isVerbotenMeasure)
+ ? undefined
+ : r.measures.map((measure) => (
+ <span
+ key={measure}
+ class="rounded bg-gray-100 px-1.5 py-0.5"
+ >
+ {measure}
+ </span>
+ ))}
+ </div>
+ </td>
+ <td class="whitespace-nowrap py-2 pl-3 pr-4 text-sm sm:pr-6 text-left">
+ {r.exposed ? (
+ <i18n.Translate>Customer-visible</i18n.Translate>
) : (
- <Fragment />
+ <i18n.Translate>Internal</i18n.Translate>
)}
- {r.measures}
+ </td>
+ <td class="whitespace-nowrap py-2 pl-3 pr-4 text-sm font-medium sm:pr-6 text-right">
+ {r.display_priority}
</td>
{!hasActions ? undefined : (
<td class="relative flex justify-end whitespace-nowrap py-2 pl-3 pr-4 text-sm font-medium sm:pr-6">
{!onEdit ? undefined : (
- <button onClick={() => onEdit(r, r.idx)}>
+ <button
+ type="button"
+ aria-label={i18n.str`Edit ${labelForOperationType(r.operation_type, i18n)} rule`}
+ onClick={() => onEdit(r, r.idx)}
+ >
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
@@ -228,6 +200,7 @@ export function RulesInfo({
stroke-width="1.5"
stroke="currentColor"
class="size-6 text-green-700"
+ aria-hidden="true"
>
<path
stroke-linecap="round"
@@ -238,7 +211,11 @@ export function RulesInfo({
</button>
)}
{!onRemove ? undefined : (
- <button onClick={() => onRemove(r, r.idx)}>
+ <button
+ type="button"
+ aria-label={i18n.str`Remove ${labelForOperationType(r.operation_type, i18n)} rule`}
+ onClick={() => onRemove(r, r.idx)}
+ >
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
@@ -246,6 +223,7 @@ export function RulesInfo({
stroke-width="1.5"
stroke="currentColor"
class="size-6 text-red-700"
+ aria-hidden="true"
>
<path
stroke-linecap="round"
@@ -267,6 +245,34 @@ export function RulesInfo({
);
}
+function isVerbotenMeasure(name: string): boolean {
+ return name.toUpperCase() === "VERBOTEN";
+}
+
+export function labelForOperationType(
+ op: LimitOperationType,
+ i18n: InternationalizationAPI,
+): TranslatedString {
+ switch (op) {
+ case LimitOperationType.withdraw:
+ return i18n.ctx("operation type")`Withdraw`;
+ case LimitOperationType.deposit:
+ return i18n.ctx("operation type")`Deposit`;
+ case LimitOperationType.merge:
+ return i18n.ctx("operation type")`Merge`;
+ case LimitOperationType.aggregate:
+ return i18n.ctx("operation type")`Aggregate`;
+ case LimitOperationType.balance:
+ return i18n.ctx("operation type")`Balance`;
+ case LimitOperationType.refund:
+ return i18n.ctx("operation type")`Refund`;
+ case LimitOperationType.close:
+ return i18n.ctx("operation type")`Close`;
+ case LimitOperationType.transaction:
+ return i18n.ctx("operation type")`Transaction`;
+ }
+}
+
export function rate(a: AmountJson, b: number): number {
const af = toFloat(a);
const bf = b;
diff --git a/packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.test.tsx b/packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.test.tsx
@@ -0,0 +1,193 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+import {
+ AmlDecision,
+ AmlSpaDialect,
+ AvailableMeasureSummary,
+ setupI18n,
+} from "@gnu-taler/taler-util";
+import assert from "node:assert/strict";
+import test from "node:test";
+import { h, render } from "preact";
+import {
+ ShowDecisionLimitInfo,
+ parseImmediateMeasures,
+} from "./ShowDecisionLimitInfo.js";
+
+setupI18n("en", {});
+
+async function installDom() {
+ const happyDomPackage = "happy-dom";
+ const { Window } = await import(happyDomPackage);
+ const window = new Window({ url: "https://aml.example/" });
+ for (const [key, value] of Object.entries({
+ window,
+ document: window.document,
+ location: window.location,
+ history: window.history,
+ navigator: window.navigator,
+ addEventListener: window.addEventListener.bind(window),
+ removeEventListener: window.removeEventListener.bind(window),
+ Node: window.Node,
+ Element: window.Element,
+ HTMLElement: window.HTMLElement,
+ MouseEvent: window.MouseEvent,
+ })) {
+ Object.defineProperty(globalThis, key, {
+ configurable: true,
+ writable: true,
+ value,
+ });
+ }
+ return window;
+}
+
+async function eventually(assertion: () => void): Promise<void> {
+ let lastError: unknown;
+ for (let attempt = 0; attempt < 10; attempt++) {
+ try {
+ assertion();
+ return;
+ } catch (error) {
+ lastError = error;
+ await new Promise((resolve) => setTimeout(resolve, 0));
+ }
+ }
+ throw lastError;
+}
+
+const account = "1111111111111111111111111111111111111111111111111111";
+const decision: AmlDecision = {
+ h_payto: account as never,
+ is_wallet: false,
+ rowid: 12 as never,
+ justification: "Ownership changed.",
+ new_measures: "+custom-review standard-monitoring",
+ decider_pub: "OFFICER-PUBLIC-KEY",
+ decider_name: "Alex Compliance",
+ kyc_attributes_rowid: 44 as never,
+ decision_time: { t_s: 1_800_000_000 },
+ properties: { high_risk: true },
+ limits: {
+ expiration_time: { t_s: "never" },
+ successor_measure: "standard-monitoring",
+ rules: [],
+ custom_measures: {
+ "custom-review": {
+ check_name: "identity-form",
+ prog_name: "review-program",
+ },
+ },
+ },
+ to_investigate: true,
+ is_active: true,
+};
+const measures: AvailableMeasureSummary = {
+ roots: {
+ "standard-monitoring": {
+ check_name: "skip",
+ prog_name: "review-program",
+ },
+ },
+ checks: {
+ "identity-form": {
+ description: "Review identity documents",
+ requires: [],
+ outputs: [],
+ fallback: "manual-review",
+ },
+ },
+ programs: {
+ "review-program": {
+ description: "Manual officer review",
+ context: [],
+ inputs: [],
+ },
+ },
+ default_rules: [],
+};
+const routeToShowCollectedInfo = ({
+ cid,
+ rowId,
+}: {
+ cid: string;
+ rowId: string;
+}) => `/account/${cid}/attributes/${rowId}`;
+
+test("immediate measure expressions preserve AND and OR semantics", () => {
+ assert.deepEqual(parseImmediateMeasures("+one two"), {
+ names: ["one", "two"],
+ isAnd: true,
+ });
+ assert.deepEqual(parseImmediateMeasures("one two"), {
+ names: ["one", "two"],
+ isAnd: false,
+ });
+ assert.deepEqual(parseImmediateMeasures(), { names: [], isAnd: false });
+});
+
+test("current decision renders provenance, impact, properties and attribute link", async () => {
+ const window = await installDom();
+ const container = window.document.createElement("div");
+ render(
+ <ShowDecisionLimitInfo
+ decision={decision}
+ dialect={AmlSpaDialect.TOPS}
+ serverMeasures={measures}
+ account={account}
+ routeToShowCollectedInfo={routeToShowCollectedInfo}
+ presentation="static"
+ />,
+ container as unknown as Element,
+ );
+ assert.match(container.textContent, /Alex Compliance/);
+ assert.match(container.textContent, /Under investigation/);
+ assert.match(
+ container.textContent,
+ /All listed measures were requested \(AND\)/,
+ );
+ assert.match(container.textContent, /custom-review/);
+ assert.match(container.textContent, /Built-in check/);
+ assert.match(container.textContent, /high_risk/);
+ const link = container.querySelector("a");
+ assert.equal(link?.getAttribute("href"), `/account/${account}/attributes/44`);
+ render(null, container as unknown as Element);
+ await window.happyDOM.abort();
+});
+
+test("historical automated outcomes retain unresolved measure names", async () => {
+ const window = await installDom();
+ const container = window.document.createElement("div");
+ render(
+ <ShowDecisionLimitInfo
+ decision={{
+ ...decision,
+ decider_pub: undefined,
+ decider_name: undefined,
+ new_measures: "retired-measure",
+ is_active: false,
+ }}
+ dialect={AmlSpaDialect.TOPS}
+ serverMeasuresUnavailable
+ account={account}
+ routeToShowCollectedInfo={routeToShowCollectedInfo}
+ presentation="history-disclosure"
+ />,
+ container as unknown as Element,
+ );
+ assert.match(container.textContent, /Automated outcome/);
+ assert.match(container.textContent, /Historical/);
+ container.querySelector("button")?.click();
+ await eventually(() => {
+ assert.match(container.textContent, /retired-measure/);
+ assert.match(container.textContent, /configuration could not be loaded/);
+ });
+ render(null, container as unknown as Element);
+ await window.happyDOM.abort();
+});
diff --git a/packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx b/packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx
@@ -1,160 +1,450 @@
/*
This file is part of GNU Taler
- (C) 2022-2025 Taler Systems S.A.
+ (C) 2022-2026 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 { AbsoluteTime, KycRule } from "@gnu-taler/taler-util";
+*/
+import {
+ AbsoluteTime,
+ AmlDecision,
+ AmlSpaDialect,
+ AvailableMeasureSummary,
+ MeasureInformation,
+} from "@gnu-taler/taler-util";
import { Time, useTranslationContext } from "@gnu-taler/web-util/browser";
-import { Fragment, h, VNode } from "preact";
+import { ComponentChildren, Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
-import { useServerMeasures } from "../hooks/server-info.js";
+import { Link } from "wouter-preact";
+import { isBuiltInSkipCheck } from "../utils/measure-check.js";
+import { DecisionProperties } from "./DecisionProperties.js";
import { RulesInfo } from "./RulesInfo.js";
-const TALER_SCREEN_ID = 120;
+export interface DecisionAuditProps {
+ decision: AmlDecision;
+ dialect: AmlSpaDialect;
+ serverMeasures?: AvailableMeasureSummary;
+ serverMeasuresLoading?: boolean;
+ serverMeasuresUnavailable?: boolean;
+ account: string;
+ routeToShowCollectedInfo: (params: { cid: string; rowId: string }) => string;
+ presentation: "static" | "history-disclosure";
+}
-export function ShowDecisionLimitInfo({
- rules,
- since,
- until,
- startOpen,
- justification,
- fixed,
- measure,
-}: {
- since: AbsoluteTime;
- until: AbsoluteTime;
- justification?: string;
- rules: KycRule[];
- startOpen?: boolean;
- fixed?: boolean;
- measure: string;
-}): VNode {
- const { i18n } = useTranslationContext();
- const [opened, setOpened] = useState(startOpen ?? false);
+export function ShowDecisionLimitInfo(props: DecisionAuditProps): VNode {
+ const [opened, setOpened] = useState(false);
- function Header() {
+ if (props.presentation === "static") {
return (
- <div
- data-fixed={!!fixed}
- class="p-4 relative bg-gray-200 flex justify-between data-[fixed=false]:cursor-pointer"
- onClick={() => {
- if (!fixed) {
- setOpened((o) => !o);
- }
- }}
- >
- <div class="flex min-w-0 gap-x-4">
- <div class="flex rounded-md shadow-sm border-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600">
- <div class="pointer-events-none bg-gray-300 inset-y-0 flex items-center px-3">
- <i18n.Translate>Since</i18n.Translate>
- </div>
- <div class="p-2 bg-gray-50 text-right rounded-md rounded-l-none data-[left=true]:text-left w-full py-1.5 pl-3 text-gray-900 placeholder:text-gray-50 sm:text-sm sm:leading-6">
- <Time format="dd/MM/yyyy HH:mm:ss" timestamp={since} />
- </div>
- </div>
- </div>
- <div class="flex shrink-0 items-center gap-x-4">
- <div class="flex rounded-md shadow-sm border-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600">
- <div class="pointer-events-none bg-gray-300 inset-y-0 flex items-center px-3">
- {AbsoluteTime.isExpired(until) ? (
- <i18n.Translate>Expired</i18n.Translate>
- ) : (
- <i18n.Translate>Expires</i18n.Translate>
- )}
- </div>
- <div class="p-2 bg-gray-50 text-right rounded-md rounded-l-none data-[left=true]:text-left w-full py-1.5 pl-3 text-gray-900 placeholder:text-gray-50 sm:text-sm sm:leading-6">
- <Time format="dd/MM/yyyy HH:mm:ss" timestamp={until} />
- </div>
- </div>
- {AbsoluteTime.isNever(until) ? undefined : (
- <div class="flex rounded-md shadow-sm border-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600">
- <div class="pointer-events-none p-2 bg-gray-300 inset-y-0 flex items-center ">
- <i18n.Translate>Successor measure</i18n.Translate>
- </div>
- <div class="p-2 bg-gray-50 rounded-md rounded-l-none data-[left=true]:text-left text-gray-900 placeholder:text-gray-50 sm:text-sm sm:leading-6">
- {measure}
- </div>
- </div>
- )}
- {fixed ? (
- <Fragment />
- ) : (
- <div class="rounded-full bg-gray-50 p-2">
- <svg
- xmlns="http://www.w3.org/2000/svg"
- fill="none"
- viewBox="0 0 24 24"
- stroke-width="1.5"
- stroke="currentColor"
- class="size-6 w-6 h-6"
- >
- {opened ? (
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- d="m19.5 8.25-7.5 7.5-7.5-7.5"
- />
- ) : (
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- d="m4.5 15.75 7.5-7.5 7.5 7.5"
- />
- )}
- </svg>
- </div>
- )}
- </div>
+ <div class="rounded-lg border border-gray-300 p-4 dark:border-gray-700 sm:p-5">
+ <DecisionDetails {...props} />
</div>
);
}
- if (!opened) {
- return (
- <div class="overflow-hidden border border-gray-800 rounded-xl">
- <Header />
- </div>
- );
- }
+ return (
+ <div class="overflow-hidden rounded-lg border border-gray-300 dark:border-gray-700">
+ <button
+ type="button"
+ aria-expanded={opened}
+ class="flex w-full items-start justify-between gap-3 bg-gray-50 p-4 text-left hover:bg-gray-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-inset focus-visible:outline-primary dark:bg-gray-900 dark:hover:bg-gray-800"
+ onClick={() => setOpened((value) => !value)}
+ >
+ <DecisionMetadata decision={props.decision} compact />
+ <Chevron expanded={opened} />
+ </button>
+ {opened ? (
+ <div class="border-t border-gray-200 p-4 dark:border-gray-700 sm:p-5">
+ <DecisionDetails {...props} hideMetadata />
+ </div>
+ ) : undefined}
+ </div>
+ );
+}
+function DecisionDetails({
+ decision,
+ dialect,
+ serverMeasures,
+ serverMeasuresLoading,
+ serverMeasuresUnavailable,
+ account,
+ routeToShowCollectedInfo,
+ hideMetadata,
+}: DecisionAuditProps & { hideMetadata?: boolean }): VNode {
+ const { i18n } = useTranslationContext();
+ const immediate = parseImmediateMeasures(decision.new_measures);
+ const customMeasures = Object.entries(decision.limits.custom_measures ?? {});
return (
- <div class="overflow-hidden border border-gray-800 rounded-xl">
- <Header />
- <div class="p-4 grid gap-y-4">
- {!justification ? undefined : (
- <div class="">
- <label
- for="comment"
- class="block text-sm font-medium leading-6 text-gray-900"
+ <div class="space-y-6">
+ {hideMetadata ? undefined : <DecisionMetadata decision={decision} />}
+
+ <AuditSection title={i18n.str`Decision provenance`}>
+ <dl class="grid gap-4 text-sm sm:grid-cols-2">
+ <SummaryDatum label={i18n.str`Decision made by`}>
+ {decision.decider_name ??
+ (decision.decider_pub
+ ? i18n.str`AML officer (name unavailable)`
+ : i18n.str`Automated outcome`)}
+ </SummaryDatum>
+ <SummaryDatum label={i18n.str`Resulting case disposition`}>
+ {decision.to_investigate
+ ? i18n.str`Under investigation`
+ : i18n.str`Not under investigation`}
+ </SummaryDatum>
+ </dl>
+ <p class="mt-4 whitespace-pre-wrap break-words text-sm leading-6 text-gray-700 dark:text-gray-300">
+ <span class="font-semibold text-gray-900 dark:text-gray-100">
+ <i18n.Translate>Justification:</i18n.Translate>{" "}
+ </span>
+ {decision.justification || i18n.str`No justification was recorded.`}
+ </p>
+ {decision.kyc_attributes_rowid === undefined ? undefined : (
+ <p class="mt-3 text-sm">
+ <Link
+ class="font-semibold text-primary underline underline-offset-2 dark:text-darkPrimary"
+ href={routeToShowCollectedInfo({
+ cid: account,
+ rowId: String(decision.kyc_attributes_rowid),
+ })}
>
- <i18n.Translate>AML officer justification</i18n.Translate>
- </label>
- <div class="mt-2">
- <textarea
- rows={2}
- readOnly
- name="comment"
- id="comment"
- class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- >
- {justification}
- </textarea>
+ <i18n.Translate>
+ View submitted customer information
+ </i18n.Translate>
+ </Link>
+ </p>
+ )}
+ </AuditSection>
+
+ <AuditSection title={i18n.str`Immediate measures requested`}>
+ {!immediate.names.length ? (
+ <p class="text-sm text-gray-600 dark:text-gray-300">
+ <i18n.Translate>
+ This decision did not request an immediate measure.
+ </i18n.Translate>
+ </p>
+ ) : (
+ <div class="space-y-3">
+ <p class="text-sm text-gray-600 dark:text-gray-300">
+ {immediate.isAnd
+ ? i18n.str`All listed measures were requested (AND).`
+ : i18n.str`Any listed measure may satisfy the request (OR).`}
+ </p>
+ <div class="space-y-2">
+ {immediate.names.map((name) => (
+ <MeasureDefinition
+ key={name}
+ name={name}
+ stored={decision.limits.custom_measures?.[name]}
+ configured={serverMeasures?.roots[name]}
+ serverMeasures={serverMeasures}
+ serverMeasuresLoading={serverMeasuresLoading}
+ serverMeasuresUnavailable={serverMeasuresUnavailable}
+ />
+ ))}
</div>
</div>
)}
+ </AuditSection>
- <RulesInfo rules={rules} />
+ <AuditSection title={i18n.str`Operation rules`}>
+ {decision.limits.rules.length ? (
+ <RulesInfo rules={decision.limits.rules} />
+ ) : (
+ <p class="text-sm text-gray-600 dark:text-gray-300">
+ <i18n.Translate>
+ No operation-specific rules were stored.
+ </i18n.Translate>
+ </p>
+ )}
+ </AuditSection>
+
+ <AuditSection title={i18n.str`Policy transition`}>
+ <dl class="grid gap-4 text-sm sm:grid-cols-2">
+ <SummaryDatum label={i18n.str`Policy expires`}>
+ <Time
+ format="PPp"
+ timestamp={AbsoluteTime.fromProtocolTimestamp(
+ decision.limits.expiration_time,
+ )}
+ />
+ </SummaryDatum>
+ <SummaryDatum label={i18n.str`Successor measure`}>
+ {decision.limits.successor_measure ?? i18n.str`Exchange defaults`}
+ </SummaryDatum>
+ </dl>
+ </AuditSection>
+
+ <AuditSection title={i18n.str`Custom measure definitions`}>
+ {!customMeasures.length ? (
+ <p class="text-sm text-gray-600 dark:text-gray-300">
+ <i18n.Translate>No custom measures were stored.</i18n.Translate>
+ </p>
+ ) : (
+ <div class="space-y-2">
+ {customMeasures.map(([name, stored]) => (
+ <MeasureDefinition
+ key={name}
+ name={name}
+ stored={stored}
+ configured={serverMeasures?.roots[name]}
+ serverMeasures={serverMeasures}
+ serverMeasuresLoading={serverMeasuresLoading}
+ serverMeasuresUnavailable={serverMeasuresUnavailable}
+ custom
+ />
+ ))}
+ </div>
+ )}
+ </AuditSection>
+
+ <AuditSection title={i18n.str`Account properties`}>
+ <DecisionProperties
+ properties={decision.properties}
+ dialect={dialect}
+ />
+ </AuditSection>
+
+ <details class="border-t border-gray-200 pt-5 dark:border-gray-700">
+ <summary class="min-h-10 cursor-pointer py-2 text-sm font-semibold text-gray-900 dark:text-gray-100">
+ <i18n.Translate>Technical details</i18n.Translate>
+ </summary>
+ <dl class="mt-2 grid gap-3 text-sm sm:grid-cols-2">
+ <SummaryDatum label={i18n.str`Decision row`}>
+ {decision.rowid}
+ </SummaryDatum>
+ <SummaryDatum label={i18n.str`Officer public key`}>
+ <code class="break-all">
+ {decision.decider_pub ?? i18n.str`Not applicable`}
+ </code>
+ </SummaryDatum>
+ </dl>
+ </details>
+ </div>
+ );
+}
+
+export function parseImmediateMeasures(value?: string): {
+ names: string[];
+ isAnd: boolean;
+} {
+ const trimmed = value?.trim() ?? "";
+ const isAnd = trimmed.startsWith("+");
+ const expression = isAnd ? trimmed.slice(1).trim() : trimmed;
+ return {
+ isAnd,
+ names: expression ? expression.split(/\s+/).filter(Boolean) : [],
+ };
+}
+
+function MeasureDefinition({
+ name,
+ stored,
+ configured,
+ serverMeasures,
+ serverMeasuresLoading,
+ serverMeasuresUnavailable,
+ custom,
+}: {
+ name: string;
+ stored?: MeasureInformation;
+ configured?: MeasureInformation;
+ serverMeasures?: AvailableMeasureSummary;
+ serverMeasuresLoading?: boolean;
+ serverMeasuresUnavailable?: boolean;
+ custom?: boolean;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ const definition = stored ?? configured;
+ const check = definition
+ ? serverMeasures?.checks[definition.check_name]
+ : undefined;
+ const program = definition?.prog_name
+ ? serverMeasures?.programs[definition.prog_name]
+ : undefined;
+ const builtInSkip = definition
+ ? isBuiltInSkipCheck(definition.check_name)
+ : false;
+ return (
+ <div class="rounded-md border border-gray-200 bg-gray-50 p-3 text-sm dark:border-gray-700 dark:bg-gray-900/60">
+ <div class="flex flex-wrap items-center gap-2">
+ <code class="font-semibold text-gray-950 dark:text-gray-50">
+ {name}
+ </code>
+ {custom ? (
+ <span class="rounded-full bg-blue-100 px-2 py-0.5 text-xs font-semibold text-blue-800 dark:bg-blue-950 dark:text-blue-200">
+ <i18n.Translate>Stored custom definition</i18n.Translate>
+ </span>
+ ) : undefined}
</div>
+ {!definition ? (
+ <p class="mt-2 text-amber-800 dark:text-amber-300">
+ {serverMeasuresLoading
+ ? i18n.str`Current measure metadata is still loading; the stored machine name is shown.`
+ : serverMeasuresUnavailable
+ ? i18n.str`The current measure configuration could not be loaded; the stored machine name is shown.`
+ : i18n.str`No stored or currently configured definition is available for this reference.`}
+ </p>
+ ) : (
+ <dl class="mt-2 grid gap-x-5 gap-y-2 sm:grid-cols-2">
+ <CompactDatum label={i18n.str`Check`}>
+ <code>{definition.check_name}</code>
+ <span class="block text-gray-600 dark:text-gray-300">
+ {builtInSkip
+ ? i18n.str`Built-in check that requires no customer interaction.`
+ : (check?.description ?? i18n.str`Description unavailable`)}
+ </span>
+ </CompactDatum>
+ <CompactDatum label={i18n.str`Program`}>
+ {definition.prog_name ? (
+ <>
+ <code>{definition.prog_name}</code>
+ <span class="block text-gray-600 dark:text-gray-300">
+ {program?.description ?? i18n.str`Description unavailable`}
+ </span>
+ </>
+ ) : (
+ i18n.str`None`
+ )}
+ </CompactDatum>
+ {definition.operation_type ? (
+ <CompactDatum label={i18n.str`Operation`}>
+ {definition.operation_type}
+ </CompactDatum>
+ ) : undefined}
+ <CompactDatum label={i18n.str`Voluntary`}>
+ {definition.voluntary ? i18n.str`Yes` : i18n.str`No`}
+ </CompactDatum>
+ {definition.context ? (
+ <CompactDatum label={i18n.str`Context`}>
+ <pre class="overflow-auto whitespace-pre-wrap break-all text-xs">
+ {JSON.stringify(definition.context, null, 2)}
+ </pre>
+ </CompactDatum>
+ ) : undefined}
+ </dl>
+ )}
</div>
);
}
+
+function DecisionMetadata({
+ decision,
+ compact,
+}: {
+ decision: AmlDecision;
+ compact?: boolean;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ const until = AbsoluteTime.fromProtocolTimestamp(
+ decision.limits.expiration_time,
+ );
+ return (
+ <div
+ class={`grid min-w-0 flex-1 gap-4 sm:grid-cols-2 xl:grid-cols-4 ${
+ compact ? "" : "border-y border-gray-200 py-4 dark:border-gray-700"
+ }`}
+ >
+ <SummaryDatum label={i18n.str`Decision date`}>
+ <Time
+ format="PPp"
+ timestamp={AbsoluteTime.fromProtocolTimestamp(decision.decision_time)}
+ />
+ </SummaryDatum>
+ <SummaryDatum
+ label={
+ AbsoluteTime.isExpired(until) ? i18n.str`Expired` : i18n.str`Expires`
+ }
+ >
+ <Time format="PPp" timestamp={until} />
+ </SummaryDatum>
+ <SummaryDatum label={i18n.str`Decision status`}>
+ {decision.is_active ? i18n.str`Current` : i18n.str`Historical`}
+ </SummaryDatum>
+ <SummaryDatum label={i18n.str`Made by`}>
+ {decision.decider_name ??
+ (decision.decider_pub
+ ? i18n.str`AML officer`
+ : i18n.str`Automated outcome`)}
+ </SummaryDatum>
+ </div>
+ );
+}
+
+function AuditSection({
+ title,
+ children,
+}: {
+ title: string;
+ children: ComponentChildren;
+}): VNode {
+ return (
+ <section class="border-t border-gray-200 pt-5 first:border-0 first:pt-0 dark:border-gray-700">
+ <h3 class="mb-3 text-base font-semibold text-gray-950 dark:text-gray-50">
+ {title}
+ </h3>
+ {children}
+ </section>
+ );
+}
+
+function SummaryDatum({
+ label,
+ children,
+}: {
+ label: string;
+ children: ComponentChildren;
+}): VNode {
+ return (
+ <span class="min-w-0">
+ <span class="block text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
+ {label}
+ </span>
+ <span class="mt-1 block break-words text-sm font-medium text-gray-900 dark:text-gray-100">
+ {children}
+ </span>
+ </span>
+ );
+}
+
+function CompactDatum({
+ label,
+ children,
+}: {
+ label: string;
+ children: ComponentChildren;
+}): VNode {
+ return (
+ <div>
+ <dt class="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
+ {label}
+ </dt>
+ <dd class="mt-1 break-words text-gray-900 dark:text-gray-100">
+ {children}
+ </dd>
+ </div>
+ );
+}
+
+function Chevron({ expanded }: { expanded: boolean }): VNode {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ viewBox="0 0 24 24"
+ stroke-width="1.75"
+ stroke="currentColor"
+ class={`mt-1 h-5 w-5 shrink-0 transition-transform ${
+ expanded ? "rotate-180" : ""
+ }`}
+ aria-hidden="true"
+ >
+ <path
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ d="m19.5 8.25-7.5 7.5-7.5-7.5"
+ />
+ </svg>
+ );
+}
diff --git a/packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx b/packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx
@@ -1,38 +1,21 @@
/*
This file is part of GNU Taler
- (C) 2022-2025 Taler Systems S.A.
+ (C) 2022-2026 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 {
AbsoluteTime,
AvailableMeasureSummary,
- KycRule,
LegitimizationMeasures,
- TalerExchangeApi,
} from "@gnu-taler/taler-util";
import { Time, useTranslationContext } from "@gnu-taler/web-util/browser";
-import { Fragment, h, VNode } from "preact";
+import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
-import { RulesInfo } from "./RulesInfo.js";
-import { CurrentMeasureTable } from "./MeasuresTable.js";
import { computeMeasureInformation } from "../utils/computeAvailableMesaures.js";
-import { CheckCircleIcon } from "@heroicons/react/20/solid";
-
-const TALER_SCREEN_ID = 120;
-
-// function ShowLegistimizationInfo({info}:{info: LegitimizationMeasureDetails}): VNode {
-// return <CurrentMeasureTable measures={res[0]} hideMeasureNames />;
-// }
+import { CurrentMeasureTable } from "./MeasuresTable.js";
export function ShowLegistimizationInfo({
since,
@@ -51,124 +34,104 @@ export function ShowLegistimizationInfo({
}): VNode {
const { i18n } = useTranslationContext();
const [opened, setOpened] = useState(startOpen ?? false);
+ const expandable = !fixed;
+ const info = computeMeasureInformation(serverMeasures, {
+ measureList: legitimization.measures,
+ });
- function Header() {
- return (
- <div
- data-fixed={!!fixed}
- class="p-4 relative bg-gray-200 flex justify-between data-[fixed=false]:cursor-pointer"
+ return (
+ <div class="overflow-hidden rounded-lg border border-gray-300 dark:border-gray-700">
+ <button
+ type="button"
+ disabled={!expandable}
+ aria-expanded={expandable ? opened : undefined}
+ class="flex w-full items-start justify-between gap-3 bg-gray-50 p-4 text-left hover:bg-gray-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-inset focus-visible:outline-primary disabled:cursor-default dark:bg-gray-900 dark:hover:bg-gray-800"
onClick={() => {
- if (!fixed) {
- setOpened((o) => !o);
- }
+ if (expandable) setOpened((value) => !value);
}}
>
- <div class="flex min-w-0 gap-x-4">
- <div class="flex rounded-md shadow-sm border-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600">
- <div class="pointer-events-none bg-gray-300 inset-y-0 flex items-center px-3">
- <i18n.Translate>Since</i18n.Translate>
+ <span class="grid min-w-0 flex-1 gap-3 sm:grid-cols-2">
+ <span>
+ <span class="block text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
+ <i18n.Translate>Started</i18n.Translate>
+ </span>
+ <span class="mt-1 block text-sm font-medium text-gray-900 dark:text-gray-100">
+ <Time format="PPp" timestamp={since} />
+ </span>
+ </span>
+ <span>
+ <span class="block text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
+ <i18n.Translate>Status</i18n.Translate>
+ </span>
+ <span
+ class={`mt-1 inline-flex rounded-full border px-2.5 py-1 text-xs font-semibold ${
+ legitimization.verboten
+ ? "border-red-700 bg-red-50 text-red-900 dark:border-red-500 dark:bg-red-950 dark:text-red-100"
+ : completed
+ ? "border-green-700 bg-green-50 text-green-900 dark:border-green-500 dark:bg-green-950 dark:text-green-100"
+ : "border-amber-700 bg-amber-50 text-amber-950 dark:border-amber-500 dark:bg-amber-950 dark:text-amber-100"
+ }`}
+ >
+ {legitimization.verboten
+ ? i18n.str`Forbidden`
+ : completed
+ ? i18n.str`Completed`
+ : i18n.str`Waiting for customer`}
+ </span>
+ </span>
+ </span>
+ {expandable ? <Chevron expanded={opened} /> : undefined}
+ </button>
+ {opened ? (
+ <div class="space-y-4 border-t border-gray-200 p-4 dark:border-gray-700">
+ {legitimization.verboten ? (
+ <div
+ role="status"
+ class="rounded-md border border-red-300 bg-red-50 p-3 text-sm text-red-950 dark:border-red-700 dark:bg-red-950 dark:text-red-100"
+ >
+ <i18n.Translate>
+ The operation is categorically forbidden by this requirement.
+ </i18n.Translate>
</div>
- <div class="p-2 bg-gray-50 text-right rounded-md rounded-l-none data-[left=true]:text-left w-full py-1.5 pl-3 text-gray-900 placeholder:text-gray-50 sm:text-sm sm:leading-6">
- <Time format="dd/MM/yyyy HH:mm:ss" timestamp={since} />
- </div>
- </div>
- </div>
- <div class="flex shrink-0 items-center gap-x-4">
- {completed ? (
- <CheckCircleIcon title={i18n.str`Already completed.`} />
) : (
- <ClockIcon title={i18n.str`Waiting to be completed.`} />
- )}
- {fixed ? (
- <Fragment />
- ) : (
- <div class="rounded-full bg-gray-50 p-2">
- <svg
- xmlns="http://www.w3.org/2000/svg"
- fill="none"
- viewBox="0 0 24 24"
- stroke-width="1.5"
- stroke="currentColor"
- class="size-6 w-6 h-6"
- >
- {opened ? (
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- d="m19.5 8.25-7.5 7.5-7.5-7.5"
- />
+ <>
+ <p class="text-sm text-gray-600 dark:text-gray-300">
+ {legitimization.is_and_combinator ? (
+ <i18n.Translate>
+ All listed measures must be completed.
+ </i18n.Translate>
) : (
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- d="m4.5 15.75 7.5-7.5 7.5 7.5"
- />
+ <i18n.Translate>
+ Any one listed measure may be completed.
+ </i18n.Translate>
)}
- </svg>
- </div>
+ </p>
+ <CurrentMeasureTable measures={info} hideMeasureNames />
+ </>
)}
</div>
- </div>
- );
- }
-
- if (!opened) {
- return (
- <div class="overflow-hidden border border-gray-800 rounded-xl">
- <Header />
- </div>
- );
- }
-
- const info = computeMeasureInformation(serverMeasures, {
- measureList: legitimization.measures,
- });
-
- return (
- <div class="overflow-hidden border border-gray-800 rounded-xl">
- <Header />
- <div class="p-4 grid gap-y-4">
- <CurrentMeasureTable measures={info} hideMeasureNames />
- </div>
+ ) : undefined}
</div>
);
}
-function CircleCheckIcon({ title }: { title: string }): VNode {
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- fill="none"
- viewBox="0 0 24 24"
- stroke-width="1.5"
- stroke="currentColor"
- class="size-6"
- title={title}
- >
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- d="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"
- />
- </svg>
- );
-}
-
-function ClockIcon({ title }: { title: string }): VNode {
+function Chevron({ expanded }: { expanded: boolean }): VNode {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
- stroke-width="1.5"
+ stroke-width="1.75"
stroke="currentColor"
- class="size-6"
- title={title}
+ class={`mt-1 h-5 w-5 shrink-0 transition-transform ${
+ expanded ? "rotate-180" : ""
+ }`}
+ aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
- d="M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"
+ d="m19.5 8.25-7.5 7.5-7.5-7.5"
/>
</svg>
);
diff --git a/packages/taler-exchange-aml-webui/src/components/UnlockSession.test.tsx b/packages/taler-exchange-aml-webui/src/components/UnlockSession.test.tsx
@@ -0,0 +1,116 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import {
+ OfficerId,
+ Password,
+ opFixedSuccess,
+ setupI18n,
+} from "@gnu-taler/taler-util";
+import { dummyHttpResponse } from "@gnu-taler/taler-util/http";
+import { NotificationProvider } from "@gnu-taler/web-util/browser";
+import assert from "node:assert/strict";
+import test from "node:test";
+import { h, render } from "preact";
+import { OfficerLocked } from "../hooks/officer.js";
+import { UnlockSession } from "./UnlockSession.js";
+
+setupI18n("en", {});
+
+async function installDom() {
+ const happyDomPackage = "happy-dom";
+ const { Window } = await import(happyDomPackage);
+ const window = new Window({ url: "https://aml.example/" });
+ for (const [key, value] of Object.entries({
+ window,
+ document: window.document,
+ navigator: window.navigator,
+ Node: window.Node,
+ Element: window.Element,
+ Event: window.Event,
+ MouseEvent: window.MouseEvent,
+ HTMLElement: window.HTMLElement,
+ HTMLInputElement: window.HTMLInputElement,
+ HTMLButtonElement: window.HTMLButtonElement,
+ HTMLDialogElement: window.HTMLDialogElement,
+ MutationObserver: window.MutationObserver,
+ })) {
+ Object.defineProperty(globalThis, key, {
+ configurable: true,
+ writable: true,
+ value,
+ });
+ }
+ return window;
+}
+
+async function eventually(assertion: () => void): Promise<void> {
+ let lastError: unknown;
+ for (let attempt = 0; attempt < 50; attempt++) {
+ try {
+ assertion();
+ return;
+ } catch (error) {
+ lastError = error;
+ await new Promise((resolve) => setTimeout(resolve, 0));
+ }
+ }
+ throw lastError;
+}
+
+test("locked session identifies the officer and confirms forgetting", async () => {
+ const window = await installDom();
+ const publicKey =
+ "4TQZQ0M6CB0JZXJ3Z1B4H7X3EVAQXX45SB9QT0NXZYKAHQXZ3EYG" as OfficerId;
+ let forgetCalls = 0;
+ const officer: OfficerLocked = {
+ state: "locked",
+ id: publicKey,
+ officer_name: "Alice Example",
+ tryUnlock: async (_password: Password) =>
+ opFixedSuccess(dummyHttpResponse, undefined),
+ forget: () => {
+ forgetCalls++;
+ return opFixedSuccess(dummyHttpResponse, undefined);
+ },
+ };
+ const container = window.document.createElement("div");
+ window.document.body.append(container);
+ render(
+ <NotificationProvider>
+ <UnlockSession officer={officer} />
+ </NotificationProvider>,
+ container as Element,
+ );
+
+ assert.match(container.textContent, /Alice Example/);
+ assert.match(container.textContent, new RegExp(publicKey));
+
+ const forgetButton = (
+ Array.from(container.querySelectorAll("button")) as HTMLButtonElement[]
+ ).find((button) => button.textContent.trim() === "Forget session");
+ assert.ok(forgetButton);
+ forgetButton.click();
+ assert.equal(forgetCalls, 0);
+
+ const confirmation = container.querySelector("dialog");
+ assert.ok(confirmation);
+ await eventually(() => assert.equal(confirmation.open, true));
+ assert.match(confirmation.textContent, /Forget this session\?/);
+ const confirmButton = (
+ Array.from(confirmation.querySelectorAll("button")) as HTMLButtonElement[]
+ ).find((button) => button.textContent.trim() === "Forget session");
+ assert.ok(confirmButton);
+ confirmButton.click();
+ await eventually(() => assert.equal(forgetCalls, 1));
+
+ render(null, container as Element);
+ container.remove();
+ await window.happyDOM.abort();
+});
diff --git a/packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx b/packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx
@@ -29,8 +29,10 @@ import {
useNotifiedOperation,
useTranslationContext,
} from "@gnu-taler/web-util/browser";
-import { h, VNode } from "preact";
+import { Fragment, h, VNode } from "preact";
+import { useState } from "preact/hooks";
import { OfficerLocked } from "../hooks/officer.js";
+import { ConfirmationModal } from "./ConfirmationModal.js";
type FormType = {
password: string;
@@ -52,8 +54,9 @@ const unlockAccountForm = (i18n: InternationalizationAPI): FormDesign => ({
export function UnlockSession({ officer }: { officer: OfficerLocked }): VNode {
const { i18n } = useTranslationContext();
+ const [confirmForget, setConfirmForget] = useState(false);
- const { showError } = useNotificationContext();
+ const { clearErrors, showError } = useNotificationContext();
const design = unlockAccountForm(i18n);
@@ -65,6 +68,7 @@ export function UnlockSession({ officer }: { officer: OfficerLocked }): VNode {
Awaited<ReturnType<OfficerLocked["tryUnlock"]>>,
[Password]
>((_ct, password: Password) => officer.tryUnlock(password), {
+ onSuccess: () => clearErrors(),
onFail: showError(i18n.str`Failed to unlock the session.`, (fail) => {
switch (fail.case) {
case HttpStatusCode.Forbidden:
@@ -79,23 +83,62 @@ export function UnlockSession({ officer }: { officer: OfficerLocked }): VNode {
[]
>(async () => officer.forget());
+ const submitUnlock = () => {
+ if (status.status === "fail") return Promise.resolve();
+ return unlock.run(asPassword(status.result.password));
+ };
+
return (
- <div class="flex min-h-full flex-col ">
- <div class="sm:mx-auto sm:w-full sm:max-w-md">
- <h1 class="mt-6 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">
+ <>
+ <section
+ class="mx-auto max-w-2xl py-8"
+ aria-labelledby="session-locked-title"
+ >
+ <h1
+ id="session-locked-title"
+ class="text-3xl font-bold tracking-tight text-gray-900 dark:text-gray-100"
+ >
<i18n.Translate>Session locked</i18n.Translate>
</h1>
- <p class="mt-6 text-lg leading-8 text-gray-600">
+ <p class="mt-4 text-base leading-7 text-gray-700 dark:text-gray-300">
<i18n.Translate>
Your session is normally locked anytime you reload. To unlock type
your password again.
</i18n.Translate>
</p>
- </div>
- <div class="mt-10 sm:mx-auto sm:w-full sm:max-w-[480px] ">
- <form class="bg-gray-100 px-6 py-6 shadow sm:rounded-lg sm:px-12">
- <div class="mb-4">
+ <div class="mt-6 rounded-lg border border-outlineVariant bg-surfaceContainer p-4">
+ <h2 class="text-sm font-semibold text-onSurface dark:text-gray-100">
+ <i18n.Translate>Officer access</i18n.Translate>
+ </h2>
+ <dl class="mt-2 divide-y divide-outlineVariant text-sm">
+ <div class="grid gap-1 py-3 sm:grid-cols-[9rem_minmax(0,1fr)] sm:gap-4">
+ <dt class="font-semibold text-gray-900 dark:text-gray-100">
+ <i18n.Translate>Officer name</i18n.Translate>
+ </dt>
+ <dd>{officer.officer_name ?? i18n.str`Unavailable`}</dd>
+ </div>
+ <div class="grid gap-1 py-3 pb-0 sm:grid-cols-[9rem_minmax(0,1fr)] sm:gap-4">
+ <dt class="font-semibold text-gray-900 dark:text-gray-100">
+ <i18n.Translate>Officer public key</i18n.Translate>
+ </dt>
+ <dd class="min-w-0">
+ <code class="break-all text-xs sm:text-sm">
+ {officer.id ?? i18n.str`Unavailable`}
+ </code>
+ </dd>
+ </div>
+ </dl>
+ </div>
+
+ <form
+ class="mt-6 rounded-lg border border-outlineVariant bg-white p-4 shadow-sm dark:bg-gray-900"
+ onSubmit={(event) => {
+ event.preventDefault();
+ void submitUnlock();
+ }}
+ >
+ <div>
<InputLine
label={i18n.str`Password`}
name="password"
@@ -105,27 +148,57 @@ export function UnlockSession({ officer }: { officer: OfficerLocked }): VNode {
/>
</div>
- <div class="mt-8">
+ <div class="mt-6 flex flex-wrap items-center gap-3">
<AsyncButton
submit
onClick={
status.status === "fail"
? undefined
- : () => unlock.run(asPassword(status.result.password))
+ : (event) => {
+ event.preventDefault();
+ return submitUnlock();
+ }
}
- class="disabled:opacity-50 disabled:cursor-default flex w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
+ class="inline-flex min-h-11 items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-semibold text-onPrimary hover:bg-primary/90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary disabled:cursor-not-allowed disabled:bg-gray-200 disabled:text-gray-700 disabled:hover:bg-gray-200"
>
<i18n.Translate>Unlock</i18n.Translate>
</AsyncButton>
+ <button
+ type="button"
+ onClick={() => setConfirmForget(true)}
+ class="inline-flex min-h-11 items-center justify-center rounded-md px-4 py-2 text-sm font-semibold text-error hover:bg-errorContainer focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-error"
+ >
+ <i18n.Translate>Forget session</i18n.Translate>
+ </button>
</div>
</form>
- <AsyncButton
- onClick={() => forget.run()}
- class="disabled:opacity-50 disabled:cursor-default m-4 block rounded-md bg-red-600 px-3 py-2 text-center text-sm text-white shadow-sm hover:bg-red-500 "
- >
- <i18n.Translate>Forget session</i18n.Translate>
- </AsyncButton>
- </div>
- </div>
+ </section>
+
+ <ConfirmationModal
+ open={confirmForget}
+ title={<i18n.Translate>Forget this session?</i18n.Translate>}
+ confirmLabel={<i18n.Translate>Forget session</i18n.Translate>}
+ onClose={() => setConfirmForget(false)}
+ onConfirm={() => {
+ setConfirmForget(false);
+ void forget.run();
+ }}
+ >
+ <div class="space-y-3">
+ <p>
+ <i18n.Translate>
+ This deletes the officer key from this browser. You will need to
+ create and enroll a new key to use the AML WebUI here again.
+ </i18n.Translate>
+ </p>
+ <p>
+ <i18n.Translate>
+ This does not revoke the officer at the exchange. Ask the exchange
+ operator to revoke its access if the key may be compromised.
+ </i18n.Translate>
+ </p>
+ </div>
+ </ConfirmationModal>
+ </>
);
}
diff --git a/packages/taler-exchange-aml-webui/src/context/officer-info.tsx b/packages/taler-exchange-aml-webui/src/context/officer-info.tsx
@@ -0,0 +1,34 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import { AmlOfficerInfo } from "@gnu-taler/taler-util";
+import { ComponentChildren, createContext, h, VNode } from "preact";
+import { useContext } from "preact/hooks";
+
+const OfficerInfoContext = createContext<AmlOfficerInfo | undefined>(undefined);
+
+export function OfficerInfoProvider({
+ children,
+ value,
+}: {
+ children: ComponentChildren;
+ value: AmlOfficerInfo;
+}): VNode {
+ return h(OfficerInfoContext.Provider, { value, children });
+}
+
+export function useOfficerInfoContext(): AmlOfficerInfo {
+ const value = useContext(OfficerInfoContext);
+ if (!value) {
+ throw new Error(
+ "useOfficerInfoContext must be used inside OfficerInfoProvider",
+ );
+ }
+ return value;
+}
diff --git a/packages/taler-exchange-aml-webui/src/context/ui-forms.test.ts b/packages/taler-exchange-aml-webui/src/context/ui-forms.test.ts
@@ -0,0 +1,59 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import { i18n, setupI18n } from "@gnu-taler/taler-util";
+import { FormMetadata, preloadedForms } from "@gnu-taler/web-util/browser";
+import assert from "node:assert/strict";
+import test from "node:test";
+import { inheritBuiltinOfficerViews } from "./ui-forms.js";
+
+setupI18n("en", {});
+
+test("configured ToS forms inherit the built-in officer view", () => {
+ const builtins = preloadedForms(i18n);
+ const builtinTerms = builtins.find(({ id }) => id === "accept-tos");
+ assert.ok(builtinTerms?.officerView);
+
+ const configuredTerms: FormMetadata = {
+ id: "deployment-terms",
+ version: builtinTerms.version + 1,
+ label: "Deployment-specific terms",
+ description: "The form definition supplied through forms.json",
+ config: {
+ type: "accept-tos",
+ tosUrl: "https://exchange.example/terms",
+ tosVersion: "terms-v8",
+ providerName: "Example Exchange",
+ },
+ };
+
+ const [result] = inheritBuiltinOfficerViews(builtins, [configuredTerms]);
+
+ assert.equal(result.officerView, builtinTerms.officerView);
+ assert.equal(result.version, configuredTerms.version);
+ assert.equal(result.label, configuredTerms.label);
+ assert.equal(result.config, configuredTerms.config);
+});
+
+test("configured programmatic officer views take precedence", () => {
+ const CustomOfficerView = () => null;
+ const configured: FormMetadata = {
+ id: "accept-tos",
+ version: 1,
+ label: "Custom terms",
+ config: { type: "single-column", fields: [] },
+ officerView: CustomOfficerView,
+ };
+
+ const [result] = inheritBuiltinOfficerViews(preloadedForms(i18n), [
+ configured,
+ ]);
+
+ assert.equal(result.officerView, CustomOfficerView);
+});
diff --git a/packages/taler-exchange-aml-webui/src/context/ui-forms.ts b/packages/taler-exchange-aml-webui/src/context/ui-forms.ts
@@ -40,6 +40,34 @@ export type BaseForm = Record<string, unknown>;
export const useUiFormsContext = (): Type => useContext(Context);
+/**
+ * JSON form definitions cannot contain programmatic officer views. Inherit
+ * those views from the corresponding built-in form while retaining every
+ * serializable property supplied by the deployment.
+ */
+export function inheritBuiltinOfficerViews(
+ builtins: FormMetadata[],
+ configured: FormMetadata[],
+): FormMetadata[] {
+ const viewsByFormId = new Map(
+ builtins.flatMap((form) =>
+ form.officerView ? [[form.id, form.officerView] as const] : [],
+ ),
+ );
+ const viewsByFormType = new Map([
+ ["accept-tos", viewsByFormId.get("accept-tos")],
+ ]);
+ return configured.map((form) => ({
+ ...form,
+ officerView:
+ form.officerView ??
+ viewsByFormId.get(form.id) ??
+ (typeof form.config === "function"
+ ? undefined
+ : viewsByFormType.get(form.config.type)),
+ }));
+}
+
export const UiFormsProvider = ({
children,
}: {
@@ -55,7 +83,10 @@ export const UiFormsProvider = ({
});
}, []);
- const value = !forms || !forms.length ? pf : [...pf, ...forms];
+ const value =
+ !forms || !forms.length
+ ? pf
+ : [...pf, ...inheritBuiltinOfficerViews(pf, forms)];
return h(Context.Provider, {
value: { forms: value },
diff --git a/packages/taler-exchange-aml-webui/src/hooks/account.ts b/packages/taler-exchange-aml-webui/src/hooks/account.ts
@@ -54,6 +54,7 @@ export function useAccountInformation(paytoHash?: string) {
} = useExchangeApiContext();
const [pointer, updatePointer] = useListPointer(
(row: KycAttributeCollectionEvent) => String(row.rowid),
+ paytoHash,
);
async function fetcher([officer, account, offset]: [
diff --git a/packages/taler-exchange-aml-webui/src/hooks/decision-request.ts b/packages/taler-exchange-aml-webui/src/hooks/decision-request.ts
@@ -33,6 +33,7 @@ import {
TalerExchangeApi,
} from "@gnu-taler/taler-util";
import { FormErrors } from "@gnu-taler/web-util/browser";
+import { BUILT_IN_SKIP_CHECK } from "../utils/measure-check.js";
import { ComponentChildren, createContext, h, VNode } from "preact";
import { useContext, useRef, useState } from "preact/hooks";
export interface AccountAttributes {
@@ -76,7 +77,7 @@ export interface DecisionRequest {
/**
* Relevate state of the account
*/
- properties?: Record<string, boolean | string>;
+ properties?: Record<string, boolean | string | number | null>;
/**
* Errors on the properties
*/
@@ -110,11 +111,20 @@ export interface DecisionRequest {
* Custom measures defined by the officer
*/
custom_measures?: Record<string, MeasureInformation>;
+ /** Built-in properties explicitly changed by the officer. */
+ property_overrides?: string[];
+ /** Whether the officer replaced the automatically derived event selection. */
+ events_overridden?: boolean;
+ /** Whether the officer explicitly reviewed the proposed transaction rules. */
+ rules_reviewed?: boolean;
}
export const codecForMeasure = (): Codec<MeasureInformation> =>
buildCodecForObject<MeasureInformation>()
- .property("check_name", codecOptionalDefault(codecForString(), "SKIP"))
+ .property(
+ "check_name",
+ codecOptionalDefault(codecForString(), BUILT_IN_SKIP_CHECK),
+ )
.property("prog_name", codecOptional(codecForString()))
.property("context", codecOptional(codecForMap(codecForAny())))
.build("MeasureInformation");
@@ -150,6 +160,12 @@ export const codecForDecisionRequest = (): Codec<DecisionRequest> =>
.property("new_measures", codecOptional(codecForList(codecForString())))
.property("measures_and", codecOptional(codecForBoolean()))
.property("onExpire_measure", codecOptional(codecForString()))
+ .property(
+ "property_overrides",
+ codecOptional(codecForList(codecForString())),
+ )
+ .property("events_overridden", codecOptional(codecForBoolean()))
+ .property("rules_reviewed", codecOptional(codecForBoolean()))
.build("DecisionRequest");
const DECISION_REQUEST_EMPTY: DecisionRequest = {
@@ -169,38 +185,13 @@ const DECISION_REQUEST_EMPTY: DecisionRequest = {
custom_measures: undefined,
properties: undefined,
rules: undefined,
+ property_overrides: undefined,
+ events_overridden: false,
+ rules_reviewed: false,
};
-export interface DecisionTarget {
- officerId: string;
- account: string;
- fullPayto?: string;
-}
-
-interface StoredDecisionDraft {
- version: 1;
- target: DecisionTarget;
- request: DecisionRequest;
-}
-
-const DRAFT_PREFIX = "aml-decision-draft-v1:";
const LEGACY_DRAFT_KEY = "aml-decision-request";
-function draftStorageKey(target: DecisionTarget): string {
- return `${DRAFT_PREFIX}${target.officerId}:${target.account}`;
-}
-
-export function decisionTargetsMatch(
- a: DecisionTarget,
- b: DecisionTarget,
-): boolean {
- return (
- a.officerId === b.officerId &&
- a.account === b.account &&
- (!a.fullPayto || !b.fullPayto || a.fullPayto === b.fullPayto)
- );
-}
-
export function removeLegacyDecisionDraft(): void {
try {
localStorage.removeItem(LEGACY_DRAFT_KEY);
@@ -209,90 +200,9 @@ export function removeLegacyDecisionDraft(): void {
}
}
-function readDecisionDraft(
- target: DecisionTarget,
-): DecisionRequest | undefined {
- removeLegacyDecisionDraft();
- try {
- const raw = sessionStorage.getItem(draftStorageKey(target));
- if (!raw) return undefined;
- const parsed = JSON.parse(raw) as StoredDecisionDraft;
- if (
- parsed.version !== 1 ||
- !parsed.target ||
- !parsed.request ||
- !decisionTargetsMatch(parsed.target, target)
- ) {
- sessionStorage.removeItem(draftStorageKey(target));
- return undefined;
- }
- return codecForDecisionRequest().decode(parsed.request);
- } catch {
- try {
- sessionStorage.removeItem(draftStorageKey(target));
- } catch {
- // Ignore unavailable storage.
- }
- return undefined;
- }
-}
-
-function writeDecisionDraft(
- target: DecisionTarget,
- request: DecisionRequest,
-): void {
- try {
- const stored: StoredDecisionDraft = { version: 1, target, request };
- sessionStorage.setItem(draftStorageKey(target), JSON.stringify(stored));
- } catch {
- // Continue with an in-memory draft if session storage is unavailable.
- }
-}
-
-export function clearDecisionDraft(officerId: string, account: string): void {
- try {
- sessionStorage.removeItem(draftStorageKey({ officerId, account }));
- } catch {
- // Ignore unavailable storage.
- }
- removeLegacyDecisionDraft();
-}
-
export function clearDecisionDraftsForOfficer(officerId: string): void {
+ void officerId;
removeLegacyDecisionDraft();
- try {
- const prefix = `${DRAFT_PREFIX}${officerId}:`;
- const keys: string[] = [];
- for (let i = 0; i < sessionStorage.length; i++) {
- const key = sessionStorage.key(i);
- if (key?.startsWith(prefix)) keys.push(key);
- }
- for (const key of keys) sessionStorage.removeItem(key);
- } catch {
- // Ignore unavailable storage.
- }
-}
-
-export function readDecisionDraftTarget(
- officerId: string,
- account: string,
-): DecisionTarget | undefined {
- removeLegacyDecisionDraft();
- try {
- const raw = sessionStorage.getItem(draftStorageKey({ officerId, account }));
- if (!raw) return undefined;
- const parsed = JSON.parse(raw) as StoredDecisionDraft;
- if (
- parsed.version !== 1 ||
- parsed.target?.officerId !== officerId ||
- parsed.target?.account !== account
- ) {
- return undefined;
- }
- return parsed.target;
- } catch {
- return undefined;
- }
}
type DecisionRequestContextValue = [
@@ -307,11 +217,9 @@ const DecisionRequestContext = createContext<
>(undefined);
export function DecisionRequestProvider({
- target,
initial,
children,
}: {
- target: DecisionTarget;
initial?: Partial<DecisionRequest>;
children: ComponentChildren;
}): VNode {
@@ -319,22 +227,18 @@ export function DecisionRequestProvider({
...DECISION_REQUEST_EMPTY,
...initial,
});
- const [request, setRequest] = useState<DecisionRequest>(
- () => readDecisionDraft(target) ?? defaultRef.current,
- );
+ const [request, setRequest] = useState<DecisionRequest>(defaultRef.current);
const requestRef = useRef(request);
const setAndStore = (next: DecisionRequest): void => {
requestRef.current = next;
setRequest(next);
- writeDecisionDraft(target, next);
};
const update = (_label: string, partial: Partial<DecisionRequest>): void => {
setAndStore({ ...requestRef.current, ...partial });
};
const clear = (): void => {
- clearDecisionDraft(target.officerId, target.account);
requestRef.current = DECISION_REQUEST_EMPTY;
setRequest(DECISION_REQUEST_EMPTY);
};
diff --git a/packages/taler-exchange-aml-webui/src/hooks/decisions.ts b/packages/taler-exchange-aml-webui/src/hooks/decisions.ts
@@ -22,6 +22,7 @@ import {
OfficerSession,
OperationFail,
OperationOk,
+ PaytoHash,
opFixedSuccess,
TalerError,
TalerExchangeResultByMethod2,
@@ -42,6 +43,8 @@ export const PAGINATED_LIST_SIZE = 10;
// when doing paginated request, ask for one more
// and use it to know if there are more to request
export const PAGINATED_LIST_REQUEST = PAGINATED_LIST_SIZE + 1;
+export const AML_ACCOUNTS_LIST_SIZE = 20;
+export const AML_ACCOUNTS_LIST_REQUEST = AML_ACCOUNTS_LIST_SIZE + 1;
/**
* @param account
@@ -65,6 +68,7 @@ export function useAmlAccounts({
const [pointer, updatePointer] = useListPointer(
(row: CustomerAccountSummary) => String(row.rowid),
+ `${investigated ?? "all"}:${highRisk ?? "all"}:${open ?? "all"}`,
);
async function fetcher([officer, offset, investigation, highRisk, open]: [
@@ -77,7 +81,7 @@ export function useAmlAccounts({
return await api.getAmlAccounts(officer, {
order: offset.order,
offset: offset.id,
- limit: PAGINATED_LIST_REQUEST,
+ limit: AML_ACCOUNTS_LIST_REQUEST,
investigation,
highRisk,
open,
@@ -102,7 +106,7 @@ export function useAmlAccounts({
data.body.accounts,
pointer,
updatePointer,
- PAGINATED_LIST_REQUEST,
+ AML_ACCOUNTS_LIST_REQUEST,
);
}
@@ -122,8 +126,9 @@ export function useCurrentDecisions({
lib: { exchange: api },
} = useExchangeApiContext();
- const [pointer, updatePointer] = useListPointer((row: AmlDecision) =>
- String(row.rowid),
+ const [pointer, updatePointer] = useListPointer(
+ (row: AmlDecision) => String(row.rowid),
+ String(investigated ?? "all"),
);
async function fetcher([officer, offset, investigation]: [
@@ -167,20 +172,76 @@ export function revalidateAccountDecisions() {
{ revalidate: true },
);
}
+
+export function revalidateAmlAccounts() {
+ return mutate(
+ (key) => Array.isArray(key) && key[key.length - 1] === "getAmlAccounts",
+ undefined,
+ { revalidate: true },
+ );
+}
+
+/**
+ * Load the directory summary for one account. Exact matching on the client
+ * keeps this safe with older exchanges that do not understand h_payto yet.
+ */
+export function useAmlAccount(accountStr?: string):
+ | OperationFail<
+ | HttpStatusCode.Forbidden
+ | HttpStatusCode.NotFound
+ | HttpStatusCode.Conflict
+ >
+ | TalerError<{
+ requestUrl: string;
+ requestMethod: string;
+ }>
+ | OperationOk<CustomerAccountSummary | undefined>
+ | undefined {
+ const officer = useOfficer();
+ const session =
+ accountStr !== undefined && officer.state === "ready"
+ ? officer.session
+ : undefined;
+ const {
+ lib: { exchange: api },
+ } = useExchangeApiContext();
+
+ async function fetcher([officer, account]: [OfficerSession, string, string]) {
+ return await api.getAmlAccounts(officer, {
+ account: account as PaytoHash,
+ limit: 2,
+ });
+ }
+
+ const { data, error } = useSWR<
+ TalerExchangeResultByMethod2<"getAmlAccounts">,
+ TalerHttpError
+ >(!session ? undefined : [session, accountStr, "getAmlAccounts"], fetcher);
+
+ if (error) return error;
+ if (data === undefined) return undefined;
+ if (data.type !== "ok") return data;
+
+ const record = data.body.accounts.find(
+ ({ h_payto }) => h_payto === accountStr,
+ );
+ return opFixedSuccess(dummyHttpResponse, record);
+}
/**
* @param account
* @param args
* @returns
*/
-export function useAccountDecisions(accountStr: string) {
+export function useAccountDecisions(accountStr: string, active?: boolean) {
const officer = useOfficer();
const session = officer.state === "ready" ? officer.session : undefined;
const {
lib: { exchange: api },
} = useExchangeApiContext();
- const [pointer, updatePointer] = useListPointer((row: AmlDecision) =>
- String(row.rowid),
+ const [pointer, updatePointer] = useListPointer(
+ (row: AmlDecision) => String(row.rowid),
+ `${accountStr}:${active ?? "all"}`,
);
async function fetcher([officer, account, offset]: [
@@ -192,6 +253,7 @@ export function useAccountDecisions(accountStr: string) {
order: offset.order,
offset: offset.id,
account,
+ active,
limit: PAGINATED_LIST_REQUEST,
});
}
@@ -200,7 +262,9 @@ export function useAccountDecisions(accountStr: string) {
TalerExchangeResultByMethod2<"getAmlDecisions">,
TalerHttpError
>(
- !session ? undefined : [session, accountStr, pointer, "getAmlDecisions"],
+ !session
+ ? undefined
+ : [session, accountStr, pointer, active, "getAmlDecisions"],
fetcher,
);
diff --git a/packages/taler-exchange-aml-webui/src/hooks/legitimizations.ts b/packages/taler-exchange-aml-webui/src/hooks/legitimizations.ts
@@ -59,6 +59,7 @@ export function useCurrentLegitimizations(accoutnStr: string) {
const [pointer, updatePointer] = useListPointer(
(row: LegitimizationMeasureDetails) => String(row.rowid),
+ accoutnStr,
);
async function fetcher([officer, account, offset]: [
diff --git a/packages/taler-exchange-aml-webui/src/hooks/officer.test.ts b/packages/taler-exchange-aml-webui/src/hooks/officer.test.ts
@@ -0,0 +1,31 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import { AbsoluteTime } from "@gnu-taler/taler-util";
+import assert from "node:assert/strict";
+import test from "node:test";
+import { codecForOfficer } from "./officer.js";
+
+test("stored officer metadata is optional for existing encrypted keys", () => {
+ const oldRecord = codecForOfficer().decode({
+ session: "SEALED_PRIVATE_KEY",
+ when: AbsoluteTime.never(),
+ });
+ assert.equal(oldRecord.id, undefined);
+ assert.equal(oldRecord.officer_name, undefined);
+
+ const currentRecord = codecForOfficer().decode({
+ session: "SEALED_PRIVATE_KEY",
+ when: AbsoluteTime.never(),
+ id: "OFFICER_PUBLIC_KEY",
+ officer_name: "Alice Example",
+ });
+ assert.equal(currentRecord.id, "OFFICER_PUBLIC_KEY");
+ assert.equal(currentRecord.officer_name, "Alice Example");
+});
diff --git a/packages/taler-exchange-aml-webui/src/hooks/officer.ts b/packages/taler-exchange-aml-webui/src/hooks/officer.ts
@@ -15,6 +15,7 @@
*/
import {
AbsoluteTime,
+ AmlOfficerInfo,
Codec,
Duration,
EddsaPrivP,
@@ -71,6 +72,9 @@ interface OfficerCompatible {
account?: LockedAccount;
session?: LockedAccount;
when: AbsoluteTime;
+ /** Public metadata retained so the locked screen can identify the key. */
+ id?: OfficerId;
+ officer_name?: string;
}
const codecForLockedAccount =
@@ -96,6 +100,11 @@ export const codecForOfficer = (): Codec<OfficerCompatible> =>
.property("session", codecOptional(codecForLockedAccount))
.property("account", codecOptional(codecForLockedAccount))
.property("when", codecForAbsoluteTime)
+ .property(
+ "id",
+ codecOptional(codecForString() as unknown as Codec<OfficerId>),
+ )
+ .property("officer_name", codecOptional(codecForString()))
.build("Officer");
export type OfficerState = OfficerNotReady | OfficerReady;
@@ -106,6 +115,8 @@ export interface OfficerNotFound {
}
export interface OfficerLocked {
state: "locked";
+ id?: OfficerId;
+ officer_name?: string;
forget: () => OperationOk<void>;
tryUnlock: (
password: Password,
@@ -117,6 +128,7 @@ export interface OfficerReady {
forget: () => OperationOk<void>;
lock: () => OperationOk<void>;
expiration: AbsoluteTime;
+ rememberInfo?: (info: AmlOfficerInfo) => void;
}
const OFFICER_KEY = buildStorageKey("officer", codecForOfficer());
@@ -241,9 +253,9 @@ export function OfficerProvider({
removeLegacyDecisionDraft();
if (storedOfficer?.account && !storedOfficer.session) {
officerStorage.update({
+ ...storedOfficer,
account: undefined,
session: storedOfficer.account,
- when: storedOfficer.when,
});
}
}, [officerStorage, storedOfficer]);
@@ -282,6 +294,7 @@ export function OfficerProvider({
account: undefined,
session: safe,
when: AbsoluteTime.now(),
+ id,
});
const session: TimedOfficerSession = {
id,
@@ -296,6 +309,8 @@ export function OfficerProvider({
: !activeSession || !expiration
? {
state: "locked",
+ id: storedOfficer?.id,
+ officer_name: storedOfficer?.officer_name,
forget: () => {
officerStorage.reset();
clearRawSession();
@@ -308,6 +323,13 @@ export function OfficerProvider({
...unlocked,
unlocked: AbsoluteTime.now(),
};
+ officerStorage.update({
+ ...storedOfficer,
+ account: undefined,
+ session: lockedAccount,
+ when: storedOfficer?.when ?? AbsoluteTime.now(),
+ id: unlocked.id,
+ });
setRawSession(session);
if (pref.keepSessionAfterReload) writeStoredRawSession(session);
return opFixedSuccess(dummyHttpResponse, undefined);
@@ -323,6 +345,22 @@ export function OfficerProvider({
state: "ready",
session: activeSession,
expiration,
+ rememberInfo: (info: AmlOfficerInfo) => {
+ if (
+ storedOfficer?.id === activeSession.id &&
+ storedOfficer.officer_name === info.officer_name
+ ) {
+ return;
+ }
+ officerStorage.update({
+ ...storedOfficer,
+ account: undefined,
+ session: lockedAccount,
+ when: storedOfficer?.when ?? AbsoluteTime.now(),
+ id: activeSession.id,
+ officer_name: info.officer_name,
+ });
+ },
lock: () => {
clearRawSession();
return opFixedSuccess(dummyHttpResponse, undefined);
@@ -342,3 +380,14 @@ export function useOfficer(): OfficerState {
if (!state) throw new Error("useOfficer must be used inside OfficerProvider");
return state;
}
+
+/** Inject a deterministic officer state for stories and component tests. */
+export function OfficerProviderTesting({
+ children,
+ value,
+}: {
+ children: ComponentChildren;
+ value: OfficerState;
+}): VNode {
+ return h(OfficerContext.Provider, { value, children });
+}
diff --git a/packages/taler-exchange-aml-webui/src/hooks/preferences.ts b/packages/taler-exchange-aml-webui/src/hooks/preferences.ts
@@ -15,10 +15,13 @@
*/
import {
+ AmlSpaDialect,
Codec,
TranslatedString,
buildCodecForObject,
+ codecForAmlSpaDialect,
codecForBoolean,
+ codecOptional,
codecOptionalDefault,
} from "@gnu-taler/taler-util";
import {
@@ -26,21 +29,24 @@ import {
useLocalStorage,
useTranslationContext,
} from "@gnu-taler/web-util/browser";
+import { resolveAmlSpaDialect } from "../utils/dialect.js";
interface Preferences {
allowInsecurePassword: boolean;
keepSessionAfterReload: boolean;
- testingDialect: boolean;
+ dialectOverride?: AmlSpaDialect;
preventCompression: boolean;
}
+type BooleanPreference = Exclude<keyof Preferences, "dialectOverride">;
+
export const codecForPreferences = (): Codec<Preferences> =>
buildCodecForObject<Preferences>()
.property(
"allowInsecurePassword",
codecOptionalDefault(codecForBoolean(), false),
)
- .property("testingDialect", codecOptionalDefault(codecForBoolean(), false))
+ .property("dialectOverride", codecOptional(codecForAmlSpaDialect))
.property(
"keepSessionAfterReload",
codecOptionalDefault(codecForBoolean(), false),
@@ -53,7 +59,6 @@ export const codecForPreferences = (): Codec<Preferences> =>
const defaultPreferences: Preferences = {
allowInsecurePassword: false,
- testingDialect: false,
keepSessionAfterReload: false,
preventCompression: false,
};
@@ -83,24 +88,28 @@ export function usePreferences(): [
return [value, updateField];
}
-export function getAllBooleanPreferences(): Array<keyof Preferences> {
+export function getAllBooleanPreferences(): BooleanPreference[] {
return [
"allowInsecurePassword",
"keepSessionAfterReload",
- "testingDialect",
"preventCompression",
];
}
+export function useAmlSpaDialect(
+ configuredDialect: AmlSpaDialect | undefined,
+): AmlSpaDialect {
+ const [preferences] = usePreferences();
+ return resolveAmlSpaDialect(configuredDialect, preferences.dialectOverride);
+}
+
const TALER_SCREEN_ID = 118;
export function getLabelForPreferences(
- k: keyof Preferences,
+ k: BooleanPreference,
i18n: ReturnType<typeof useTranslationContext>["i18n"],
): TranslatedString {
switch (k) {
- case "testingDialect":
- return i18n.str`Use testing dialect`;
case "allowInsecurePassword":
return i18n.str`Allow Insecure password`;
case "keepSessionAfterReload":
diff --git a/packages/taler-exchange-aml-webui/src/hooks/server-info.ts b/packages/taler-exchange-aml-webui/src/hooks/server-info.ts
@@ -16,7 +16,6 @@
import {
AbsoluteTime,
CounterResultByEventName,
- EventReporting_TOPS_queries,
EventReporting_VQF_queries,
fetchTopsInfoFromServer,
fetchVqfInfoFromServer,
@@ -30,7 +29,7 @@ import {
import { dummyHttpResponse } from "@gnu-taler/taler-util/http";
import { useExchangeApiContext } from "@gnu-taler/web-util/browser";
import { endOfYear, setYear, startOfYear } from "date-fns";
-import _useSWR, { SWRHook } from "swr";
+import _useSWR, { mutate, SWRHook } from "swr";
import { useOfficer } from "./officer.js";
const useSWR = _useSWR as unknown as SWRHook;
@@ -42,14 +41,14 @@ export function useServerMeasures() {
lib: { exchange: api },
} = useExchangeApiContext();
- async function fetcher([officer]: [OfficerSession]) {
+ async function fetcher([officer]: [OfficerSession, string]) {
return await api.getAmlMeasures(officer);
}
const { data, error } = useSWR<
TalerExchangeResultByMethod2<"getAmlMeasures">,
TalerHttpError
- >(!session ? undefined : [session], fetcher, {
+ >(!session ? undefined : [session, "getAmlMeasures"], fetcher, {
refreshInterval: 0,
refreshWhenHidden: false,
revalidateOnFocus: false,
@@ -66,7 +65,48 @@ export function useServerMeasures() {
return undefined;
}
-export function useTopsServerStatistics() {
+export function useAmlOfficerInfo(enabled = true) {
+ const officer = useOfficer();
+ const session = officer.state === "ready" ? officer.session : undefined;
+ const {
+ lib: { exchange: api },
+ } = useExchangeApiContext();
+
+ const {
+ data,
+ error,
+ mutate: revalidate,
+ } = useSWR<TalerExchangeResultByMethod2<"getAmlOfficer">, TalerHttpError>(
+ enabled && session ? [api.baseUrl, session.id, "getAmlOfficer"] : undefined,
+ async () => await api.getAmlOfficer(session!),
+ {
+ refreshInterval: 0,
+ refreshWhenHidden: false,
+ revalidateOnFocus: true,
+ revalidateOnReconnect: true,
+ refreshWhenOffline: false,
+ errorRetryCount: 0,
+ shouldRetryOnError: false,
+ },
+ );
+
+ return {
+ result: data ?? error,
+ revalidate: async (): Promise<void> => {
+ await revalidate();
+ },
+ };
+}
+
+export function revalidateServerMeasures() {
+ return mutate(
+ (key) => Array.isArray(key) && key[key.length - 1] === "getAmlMeasures",
+ undefined,
+ { revalidate: true },
+ );
+}
+
+export function useTopsServerStatistics(enabled = true) {
const officer = useOfficer();
const session = officer.state === "ready" ? officer.session : undefined;
@@ -74,32 +114,44 @@ export function useTopsServerStatistics() {
unthrottledApi: { exchange: api },
} = useExchangeApiContext();
- async function fetcher([officer]: [OfficerSession]) {
+ async function fetcher([officer]: [OfficerSession, string]) {
const final = await fetchTopsInfoFromServer(api, officer);
return opFixedSuccess(dummyHttpResponse, final);
}
const { data, error } = useSWR<
- OperationOk<CounterResultByEventName<typeof EventReporting_TOPS_queries>>,
+ OperationOk<Awaited<ReturnType<typeof fetchTopsInfoFromServer>>>,
TalerHttpError
- >(!session ? undefined : [session], fetcher, {
- refreshInterval: 0,
- refreshWhenHidden: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshWhenOffline: false,
- errorRetryCount: 0,
- errorRetryInterval: 1,
- shouldRetryOnError: false,
- keepPreviousData: true,
- });
+ >(
+ !session || !enabled ? undefined : [session, "getTopsStatistics"],
+ fetcher,
+ {
+ refreshInterval: 0,
+ refreshWhenHidden: false,
+ revalidateOnFocus: false,
+ revalidateOnReconnect: false,
+ refreshWhenOffline: false,
+ errorRetryCount: 0,
+ errorRetryInterval: 1,
+ shouldRetryOnError: false,
+ keepPreviousData: true,
+ },
+ );
if (data) return data;
if (error) return error;
return undefined;
}
+export function revalidateTopsServerStatistics() {
+ return mutate(
+ (key) => Array.isArray(key) && key[key.length - 1] === "getTopsStatistics",
+ undefined,
+ { revalidate: true },
+ );
+}
+
export function useVqfServerStatistics(year: number) {
const officer = useOfficer();
const session = officer.state === "ready" ? officer.session : undefined;
@@ -108,7 +160,7 @@ export function useVqfServerStatistics(year: number) {
unthrottledApi: { exchange: api },
} = useExchangeApiContext();
- async function fetcher([officer, year]: [OfficerSession, number]) {
+ async function fetcher([officer, year]: [OfficerSession, number, string]) {
const date = setYear(new Date(), year);
const jan_1st = AbsoluteTime.fromMilliseconds(startOfYear(date).getTime());
const dec_31st = AbsoluteTime.fromMilliseconds(endOfYear(date).getTime());
@@ -123,7 +175,7 @@ export function useVqfServerStatistics(year: number) {
CounterResultByEventName<ReturnType<typeof EventReporting_VQF_queries>>
>,
TalerHttpError
- >(!session ? undefined : [session, year], fetcher, {
+ >(!session ? undefined : [session, year, "getVqfStatistics"], fetcher, {
refreshInterval: 0,
refreshWhenHidden: false,
revalidateOnFocus: false,
diff --git a/packages/taler-exchange-aml-webui/src/hooks/transfers.test.ts b/packages/taler-exchange-aml-webui/src/hooks/transfers.test.ts
@@ -0,0 +1,71 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+import {
+ OfficerSession,
+ TalerExchangeHttpClient,
+ opFixedSuccess,
+} from "@gnu-taler/taler-util";
+import { dummyHttpResponse } from "@gnu-taler/taler-util/http";
+import assert from "node:assert/strict";
+import test from "node:test";
+import { PAGINATED_LIST_REQUEST, requestTransferList } from "./transfers.js";
+
+const officer: OfficerSession = {
+ id: "4TQZQ0M6CB0JZXJ3Z1B4H7X3EVAQXX45SB9QT0NXZYKAHQXZ3EYG" as never,
+ __signingKey: new Uint8Array(32) as never,
+};
+
+test("wallet credit category dispatches only to the wallet endpoint", async () => {
+ const calls: string[] = [];
+ let walletParams: unknown;
+ const response = opFixedSuccess(dummyHttpResponse, { transfers: [] });
+ const api = {
+ getTransfersCredit: async () => {
+ calls.push("credit");
+ return response;
+ },
+ getTransfersDebit: async () => {
+ calls.push("debit");
+ return response;
+ },
+ getTransfersKycAuth: async () => {
+ calls.push("kyc-auth");
+ return response;
+ },
+ getWalletCredit: async (_officer, params) => {
+ calls.push("wallet-credit");
+ walletParams = params;
+ return response;
+ },
+ } satisfies Pick<
+ TalerExchangeHttpClient,
+ | "getTransfersCredit"
+ | "getTransfersDebit"
+ | "getTransfersKycAuth"
+ | "getWalletCredit"
+ >;
+
+ await requestTransferList(
+ api,
+ officer,
+ { id: "99", order: "dec", page: 2 },
+ "wallet-credit",
+ { currency: "CHF", value: 5, fraction: 0 },
+ "1111111111111111111111111111111111111111111111111111" as never,
+ );
+
+ assert.deepEqual(calls, ["wallet-credit"]);
+ assert.deepEqual(walletParams, {
+ order: "dec",
+ offset: "99",
+ limit: PAGINATED_LIST_REQUEST,
+ threshold: { currency: "CHF", value: 5, fraction: 0 },
+ account: "1111111111111111111111111111111111111111111111111111",
+ });
+});
diff --git a/packages/taler-exchange-aml-webui/src/hooks/transfers.ts b/packages/taler-exchange-aml-webui/src/hooks/transfers.ts
@@ -13,14 +13,14 @@
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 { useState } from "preact/hooks";
-
// FIX default import https://github.com/microsoft/TypeScript/issues/49189
import {
AmountJson,
+ Amounts,
ExchangeTransferListEntry,
OfficerSession,
PaytoHash,
+ TalerExchangeHttpClient,
TalerExchangeResultByMethod2,
TalerHttpError,
} from "@gnu-taler/taler-util";
@@ -62,6 +62,7 @@ export function useTransferDebit() {
const [pointer, updatePointer] = useListPointer(
(row: ExchangeTransferListEntry) => String(row.rowid),
+ "debit",
);
async function fetcher([officer, offset]: [
@@ -93,7 +94,47 @@ export function useTransferDebit() {
);
}
-type Direction = "credit" | "debit" | "kyc-auth";
+export type TransferCategory =
+ | "credit"
+ | "debit"
+ | "kyc-auth"
+ | "wallet-credit";
+
+type TransferListApi = Pick<
+ TalerExchangeHttpClient,
+ | "getTransfersCredit"
+ | "getTransfersDebit"
+ | "getTransfersKycAuth"
+ | "getWalletCredit"
+>;
+
+export async function requestTransferList(
+ api: TransferListApi,
+ officer: OfficerSession,
+ offset: ListPointer,
+ direction: TransferCategory,
+ threshold?: AmountJson,
+ account?: PaytoHash,
+) {
+ const params = {
+ order: offset.order,
+ offset: offset.id,
+ limit: PAGINATED_LIST_REQUEST,
+ threshold,
+ account,
+ };
+ switch (direction) {
+ case "credit":
+ return await api.getTransfersCredit(officer, params);
+ case "debit":
+ return await api.getTransfersDebit(officer, params);
+ case "kyc-auth":
+ return await api.getTransfersKycAuth(officer, params);
+ case "wallet-credit":
+ return await api.getWalletCredit(officer, params);
+ }
+}
+
/**
* @param args
* @returns
@@ -103,7 +144,7 @@ export function useTransferList({
threshold,
account,
}: {
- direction?: "credit" | "debit" | "kyc-auth";
+ direction?: TransferCategory;
threshold?: AmountJson;
account?: PaytoHash;
} = {}) {
@@ -115,60 +156,33 @@ export function useTransferList({
const [pointer, updatePointer] = useListPointer(
(row: ExchangeTransferListEntry) => String(row.rowid),
+ `${direction ?? "debit"}:${threshold ? Amounts.stringify(threshold) : ""}:${account ?? ""}`,
);
async function fetcher([officer, offset, direction, threshold, account]: [
OfficerSession,
ListPointer,
- Direction,
+ TransferCategory,
AmountJson | undefined,
PaytoHash | undefined,
]) {
- switch (direction) {
- case "credit": {
- return await api.getTransfersCredit(officer, {
- order: offset.order,
- offset: offset.id,
- limit: PAGINATED_LIST_REQUEST,
- threshold,
- account,
- });
- }
- case "debit": {
- return await api.getTransfersDebit(officer, {
- order: offset.order,
- offset: offset.id,
- limit: PAGINATED_LIST_REQUEST,
- threshold,
- account,
- });
- }
- case "kyc-auth": {
- return await api.getTransfersKycAuth(officer, {
- order: offset.order,
- offset: offset.id,
- limit: PAGINATED_LIST_REQUEST,
- threshold,
- account,
- });
- }
- }
+ return await requestTransferList(
+ api,
+ officer,
+ offset,
+ direction,
+ threshold,
+ account,
+ );
}
const { data, error } = useSWR<
TalerExchangeResultByMethod2<"getTransfersCredit">,
TalerHttpError
>(
- !session
+ !session || !direction
? undefined
- : [
- session,
- pointer,
- direction ?? "debit",
- threshold,
- account,
- "getTransfers",
- ],
+ : [session, pointer, direction, threshold, account, "getTransfers"],
fetcher,
);
diff --git a/packages/taler-exchange-aml-webui/src/i18n/aml-backoffice.pot b/packages/taler-exchange-aml-webui/src/i18n/aml-backoffice.pot
@@ -24,2291 +24,4258 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-
-#. screenid: 118
-#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:103
-msgid "Use testing dialect"
-msgstr ""
-
#. screenid: 118
-#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:105
+#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:114
msgid "Allow Insecure password"
msgstr ""
#. screenid: 118
-#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:107
+#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:116
msgid "Keep session after reload"
msgstr ""
#. screenid: 118
-#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:109
+#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:118
msgid "Don't compress request"
msgstr ""
#. screenid: 101
-#: packages/taler-exchange-aml-webui/src/ExchangeAmlFrame.tsx:75
-msgid "Preferences"
+#: packages/taler-exchange-aml-webui/src/ExchangeAmlFrame.tsx:85
+msgid "Lock session"
msgstr ""
#. screenid: 101
-#: packages/taler-exchange-aml-webui/src/ExchangeAmlFrame.tsx:120
-msgid "Show debug information"
+#: packages/taler-exchange-aml-webui/src/ExchangeAmlFrame.tsx:90
+msgid "Lock"
msgstr ""
#. screenid: 125
#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:46
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:45
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:94
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:47
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:47
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:115
msgid "Password"
msgstr ""
#. screenid: 125
#. screenid: 122
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:50
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:71
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:555
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:996
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:749
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:780
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:797
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:827
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:841
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:51
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:72
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:629
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1108
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:794
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:825
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:842
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:872
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:886
msgid "Required"
msgstr ""
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:54
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:55
msgid "should have at least 12 characters"
msgstr ""
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:56
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:57
msgid "should have lowercase and uppercase characters"
msgstr ""
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:58
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:59
msgid "should have numbers"
msgstr ""
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:60
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:61
msgid "should have at least one character which is not a number or letter"
msgstr ""
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:67
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:68
msgid "Repeat password"
msgstr ""
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:73
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:74
msgid "doesn't match"
msgstr ""
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:105
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:112
msgid "Create session"
msgstr ""
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:117
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:139
msgid "Create"
msgstr ""
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:66
-msgid "Failed to unlock the session."
-msgstr ""
-
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:69
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:243
-msgid "Authorization denied for this session. Contact the administrator."
+#: packages/taler-exchange-aml-webui/src/components/AccountBadges.tsx:28
+msgid "Wallet account"
msgstr ""
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:80
-msgid "Session locked"
+#: packages/taler-exchange-aml-webui/src/components/AccountBadges.tsx:28
+msgid "Bank account"
msgstr ""
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:83
-msgid ""
-"Your session is normally locked anytime you reload. To unlock type your "
-"password again."
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/components/AccountBadges.tsx:40
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:93
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:245
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:296
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:100
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:130
+msgid "Under investigation"
msgstr ""
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:108
-msgid "Unlock"
+#: packages/taler-exchange-aml-webui/src/components/AccountBadges.tsx:89
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:101
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:254
+msgid "High risk"
msgstr ""
-#. screenid: 119
-#. screenid: 112
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:116
-#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:81
-msgid "Forget session"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:51
+msgid "Payment target type"
msgstr ""
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:55
-msgid "There are no rules for operations"
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:81
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:199
+msgid "Account holder"
msgstr ""
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:58
-msgid "This means that no operation has any limit."
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:107
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:110
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:571
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:806
+msgid "IBAN"
msgstr ""
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:69
-msgid "Add custom rule"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:109
+msgid "BIC"
msgstr ""
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:94
-msgid "Operation"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:114
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:119
+msgid "Bank"
msgstr ""
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:100
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:625
-msgid "Threshold"
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:115
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:120
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:154
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:160
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:295
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:859
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:364
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:435
+msgid "Account"
msgstr ""
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:106
-msgid "Escalation"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:116
+msgid "Taler bank"
msgstr ""
-#. screenid: 121
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:120
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:243
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:800
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:844
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:902
-msgid "%1$s"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:121
+msgid "Cyclos"
msgstr ""
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:195
-msgctxt "threshold"
-msgid "%1$s every %2$s"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:124
+msgid "Bitcoin address"
msgstr ""
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:213
-msgid "(all)"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:129
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:144
+msgid "Reserve public key"
msgstr ""
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:59
-#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:69
-msgid "Since"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:133
+msgid "Bitcoin"
msgstr ""
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:70
-msgid "Expired"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:136
+msgid "Ethereum address"
msgstr ""
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:72
-msgid "Expires"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:139
+msgid "Ethereum"
msgstr ""
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:82
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:724
-msgid "Successor measure"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:142
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:70
+msgid "Exchange"
msgstr ""
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:140
-msgid "AML officer justification"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:149
+msgid "Taler reserve"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/components/ShowDefaultRules.tsx:11
-msgid "Default rules"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:150
+msgid "Taler reserve (HTTP)"
msgstr ""
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:42
-msgid "Forms"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:157
+msgid "Test account"
msgstr ""
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:45
-msgid "Measures used to gather information about the customer."
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:180
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:225
+msgid "Account details unavailable"
msgstr ""
-#. screenid: 123
-#. screenid: 108
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:69
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:162
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:248
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:153
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:552
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:992
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:192
-msgid "Name"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:54
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:96
+msgid "Not opened"
msgstr ""
-#. screenid: 123
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:76
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:169
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:584
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:837
-msgid "Check"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:59
+msgid "Opened:"
msgstr ""
-#. screenid: 123
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:82
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:255
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:564
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:791
-msgid "Program"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:68
+msgid "Closed:"
msgstr ""
-#. screenid: 123
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:88
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:175
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:267
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:607
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:805
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:893
-msgid "Context"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:94
+msgid "Closed"
msgstr ""
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:102
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:189
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:281
-msgid "Modify"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:95
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:263
+msgid "Open"
msgstr ""
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:135
-msgid "Info"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:125
+msgid "No note"
msgstr ""
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:138
-msgid "Will show information to the user."
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:136
+msgid "Show full note"
msgstr ""
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:221
-msgid "Instant measures"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:146
+msgid "System information"
msgstr ""
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:224
-msgid "Triggered immediately without customer interaction."
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:149
+msgid "Transactions remain below the threshold that opens an AML file."
msgstr ""
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:261
-msgid "Input requirement"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:122
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:202
+msgid "Account case"
msgstr ""
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:78
-msgid "Already completed."
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:149
+msgid "Failed to download AML file."
msgstr ""
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:80
-msgid "Waiting to be completed."
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:152
+msgid "No AML file is available for this account."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:183
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:365
-msgid "Current active rules"
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:154
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:72
+msgid "Authorization denied for this session. Contact the administrator."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:188
-msgid "There are no rules for this account yet."
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:156
+msgid "The account or session was not found."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:238
-msgid "New rule form"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:158
+msgid "The session is disabled. Contact the administrator."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:250
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:230
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:412
-msgid "Add"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:160
+msgid "The exchange does not support PDF reports."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:258
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:221
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:403
-msgid "Cancel"
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:175
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:354
+msgid "Read-only officers cannot create AML decisions."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:356
-msgid "Basic plan"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:177
+msgid "A payto URI is required to create a new decision."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:367
-msgid "Premium"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:194
+msgid "Back to accounts"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:378
-msgid "E-commerce"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:224
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:505
+msgid "File no. %1$s"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:389
-msgid "Point of Sale"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:253
+msgid "New decision"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:408
-msgid "Check rules"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:265
+msgid "Download AML file (PDF)"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:428
-msgid ""
-"The account is a wallet and there are bank account operation's limits which "
-"may trigger actions that are not required: %1$s"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:278
+msgid "AML file download started."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:437
-msgid ""
-"The account isn't a wallet and there are wallet operation's limits which may "
-"trigger actions that are not required: %1$s"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:284
+msgid "Account notes"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:446
-msgid ""
-"The account is a wallet and there are wallet operation's limits which are "
-"not limited: %1$s"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:293
+msgid "Current account status and notes could not be loaded."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:454
-msgid ""
-"The AML account is a bank account, but not all account-related operations "
-"are limited ( %1$s)."
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:302
+msgid "Try again"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:482
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:269
-msgid "New rules"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:316
+msgid "Account identifiers"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:503
-msgid "Reset rules to current state"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:325
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:509
+msgid "Technical identifiers"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:511
-msgid "Set rules to default"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:329
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:513
+msgid "Full payto URI"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:519
-msgid "Freeze account"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:331
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:144
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:155
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:173
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:190
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:390
+msgid "Unavailable"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:535
-msgid "Behavior on rule expiration"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:332
+msgid "Copy payto URI"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:546
-msgid "Reset measure"
+#. screenid: 113
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:335
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:517
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:188
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:157
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:289
+msgid "Normalized payto hash"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:558
-msgid "Reset expiration"
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:337
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:194
+msgid "Copy normalized payto hash"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:583
-msgctxt "operation type"
-msgid "Withdraw"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:341
+msgid "File number"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:585
-msgctxt "operation type"
-msgid "Deposit"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:343
+msgid "Copy file number"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:587
-msgctxt "operation type"
-msgid "Merge"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:351
+msgid "Account case views"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:589
-msgctxt "operation type"
-msgid "Aggregate"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:355
+msgid "Overview"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:591
-msgctxt "operation type"
-msgid "Balance"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:360
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:565
+msgid "Transfers"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:593
-msgctxt "operation type"
-msgid "Refund"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:365
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:67
+msgid "Decision history"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:595
-msgctxt "operation type"
+#: packages/taler-exchange-aml-webui/src/components/ConfirmationModal.tsx:73
msgid "Close"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:597
-msgctxt "operation type"
-msgid "Transaction"
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/ConfirmationModal.tsx:91
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:207
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:534
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:280
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:469
+msgid "Cancel"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:612
-msgid "Operation type"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:36
+msgid "AML officer enrollment request"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:633
-msgid "Timeframe"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:37
+msgid ""
+"Please enroll this AML officer public key:\n"
+"\n"
+"%1$s"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:639
-msgid "Exposed"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:59
+msgid "Officer key awaiting enrollment"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:640
-msgid "Is this limit communicated to the customer?"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:62
+msgid ""
+"This browser has created an AML officer key, but the exchange has not granted it "
+"access. Ask the exchange operator or administrator to enroll the public key "
+"below."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:652
-msgid "Escalation measure"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:70
+msgid "AML officer public key"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:653
-msgid ""
-"Measures that the customer will need to satisfy to apply for a new threshold."
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:76
+msgid "Copy AML officer public key"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:658
-msgid "All measures"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:82
+msgid "After the operator confirms enrollment, retry the access check."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:659
-msgid "Hint the customer that all measures should be completed"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:92
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:69
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:212
+msgid "Retry access check"
msgstr ""
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:672
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:157
-msgid "Expiration"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:101
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:188
+msgid "Checking officer access"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:673
-msgid "Predefined shortcuts"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:104
+msgid "Last checked at %1$s"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:677
-msgid "In a week"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:114
+msgid "Request enrollment"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:685
-msgid "In a month"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:121
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:128
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:77
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:85
+msgid "Discard this key"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:693
-msgid "In a year"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:127
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:84
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:250
+msgid "Confirmation required"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:701
-msgid "Never"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:135
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:92
+msgid ""
+"Discarding this key removes the officer session from this browser. You will need "
+"to create a new key to use the AML WebUI again."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:712
-msgid "Expiration date"
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:41
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:205
+msgid "Failed to check AML officer access."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:713
-msgid "Until when are the new rules active."
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:45
+msgid ""
+"This officer key cannot authenticate with the exchange. Retry the check or "
+"discard the key and create a new session."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:725
-msgid "Measure taken automatically upon expiration of the current decision."
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:50
+msgid "The exchange rejected the officer access check."
msgstr ""
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:107
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:62
-msgid "Failed to load account information."
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:57
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:211
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:522
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:101
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:612
+msgid "Technical details"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:125
-msgid "Failed to load decision history."
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:69
+msgid "Failed to unlock the session."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:143
-msgid "Failed to load current legitimizations."
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:95
+msgid "Session locked"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:188
-msgid "New decision"
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:98
+msgid ""
+"Your session is normally locked anytime you reload. To unlock type your password "
+"again."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:196
-msgid "Show transfers"
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:136
+msgid "Unlock"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:236
-msgid "Failed to download report."
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:144
+msgid "Forget session"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:241
-msgid "The account has no KYC info."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:162
+msgid "Review derived account properties"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:245
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:183
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:195
-msgid "Session not found. Contact the administrator."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:165
+msgid ""
+"Values may be derived from the selected AML/KYC form. Confirm them against the "
+"case record and change only values that require an officer override."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:247
-msgid "The session is disabled. Contact the administrator."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:187
+msgid "Reset to derived values"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:249
-msgid "The server doesn't support PDF download. Contact the administrator."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:192
+msgid "Invalid custom properties"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:260
-msgid "Case history for selected account"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:193
+msgid ""
+"Custom property names and values must be non-empty and names must be unique and "
+"different from built-in properties."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:265
-msgid "ID:"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:216
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:466
+msgid "Properties"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:271
-msgid "Payto:"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:217
+msgid "Built-in property names are preserved when the decision is submitted."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:282
-msgid "Export as PDF"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:223
+msgid "Custom properties"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:298
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:279
-msgid "Export completed"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:224
+msgid "Add more properties that are not listed above."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:301
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:282
-msgid "Click here to save the file in your computer."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:229
+msgid "New properties"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:310
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:411
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:208
-msgid "Under investigation"
+#. screenid: 123
+#. screenid: 108
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:234
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:73
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:171
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:261
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:204
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:626
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1104
+msgid "Name"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:311
-msgid ""
-"This account requires a manual review and is waiting for a decision to be "
-"made."
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:240
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:720
+msgid "Value"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:322
-msgid "Collected information"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:262
+msgid "Current note on the GwG file"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:325
-msgid "Every attribute collection event (via form upload or KYC provider)."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:267
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:63
+msgid "Customer name or internal alias."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:333
-msgid "No collected attributes for this account."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:272
+msgid "Is the account active for deposit and payments?"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:347
-msgid "Current account properties"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:277
+msgid "Is the account idle?"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:354
-msgid "No active decision found"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:278
+msgid "No operation for a period of time"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:355
-msgid ""
-"There is no decision for this account yet. The account is limited by the "
-"default rules."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:283
+msgid "Does account belong to a domestic PEP?"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:384
-msgid "Previous AML decisions"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:288
+msgid "Does account belong to a foreign PEP?"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:403
-msgid "No AML history found"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:293
+msgid "Does account belong to an international-organization PEP?"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:409
-msgid "Current active measures"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:298
+msgid "Does account belong to a high risk customer?"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:537
-msgid "Now"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:303
+msgid "Does account belong to a person from a high risk country?"
msgstr ""
-#. screenid: 112
-#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:43
-msgid "Session public key"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:308
+msgid "The MROS reporting state for the account."
msgstr ""
-#. screenid: 112
-#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:59
-msgid "Request session activation"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:313
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:307
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:175
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:199
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:497
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:630
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:653
+msgid "None"
msgstr ""
-#. screenid: 112
-#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:70
-msgid "Lock session"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:317
+msgid "Pending investigation"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:73
-msgid "Failed to load accounts"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:321
+msgid "Investigated without suspicion"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:83
-msgid "Failed to load the accounts"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:325
+msgid "Reported simple suspicion"
msgstr ""
-#. screenid: 111
-#. screenid: 110
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:88
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:168
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:76
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:128
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:66
-msgid ""
-"This session signature is invalid, contact administrator or create a new one."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:329
+msgid "Reported substantiated suspicion"
msgstr ""
-#. screenid: 111
-#. screenid: 110
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:95
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:175
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:83
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:135
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:73
-msgid ""
-"The designated AML session is not known, contact administrator or create a "
-"new one."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:336
+msgid "Informal reason why the AML investigation was triggered"
msgstr ""
-#. screenid: 111
-#. screenid: 110
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:102
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:182
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:90
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:142
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:80
-msgid ""
-"The designated AML session is not enabled, contact administrator or create a "
-"new one."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:341
+msgid "Identifies the sanction list entry that the account matched against"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:122
-msgid "High risk accounts. Only with custom rules."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:343
+msgid "Best match, does not mean it was a good match."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:123
-msgid "Account with custom rules."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:347
+msgid "Score for how good the sanction list match was"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:125
-msgid "High risk accounts"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:349
+msgid "Integer score from 0 (no match) to 1,000,000,000 (best match)."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:126
-msgid "All known accounts."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:353
+msgid "Score for how much supporting data we had for the sanction list match"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:130
-msgid "High risk accounts under investigation. Only with custom rules."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:355
+msgid "Integer score from 0 (no supporting data) to 1,000,000,000 (highest confidence)."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:131
-msgid "Accounts under investigation. Only with custom rules."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:359
+msgid ""
+"Suppress flagging this account when it creates a hit on a sanctions list, this "
+"is a false-positive"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:133
-msgid "High risk accounts under investigation."
+#: packages/taler-exchange-aml-webui/src/components/DecisionProperties.tsx:46
+msgid "No account properties were recorded."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:134
-msgid "Accounts under investigation."
+#: packages/taler-exchange-aml-webui/src/components/DecisionProperties.tsx:91
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:317
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:509
+msgid "Yes"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:137
-msgid "High risk accounts without investigation. Only with custom rules."
+#: packages/taler-exchange-aml-webui/src/components/DecisionProperties.tsx:91
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:317
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:509
+msgid "No"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:138
-msgid "Accounts without investigation. Only with custom rules."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:59
+msgid "There are no rules for operations"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:140
-msgid "High risk accounts without investigation."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:62
+msgid "This means that no operation has any limit."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:141
-msgid "Accounts without investigation."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:90
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:312
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:500
+msgid "Operation"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:174
-msgid "Failed to download"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:96
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:695
+msgid "Threshold"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:177
-msgid "There are no accounts in the resultset."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:102
+msgid "Escalation"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:179
-msgid "The format requested is not acceptable from the service provider."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:108
+msgid "Visibility"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:181
-msgid "Authorization denied for this session."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:114
+msgid "Priority"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:185
-msgid "The session is disabled. Contact the administrator"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:121
+msgid "Actions"
msgstr ""
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:240
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:368
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:142
+msgctxt "threshold"
+msgid "%1$s every %2$s"
+msgstr ""
+
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:161
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:725
+msgid "Block operation"
+msgstr ""
+
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:163
+msgid "All required:"
+msgstr ""
+
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:165
+msgid "Any one:"
+msgstr ""
+
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:182
+msgid "Customer-visible"
+msgstr ""
+
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:184
+msgid "Internal"
+msgstr ""
+
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:197
+msgid "Move %1$s rule up"
+msgstr ""
+
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:206
+msgid "Move %1$s rule down"
+msgstr ""
+
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:217
+msgid "Edit %1$s rule"
+msgstr ""
+
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:240
+msgid "Remove %1$s rule"
+msgstr ""
+
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:282
+msgctxt "operation type"
+msgid "Withdraw"
+msgstr ""
+
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:284
+msgctxt "operation type"
+msgid "Deposit"
+msgstr ""
+
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:286
+msgctxt "operation type"
+msgid "Merge"
+msgstr ""
+
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:288
+msgctxt "operation type"
+msgid "Aggregate"
+msgstr ""
+
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:290
+msgctxt "operation type"
+msgid "Balance"
+msgstr ""
+
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:292
+msgctxt "operation type"
+msgid "Refund"
+msgstr ""
+
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:294
+msgctxt "operation type"
+msgid "Close"
+msgstr ""
+
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:296
+msgctxt "operation type"
+msgid "Transaction"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:83
+msgid "Decision provenance"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:85
+msgid "Decision made by"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:88
+msgid "AML officer (name unavailable)"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:89
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:369
+msgid "Automated outcome"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:91
+msgid "Resulting case disposition"
+msgstr ""
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:94
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:246
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:105
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:132
+msgid "Not under investigation"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:99
+msgid "Justification:"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:101
+msgid "No justification was recorded."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:112
+msgid "View submitted customer information"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:120
+msgid "Immediate measures requested"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:123
+msgid "This decision did not request an immediate measure."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:131
+msgid "All listed measures were requested (AND)."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:132
+msgid "Any listed measure may satisfy the request (OR)."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:151
+msgid "Operation rules"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:156
+msgid "No operation-specific rules were stored."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:163
+msgid "Policy transition"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:165
+msgid "Policy expires"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:173
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:796
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:362
+msgid "Successor measure"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:174
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:479
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:163
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:365
+msgid "Exchange defaults"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:179
+msgid "Custom measure definitions"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:182
+msgid "No custom measures were stored."
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:202
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:278
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:128
+msgid "Account properties"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:214
+msgid "Decision row"
+msgstr ""
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:217
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:174
+msgid "Officer public key"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:219
+msgid "Not applicable"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:277
+msgid "Stored custom definition"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:284
+msgid "Current measure metadata is still loading; the stored machine name is shown."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:286
+msgid ""
+"The current measure configuration could not be loaded; the stored machine name "
+"is shown."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:287
+msgid "No stored or currently configured definition is available for this reference."
+msgstr ""
+
+#. screenid: 123
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:291
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:80
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:178
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:659
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:938
+msgid "Check"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:295
+msgid "Built-in check that requires no customer interaction."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:296
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:304
+msgid "Description unavailable"
+msgstr ""
+
+#. screenid: 123
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:299
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:86
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:268
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:639
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:891
+msgid "Program"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:316
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:508
+msgid "Voluntary"
+msgstr ""
+
+#. screenid: 123
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:320
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:92
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:184
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:280
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:682
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:907
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:644
+msgid "Context"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:349
+msgid "Decision date"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:357
+msgid "Expired"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:357
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:419
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:354
+msgid "Expires"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:362
+msgid "Decision status"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:363
+msgid "Current"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:363
+msgid "Historical"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:365
+msgid "Made by"
+msgstr ""
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:368
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:272
+msgid "AML officer"
+msgstr ""
+
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:44
+msgid "Forms"
+msgstr ""
+
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:47
+msgid "Measures used to gather information about the customer."
+msgstr ""
+
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:62
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:160
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:250
+msgid "Select"
+msgstr ""
+
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:107
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:199
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:295
+msgid "Modify"
+msgstr ""
+
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:141
+msgid "Information"
+msgstr ""
+
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:144
+msgid "Shows information to the customer without running an AML program."
+msgstr ""
+
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:232
+msgid "Instant measures"
+msgstr ""
+
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:235
+msgid "Triggered immediately without customer interaction."
+msgstr ""
+
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:274
+msgid "Input requirement"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:56
+msgid "Started"
+msgstr ""
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:64
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:301
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:140
+msgid "Status"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:76
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:447
+msgid "Forbidden"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:78
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:443
+msgid "Completed"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:79
+msgid "Waiting for customer"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:92
+msgid "The operation is categorically forbidden by this requirement."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:100
+msgid "All listed measures must be completed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:104
+msgid "Any one listed measure may be completed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:24
+msgid "Expiration shortcuts"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:29
+msgid "In a week"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:30
+msgid "In a month"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:31
+msgid "In a year"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:50
+msgid "Never"
+msgstr ""
+
+#. screenid: 122
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:115
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:98
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:63
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:72
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:209
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:218
+msgid "Failed to load available measures."
+msgstr ""
+
+#. screenid: 122
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:120
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:112
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:77
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:223
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:294
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:480
+msgid "The officer session is invalid."
+msgstr ""
+
+#. screenid: 122
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:124
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:116
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:81
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:227
+msgid "The measures endpoint was not found."
+msgstr ""
+
+#. screenid: 122
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:130
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:122
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:87
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:233
+msgid "The officer session is disabled."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:195
+msgid "Edit proposed rule"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:197
+msgid "Add proposed rule"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:216
+msgid "Save rule"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:218
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:372
+msgid "Add rule"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:356
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:348
+msgid "Proposed rules"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:359
+msgid ""
+"This complete rule set replaces the currently applied rules and exchange "
+"defaults until it expires. Higher rows take precedence."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:390
+msgid "Rules for another account type"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:393
+msgid "These operations do not apply to this account type: %1$s."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:400
+msgid "Operations without limits"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:401
+msgid "No proposed rule limits these operations: %1$s."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:408
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:336
+msgid "Invalid proposed rules"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:409
+msgid ""
+"Edit the highlighted rule set before continuing. Hard blocks cannot be combined "
+"with measures, and Balance and Refund rules must use an instant timeframe."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:432
+msgid "Remove proposed rule?"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:434
+msgid "This is the final rule. Removing it leaves every applicable operation unlimited."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:439
+msgid "The rule will be removed from the proposed set."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:449
+msgid "Keep rule"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:459
+msgid "Remove rule"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:467
+msgid "Replace proposed rules"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:470
+msgid "Preview a complete replacement before applying it."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:476
+msgid "Currently applied"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:486
+msgid "E-commerce"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:489
+msgid "Point of Sale"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:496
+msgid "Basic plan"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:501
+msgid "Premium"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:510
+msgid "Freeze account"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:518
+msgid "Replacement preview"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:521
+msgid "Confirm account freeze"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:522
+msgid "Every applicable operation will receive a zero hard limit."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:548
+msgid "Apply replacement"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:556
+msgid "Rule expiration"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:559
+msgid "Choose how long the proposed rules apply and what happens afterwards."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:578
+msgid "The proposed rules never expire, so no successor action will run."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:598
+msgid "Restore currently applied expiration"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:682
+msgid "Operation type"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:704
+msgid "Timeframe"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:705
+msgid ""
+"Use Y, M, D, h, m or s after each number. Forever accumulates over the account's "
+"full history."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:709
+msgid "Instant timeframe"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:710
+msgid ""
+"Balance and Refund limits apply to one balance or transaction, so their "
+"timeframe is fixed to zero."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:716
+msgid "Exposed"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:717
+msgid "Is this limit communicated to the customer?"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:723
+msgid "When the threshold is crossed"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:726
+msgid "Require measures"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:740
+msgid "Required measures"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:741
+msgid "Measures that the customer will need to satisfy to apply for a new threshold."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:747
+msgid "All measures"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:748
+msgid "Hint the customer that all measures should be completed"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:767
+msgid "Expiration date"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:768
+msgid "Until when are the new rules active."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:773
+msgid "Choose a future expiration date or Never."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:779
+msgid "After expiration"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:781
+msgid "Return to exchange defaults"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:782
+msgid "Trigger a successor measure"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:797
+msgid "Measure taken automatically upon expiration of the current decision."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:805
+msgid "This successor measure is no longer available."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:133
+msgid "Case summary"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:134
+msgid "Current review state and the latest account activity."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:138
+msgid "Review status"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:142
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:153
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:171
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:188
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:492
+msgid "Loading…"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:146
+msgid "Manual review required — waiting for an AML decision."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:147
+msgid "No manual review"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:150
+msgid "Effective decision"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:168
+msgid "Requirements"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:185
+msgid "Latest collected information"
+msgstr ""
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:208
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:305
+msgid "Current decision"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:209
+msgid "The complete AML decision currently applied to this account."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:216
+msgid "Effective policy could not be loaded"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:234
+msgid "Exchange defaults apply"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:235
+msgid "No AML officer decision is active for this account."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:238
+msgid "Account type unavailable"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:239
+msgid ""
+"Open this case from the account directory or payto search to see the applicable "
+"default rules."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:248
+msgid "Default rules could not be loaded"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:255
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:419
+#: packages/taler-exchange-aml-webui/src/components/ShowDefaultRules.tsx:11
+msgid "Default rules"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:266
+msgid "Collected information"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:267
+msgid "KYC information filed by the customer or an AML officer."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:273
+msgid "Collected information could not be loaded"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:279
+msgid "No collected information"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:280
+msgid "No KYC information has been collected for this account."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:302
+msgid "Active requirements"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:303
+msgid "Measures the customer must complete under the current policy."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:309
+msgid "Active requirements could not be loaded"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:315
+msgid "No active requirements"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:316
+msgid "The customer has no active legitimization measures to complete."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:413
+msgid "Officer decision"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:416
+msgid "Does not expire"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:439
+msgid "Waiting"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:451
+msgid "More on later pages"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:510
+msgid "Try loading this section again."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:518
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:97
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:633
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:205
+msgid "Retry"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:566
+msgid "Unconfigured form"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:567
+msgid "Form not identified"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:576
+msgid "Filed by an AML officer"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:577
+msgid "Provided by the customer"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:581
+msgid "Attribute data is unavailable."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:595
+msgid "View details"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:70
+msgid "Review superseded AML decisions for this account, from newest to oldest."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:79
+msgid "Loading decision history…"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:84
+msgid "Decision history could not be loaded"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:87
+msgid "Try loading the decision history again."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:111
+msgid "No previous decisions"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:114
+msgid "No superseded AML decisions have been recorded for this account."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:125
+msgid "Previous decisions"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:153
+msgid "The export could not be prepared. Try again."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:164
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:173
+msgid "Failed to load accounts"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:193
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:552
msgid "Accounts"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:247
-msgid "Export as file"
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:196
+msgid "Review accounts known to the exchange for AML and KYC handling."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:203
+msgid "Export filtered accounts"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:211
+msgid "Download CSV"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:218
+msgid "Download Excel"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:226
+msgid "Preparing export…"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:230
+msgid "Export failed"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:236
+msgid "Account filters"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:242
+msgid "Investigation"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:244
+msgid "All accounts"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:251
+msgid "Risk"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:253
+msgid "All risk levels"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:255
+msgid "Not high risk"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:260
+msgid "File status"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:262
+msgid "All file statuses"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:264
+msgid "Not open"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:273
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:589
+msgid "Clear filters"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:283
+msgid "Showing %1$s accounts · newest first"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:290
+msgid "AML and KYC accounts"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:298
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:458
+msgid "Account lifecycle"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:304
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:467
+msgid "Latest note"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:550
+msgid "Copied"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:550
+msgid "Copy"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:576
+msgid "No matching accounts"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:576
+msgid "No accounts yet"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:580
+msgid "No accounts match the selected filters."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:581
+msgid "The exchange has not recorded any AML or KYC accounts yet."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:647
+msgid "This officer session is not authorized to list accounts."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:649
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:674
+msgid "The exchange does not recognize this officer session."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:651
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:676
+msgid "This officer session is currently disabled."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:668
+msgid "There are no matching accounts to export."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:670
+msgid "The exchange does not support the selected export format."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:672
+msgid "This officer session is not authorized to export accounts."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:52
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:546
+msgid "Dashboard"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:55
+msgid ""
+"Review cases requiring attention, investigate accounts, and monitor AML "
+"reporting indicators."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:77
+msgid "Review case queue"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:80
+msgid "Review accounts currently under investigation."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:94
+msgid "Inspect transfers"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:97
+msgid "Find credit, debit, and KYC authorization activity."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:128
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:165
+msgid "Statistics"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:132
+msgid "No reporting profile for this dialect"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:137
+msgid ""
+"The testing dialect does not define dashboard statistics. Select TOPS in "
+"development settings to inspect the TOPS reporting profile."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:154
+msgid "Failed to load TOPS statistics."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:192
+msgid "Some statistics are unavailable."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:195
+msgid "The available values are shown below. Missing values are not zero."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:275
+msgid "Accounts open"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:278
+msgid "New files last year"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:281
+msgid "Closed files last year"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:284
+msgid "MROS substantiated"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:287
+msgid "MROS simple"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:290
+msgid "High risk files"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:293
+msgid "PEP files"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:333
+msgid "Number of accounts that are opened"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:336
+msgid "Number of new GwG files in the last year"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:339
+msgid "Number of GwG files closed in the last year"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:342
+msgid "Number of MROS reports based on Art 9 Abs. 1 GwG (per year)"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:345
+msgid "Number of MROS reports based on Art 305ter Abs. 2 StGB (per year)"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:348
+msgid "Number of GwG files of high-risk customers"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:351
+msgid "Number of GwG files managed with “increased risk” due to PEP status"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:354
+msgid "Number of customers with open proceeding."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:400
+msgid "previous"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:443
+msgid "Decreased by"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:447
+msgid "Increased by"
+msgstr ""
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:114
+msgid ""
+"The built-in event selection differs from the events derived from the proposed "
+"account state."
+msgstr ""
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:119
+msgid ""
+"Built-in events are derived from changes to the proposed account properties. "
+"They are stored for reporting and statistics; they do not notify the customer."
+msgstr ""
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:138
+msgid "Reset to derived events"
+msgstr ""
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:169
+msgid "Calculated"
+msgstr ""
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:170
+msgid "Events derived from proposed property changes and submitted information."
+msgstr ""
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:184
+msgid "Other built-in events"
+msgstr ""
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:185
+msgid "Additional events that may be recorded manually."
+msgstr ""
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:198
+msgid "Custom events"
+msgstr ""
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:199
+msgid "Operator-defined event names that are not part of the selected dialect."
+msgstr ""
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:213
+msgid "Events recorded with this decision"
+msgstr ""
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:214
+msgid "Events are added only after the decision is successfully submitted."
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:209
+msgid "Add customer information"
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:212
+msgid ""
+"The completed form is attached to this AML decision as reviewed account "
+"information. It does not create a customer-facing measure."
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:223
+msgid "Selected form"
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:233
+msgid "Choose another form"
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:242
+msgid "Expiration"
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:243
+msgid "Expiration date of the information filled in this form."
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:254
+msgid "Form context"
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:261
+msgid "Advanced form context"
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:264
+msgid ""
+"Only change this operator-defined JSON when the form documentation requires "
+"additional context."
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:270
+msgid "Context as JSON"
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:291
+msgid "Invalid JSON"
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:296
+msgid "Invalid expiration"
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:297
+msgid "Attributes require an expiration date in the future or set to Never."
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:355
+msgid "Include new information"
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:356
+msgid ""
+"This step is optional. Select a form to attach newly reviewed AML/KYC "
+"information, or continue without one."
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:361
+msgid "AML/KYC form"
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:362
+msgid "Search AML/KYC forms"
+msgstr ""
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:101
+msgid "The account will be included in the AML investigation queue."
+msgstr ""
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:106
+msgid "The account will not be included in the AML investigation queue."
+msgstr ""
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:114
+msgid "Current investigation status"
+msgstr ""
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:128
+msgid "No previous decision"
+msgstr ""
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:140
+msgid "Investigation status after this decision"
+msgstr ""
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:145
+msgid ""
+"Choose whether the account should remain in the AML investigation queue after "
+"this decision is submitted."
+msgstr ""
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:201
+msgid "Full name used in the payto URI when creating this previously unknown account."
+msgstr ""
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:208
+msgid "Decision rationale"
+msgstr ""
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:209
+msgid ""
+"Record the facts and reasoning needed to understand this decision in a later "
+"audit or review."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:264
+msgid "Create custom measure"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:266
+msgid "Edit custom measure"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:270
+msgid ""
+"Combine a customer check with an AML program, or use SKIP to run a program "
+"immediately. Context values must satisfy the selected check and program "
+"requirements."
+msgstr ""
+
+#. screenid: 122
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:289
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:478
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:366
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:115
+msgid "Add custom measure"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:299
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:488
+msgid "Save changes"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:306
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:495
+msgid "Remove custom measure"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:547
+msgid "Configure %1$s verification"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:558
+msgid "Use advanced measure editor"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:587
+msgid "Use guided verification editor"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:632
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1111
+msgid "There is already a measure with that name"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:646
+msgid ""
+"Runs immediately for SKIP measures, or after a successful check. It may be "
+"omitted for a check that only presents or collects information."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:650
+msgid "Missing check or program"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:660
+msgid ""
+"The customer-facing check to perform before the program. Leave empty to use SKIP "
+"and run the program immediately."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:683
+msgid ""
+"Configuration values required by the selected check or program. Property names "
+"and value types must match the exchange configuration."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:690
+msgid "Field name"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:695
+msgid "Type"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:699
+msgid "string"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:703
+msgid "number"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:707
+msgid "boolean"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:711
+msgid "json"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:738
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:792
+msgid "Program \"%1$s\" is not available"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:742
+msgid "There are unsatisfied inputs: %1$s"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:750
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:772
+msgid "Check \"%1$s\" is not available"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:756
+msgid "There are missing inputs: %1$s"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:779
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:799
+msgid "There are missing requirements: %1$s"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:855
+msgid "Can't be empty"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:859
+msgid "Not a number"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:861
+msgid "It should be finite"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:866
+msgid "It should be either \"true\" or \"false\""
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:871
+msgid "Couldn't parse as json string: %1$s"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:899
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:946
+msgid "Description"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:915
+msgid "Inputs"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:954
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:534
+msgid "Outputs"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:962
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:401
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:533
+msgid "Required context"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:970
+msgid "Fallback"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:993
+msgid "Context values"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1045
+msgid "Selected pipeline"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1048
+msgid "Review how the exchange will execute this measure."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1105
+msgid "Name of the verification measure"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1118
+msgid "Read only"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1119
+msgid "Prevent the customer from changing the address"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:154
+msgid "Customer actions after submission"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:157
+msgid ""
+"Immediate measures start as soon as this decision is accepted. A measure may "
+"show information, collect customer data, or run an AML program. Leave the "
+"selection empty when no immediate customer action is required."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:302
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:301
+msgid "Too many SKIP measures"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:303
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:302
+msgid "At most one immediate measure may use the SKIP check."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:332
+msgid "Configure verification measure “%1$s”"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:372
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:522
+msgid "Custom measures"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:375
+msgid "Measures defined only for this proposed decision."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:399
+msgid "Edit"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:407
+msgid "Available exchange measures"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:410
+msgid "Reusable templates configured by the exchange operator"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:432
+msgid "Use as template"
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:512
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:288
+msgid "Immediate measures"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:513
+msgid ""
+"Selected measures begin immediately after the decision is accepted by the "
+"exchange."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:518
+msgid "Require every selected measure"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:519
+msgid ""
+"When enabled, all selected measures must be completed. Otherwise, completing any "
+"one of them is sufficient."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:190
+msgid "Failed to make the decision."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:193
+msgid "Invalid credentials."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:195
+msgid "Session not found. Contact the administrator."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:197
+msgid ""
+"The exchange rejected the decision because the officer session is disabled or "
+"the account has a newer decision. Reload the account before trying again."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:251
+msgid ""
+"This decision records that an MROS report was filed. Confirm that the report has "
+"actually been submitted before continuing."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:264
+msgid "Go back and review"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:271
+msgid "Confirm decision"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:283
+msgid "Unknown measure"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:284
+msgid ""
+"A rule or immediate action references a measure that is not available. Review "
+"the rules and measures before submitting."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:291
+msgid "Invalid custom measure"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:292
+msgid ""
+"A custom measure references an unavailable check or program, lacks required "
+"context, or cannot provide the selected program inputs. Review the immediate "
+"measures before submitting."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:310
+msgid "Missing deadline"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:311
+msgid "Set when the proposed rules expire and what should happen afterward."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:319
+msgid "Invalid rule expiration"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:320
+msgid "Rule expiration must be in the future or set to Never."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:327
+msgid "Missing rules"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:328
+msgid "A decision must contain the complete rule set that will apply to the account."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:337
+msgid ""
+"Review the proposed rules. Hard blocks must be explicit, and Balance and Refund "
+"rules must use an instant timeframe."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:376
+msgid "Immediate measures not reviewed"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:378
+msgid "Review whether the customer must complete any immediate measures."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:384
+msgid "No immediate customer action"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:385
+msgid "No measure will start when this decision is submitted."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:396
+msgid "Account properties not reviewed"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:398
+msgid "Review the account properties before submitting the decision."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:409
+msgid "Reporting events not reviewed"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:411
+msgid "Review which statistical events will be recorded with the decision."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:420
+msgid "Case disposition incomplete"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:421
+msgid "You must complete the justification section."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:430
+msgid "Invalid attributes"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:431
+msgid ""
+"Correct the selected form or continue without attaching new customer "
+"information."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:443
+msgid "Decision details"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:447
+msgid "Justification"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:450
+msgid "Not provided"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:454
+msgid "The account remains under investigation."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:458
+msgid "The account will not remain under investigation."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:487
+msgid "No account properties"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:493
+msgid "Events"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:496
+msgid "No events"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:501
+msgid "Submitted attributes"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:509
+msgid "expiration set"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:515
+msgid "No new attributes"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:537
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:550
+msgid "Discard decision"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:544
+msgid "Submit AML decision"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:549
+msgid "Discard this decision?"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:554
+msgid ""
+"All entries made in this decision wizard will be lost. No change will be "
+"submitted to the exchange."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:571
+msgid "Review this step"
+msgstr ""
+
+#. screenid: 113
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:172
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:250
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:507
+msgid "Back to account"
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:177
+msgid "New AML decision"
+msgstr ""
+
+#. screenid: 113
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:201
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:297
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:790
+msgid "Payto URI"
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:218
+msgid "Step %1$s of %2$s"
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:236
+msgid "Decision steps"
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:245
+msgid "Previous step"
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:254
+msgid "Next step"
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:273
+msgid "Customer information"
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:274
+msgid "Optionally add reviewed AML/KYC information to this decision."
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:279
+msgid "Review the account state derived from the available information."
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:283
+msgid "Reporting events"
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:284
+msgid "Review the statistical events recorded with this decision."
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:289
+msgid "Choose actions the customer must complete after the decision is submitted."
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:293
+msgid "Transaction rules"
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:294
+msgid "Set operation thresholds, escalation measures, and expiration behavior."
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:298
+msgid "Case disposition"
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:299
+msgid "Record the rationale and whether the case remains under investigation."
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:305
+msgid "Review and submit"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:318
-msgid "No results"
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:306
+msgid "Check the complete decision before signing and submitting it."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:329
-msgid "#"
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:326
+msgid "Decision progress"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:335
-msgid "Account Identification"
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:407
+msgid "Loading account decision"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:341
-msgid "Open time"
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:418
+msgid "Decision for account"
msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:347
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:243
-msgid "Status"
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:425
+msgid "Decision for wallet account"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:365
-msgid "From %1$s %2$s To %3$s"
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:431
+msgid "Decision for bank account"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:371
-msgid "Since %1$s"
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:107
+msgid "Enter a valid HTTP or HTTPS URL."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:374
-msgid "Not opened"
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:114
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:176
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:218
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:259
+msgid "Development settings"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:419
-msgid "High risk"
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:117
+msgid "These browser-local settings are intended for development and troubleshooting."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:427
-msgid "With custom rules"
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:132
+msgid "Exchange connection"
msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:642
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:673
-msgid "Invalid account"
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:135
+msgid ""
+"Changing the exchange reloads the application. The override is stored only in "
+"this browser."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:657
-msgid "Search by ID"
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:147
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:97
+msgid "Exchange base URL"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:687
-msgid "Under investigation: "
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:166
+msgid "Leave empty to use the configured URL: %1$s"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:696
-msgid "High risk:"
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:170
+msgid "Leave empty to derive the exchange URL from this page."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:705
-msgid "Custom rules:"
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:184
+msgid "Currently connected to"
msgstr ""
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:47
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:366
-msgid "Dashboard"
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:196
+msgid "Apply and reload"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:88
-msgid "Failed to load TOPS statistics."
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:207
+msgid "Use configured URL"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:99
-msgid "Statistics"
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:214
+msgid "Preferences"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:187
-msgid "Accounts open"
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:221
+msgid "AML SPA dialect"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:190
-msgid "New files last year"
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:236
+msgid "Use exchange configuration"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:193
-msgid "Closed files last year"
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:240
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:44
+msgid "Testing"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:196
-msgid "MROS substantiated"
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:244
+msgid ""
+"Override how this web interface presents dialect-specific AML rules and "
+"properties. The override is stored only in this browser."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:199
-msgid "MROS simple"
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:262
+msgid "Show debug information"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:202
-msgid "High risk files"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:45
+msgid "Fallback dialect for development and testing."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:205
-msgid "PEP files"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:52
+msgid "TOPS"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:267
-msgid "Number of accounts that are opened"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:53
+msgid "Taler Operations deployment for Swiss AML processes."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:270
-msgid "Number of new GwG files in the last year"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:56
+msgid "File note"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:273
-msgid "Number of GwG files closed in the last year"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:57
+msgid "Current note on the GwG file."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:276
-msgid "Number of MROS reports based on Art 9 Abs. 1 GwG (per year)"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:58
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:64
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:112
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:124
+msgid "Text"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:279
-msgid "Number of MROS reports based on Art 305ter Abs. 2 StGB (per year)"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:62
+msgid "Customer label"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:282
-msgid "Number of GwG files of high-risk customers"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:68
+msgid "Account open"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:285
-msgid "Number of GwG files managed with “increased risk” due to PEP status"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:69
+msgid "Whether the account is active for deposits and payments."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:288
-msgid "Number of customers with open proceeding."
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:70
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:76
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:82
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:88
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:94
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:100
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:106
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:142
+msgid "Boolean"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:343
-msgid "previous"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:74
+msgid "Domestic PEP"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:386
-msgid "Decreased by"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:75
+msgid "Whether the customer is a domestic politically exposed person."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:390
-msgid "Increased by"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:80
+msgid "Foreign PEP"
msgstr ""
-#. screenid: 108
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:115
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:217
-msgid "Events"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:81
+msgid "Whether the customer is a foreign politically exposed person."
msgstr ""
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:116
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:86
+msgid "International-organization PEP"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:87
msgid ""
-"The events will be triggered only after the decision has been confirmed."
+"Whether the customer is a politically exposed person associated with an "
+"international organization."
msgstr ""
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:121
-msgid "Calculated"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:92
+msgid "High-risk customer"
msgstr ""
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:122
-msgid "Events based on properties and new attributes that should be triggered"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:93
+msgid "Whether the customer is classified as high risk."
msgstr ""
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:134
-msgid "Others"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:98
+msgid "High-risk country"
msgstr ""
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:135
-msgid "Events that can be triggered manually"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:99
+msgid "Whether the customer is associated with a high-risk country."
msgstr ""
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:147
-msgid "Custom list"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:104
+msgid "Account idle"
msgstr ""
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:148
-msgid "Events without built-in support."
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:105
+msgid "Whether the account has been marked as idle."
msgstr ""
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:132
-msgid "Complete the form"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:110
+msgid "Investigation trigger"
msgstr ""
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:135
-msgid "These measures will ask the customer for information."
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:111
+msgid "Informal reason why the AML investigation was triggered."
msgstr ""
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:153
-msgid "change form"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:116
+msgid "Investigation state"
msgstr ""
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:158
-msgid "Expiration date of the information filled in this form."
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:117
+msgid "Special-clarification and MROS reporting state for the account."
msgstr ""
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:217
-msgid "Include new information"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:118
+msgid "Enumeration"
msgstr ""
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:218
-msgid ""
-"Select a form to submit new information about the customer or continue to "
-"the next step"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:122
+msgid "Sanction-list best match"
msgstr ""
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:223
-msgid "Form:"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:123
+msgid "Sanction-list entry that best matched the account, regardless of match quality."
msgstr ""
-#. screenid: 106
-#. screenid: 113
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:81
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:227
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:237
-msgid "Justification"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:128
+msgid "Sanction-list rating"
msgstr ""
-#. screenid: 106
-#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:86
-msgid "Keep investigation?"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:129
+msgid "Score from 0 (no match) to 1,000,000,000 (best match)."
msgstr ""
-#. screenid: 106
-#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:91
-msgid "Account holder"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:130
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:136
+msgid "Integer"
msgstr ""
-#. screenid: 106
-#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:93
-msgid "Full name of the account holder"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:134
+msgid "Sanction-list confidence"
msgstr ""
-#. screenid: 122
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:90
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:394
-msgid "loading..."
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:135
+msgid "Score from 0 (no supporting data) to 1,000,000,000 (highest confidence)."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:239
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:421
-msgid "Update"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:140
+msgid "Suppress sanction-list match"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:246
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:428
-msgid "Remove"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:141
+msgid "Whether this account's sanction-list hit is treated as a false positive."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:473
-msgid "Configure verification type: %1$s"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:148
+msgid "Account opened"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:484
-msgid "Show complete form"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:149
+msgid "Recorded when an account changes to open."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:505
-msgid "Configure measure"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:153
+msgid "Account closed"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:515
-msgid "Show as verification"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:154
+msgid "Recorded when an account changes from open to closed."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:557
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:998
-msgid "There is already a measure with that name"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:158
+msgid "High-risk customer classification added"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:571
-msgid "Only required when no check is specified"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:159
+msgid "Recorded when an open account becomes classified as a high-risk customer."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:575
-msgid "Missing check or program"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:163
+msgid "High-risk customer classification removed"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:585
-msgid "Without a check the program will run automatically"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:164
+msgid "Recorded when the high-risk customer classification is removed."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:614
-msgid "Field name"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:168
+msgid "High-risk country classification added"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:619
-msgid "Type"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:169
+msgid "Recorded when an open account becomes associated with a high-risk country."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:623
-msgid "string"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:173
+msgid "High-risk country classification removed"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:627
-msgid "number"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:174
+msgid "Recorded when the high-risk country classification is removed."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:631
-msgid "boolean"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:178
+msgid "PEP classification added"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:635
-msgid "json"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:179
+msgid "Recorded when an open account becomes associated with any PEP category."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:644
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:197
-msgid "Value"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:183
+msgid "PEP classification removed"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:663
-msgid "There are unsatisfied inputs: %1$s"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:184
+msgid "Recorded when the account is no longer associated with any PEP category."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:674
-msgid "There are missing inputs: %1$s"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:188
+msgid "Foreign PEP classification added"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:694
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:711
-msgid "There are missing requirements: %1$s"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:189
+msgid "Recorded when an open account becomes associated with a foreign PEP."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:751
-msgid "Can't be empty"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:193
+msgid "Foreign PEP classification removed"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:755
-msgid "It should be a number"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:194
+msgid "Recorded when the foreign PEP classification is removed."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:757
-msgid "Not a number"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:198
+msgid "Domestic PEP classification added"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:759
-msgid "It should be finite"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:199
+msgid "Recorded when an open account becomes associated with a domestic PEP."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:761
-msgid "It should be a safe integer"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:203
+msgid "Domestic PEP classification removed"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:766
-msgid "It should be either \"true\" or \"false\""
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:204
+msgid "Recorded when the domestic PEP classification is removed."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:771
-msgid "Couldn't parse as json string: %1$s"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:208
+msgid "International-organization PEP classification added"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:797
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:940
-msgid "Description"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:209
+msgid ""
+"Recorded when an open account becomes associated with an "
+"international-organization PEP."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:813
-msgid "Inputs"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:213
+msgid "International-organization PEP classification removed"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:849
-msgid "Output"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:214
+msgid "Recorded when the international-organization PEP classification is removed."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:859
-msgid "Requires"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:218
+msgid "Simple suspicion reported to MROS"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:867
-msgid "Fallback"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:219
+msgid "Recorded when a report is filed under Article 305ter paragraph 2 StGB."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:993
-msgid "Name of the verification measure"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:223
+msgid "Substantiated suspicion reported to MROS"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1005
-msgid "Read only"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:224
+msgid "Recorded when a report is filed under Article 9 GwG."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1006
-msgid "Prevent the customer from changing the address"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:228
+msgid "Investigation concluded"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:256
-msgid "Configure verification measure: \"%1$s\""
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:229
+msgid "Recorded when a pending special clarification is concluded."
msgstr ""
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:294
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:115
-msgid "Add custom measure"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:233
+msgid "Investigation conclusion reversed"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:300
-msgid "Custom measures"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:234
+msgid ""
+"Recorded when a previously concluded investigation returns to a non-concluded "
+"state."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:50
+msgid "Browser override"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:52
+msgid "Exchange configuration"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:329
-msgid "Server measures"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:53
+msgid "Default fallback"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:426
-msgid "New measures"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:59
+msgid "Exchange and AML configuration"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:427
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:62
msgid ""
-"Measures that are available/executed directly after the decision is "
-"confirmed."
+"Exchange identity, the active AML dialect, and the checks and programs available "
+"to AML decisions."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:154
-msgid "Reset to default"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:71
+msgid "Public information reported by this exchange."
msgstr ""
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:175
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:234
-msgid "Properties"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:75
+msgid "Base URL"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:181
-msgid "Custom properties"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:76
+msgid "Protocol"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:182
-msgid "Add more properties that are not listed above."
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:77
+msgid "Protocol version"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:187
-msgid "New properties"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:78
+msgid "Implementation"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:218
-msgid "Current note on the GwG file"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:80
+msgid "Not reported"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:223
-msgid "Customer name or internal alias."
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:82
+msgid "Currency"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:228
-msgid "Is the account active for deposit and payments?"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:88
+msgid "AML dialect"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:233
-msgid "Is the account idle?"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:95
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:119
+msgid "Effective dialect"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:234
-msgid "No operation for a period of time"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:111
+msgid "Configured dialect"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:239
-msgid "Does account belong to a domestic PEP?"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:114
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:504
+msgid "Not specified"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:244
-msgid "Does account belong to a foreign PEP?"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:129
+msgid "Canonical properties defined by the effective dialect."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:249
-msgid "Does account belong to an international-organization PEP?"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:130
+msgid "This dialect does not define account properties."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:254
-msgid "Does account belong to a high risk customer?"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:136
+msgid "Derived events"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:259
-msgid "Does account belong to a person from a high risk country?"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:137
+msgid "Canonical events derived from account property changes."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:264
-msgid "The MROS reporting state for the account."
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:138
+msgid "This dialect does not define derived events."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:269
-msgid "None"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:144
+msgid "AML measures"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:273
-msgid "Pending investigation"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:145
+msgid "Checks, programs, root measures, and default rules reported by the exchange."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:277
-msgid "Investigated without suspicion"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:213
+msgid "%1$s entry"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:281
-msgid "Reported simple suspicion"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:214
+msgid "%1$s entries"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:285
-msgid "Reported substantiated suspicion"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:277
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:289
+msgid "Failed to load the exchange AML measures."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:292
-msgid "Informal reason why the AML investigation was triggered"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:300
+msgid "The measures endpoint is not available."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:297
-msgid "Identifies the sanction list entry that the account matched against"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:306
+msgid "The exchange configuration changed. Reload it and try again."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:299
-msgid "Best match, does not mean it was a good match."
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:332
+msgid "Retry loading measures"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:303
-msgid "Score for how good the sanction list match was"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:351
+msgid "Root measures"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:308
-msgid "Score for how much supporting data we had for the sanction list match"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:366
+msgid "No root measures are configured."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:313
-msgid ""
-"Suppress flagging this account when it creates a hit on a sanctions list, "
-"this is a false-positive"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:371
+msgid "KYC checks"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:190
-msgid "Failed to make the decision."
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:386
+msgid "No KYC checks are configured."
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:193
-msgid "Invalid credentials."
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:391
+msgid "AML programs"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:197
-msgid ""
-"The session is disabled or a more recent decision was already submitted."
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:405
+msgid "Required inputs"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:208
-msgid "Confirmation required"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:413
+msgid "No AML programs are configured."
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:209
-msgid ""
-"This decision declares that the MROS report has concluded. Please make sure "
-"that this is the case"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:428
+msgid "No default AML rules are configured."
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:222
-msgid "I want to check first!"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:480
+msgid "KYC check"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:229
-msgid "Confirm decision"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:484
+msgid "Built-in check that proceeds without collecting customer data."
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:245
-msgid "Missing deadline"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:491
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:497
+msgid "AML program"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:248
-msgid ""
-"Deadline should specify when this rules ends and what is the next measures "
-"to apply after expiration."
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:536
+msgid "Fallback measure"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:257
-msgid "Missing rules"
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:602
+msgid "Unavailable reference"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:260
-msgid "Can't make a decision without rules."
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:48
+msgid "Session and access"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:284
-msgid "Missing active measure"
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:51
+msgid ""
+"Review this officer's exchange access and manage the unlocked key in this "
+"browser."
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:287
-msgid "You should specify in the measure section."
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:66
+msgid "Officer access"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:294
-msgid "No customer action required."
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:71
+msgid "Officer name"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:297
-msgid "No active measure has been selected."
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:77
+msgid "Permissions"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:305
-msgid "Missing properties"
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:88
+msgid "Read-only"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:308
-msgid "You should specify in the properties section."
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:90
+msgid "Read and write"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:318
-msgid "Missing events"
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:118
+msgid "Session security"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:321
-msgid "You should specify in the events section."
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:121
+msgid "Lock the session when you leave this device unattended."
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:331
-msgid "Missing justification"
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:133
+msgid "Lock now"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:334
-msgid "You must complete the justification section."
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:148
+msgid "Unlocked"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:344
-msgid "Invalid attributes"
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:154
+msgid "Locks automatically"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:347
-msgid "You should check form errors or submit a decision without attributes."
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:165
+msgid "Exact time"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:361
-msgid "Clear"
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:185
+msgid "Copy public key"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:368
-msgid "Send decision"
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:200
+msgid "Remove key from this browser"
msgstr ""
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:173
-msgid "Prev"
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:203
+msgid ""
+"Removing this key deletes the officer key from this browser. It does not revoke "
+"or change the officer's access at the exchange. Ask the exchange operator to "
+"revoke access if needed."
msgstr ""
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:182
-msgid "Next"
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:214
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:222
+msgid "Remove key"
msgstr ""
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:207
-msgid "Attributes"
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:221
+msgid "Remove officer key?"
msgstr ""
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:208
-msgid "Add more information about the customer"
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:231
+msgid ""
+"This deletes the officer key from this browser. You will need to create and "
+"enroll a new key to use the AML WebUI here again."
msgstr ""
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:212
-msgid "Rules"
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:237
+msgid ""
+"This does not revoke the officer at the exchange. Ask the exchange operator to "
+"revoke its access if the key may be compromised."
msgstr ""
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:213
-msgid "Set the limit of the operations"
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:86
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:559
+msgid "Find account"
msgstr ""
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:218
-msgid "Trigger notifications."
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:89
+msgid "Look up an account by its payto information or normalized payto hash."
msgstr ""
-#. screenid: 113
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:222
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:102
-msgid "Measures"
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:100
+msgid "Find by payto"
msgstr ""
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:223
-msgid "Ask the customer to take action."
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:146
+msgid "Find by normalized payto hash"
msgstr ""
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:228
-msgid "Describe the decision."
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:169
+msgid "Enter a valid 52-character normalized payto hash."
msgstr ""
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:235
-msgid "Flag the current account state."
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:179
+msgid "Open account"
msgstr ""
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:239
-msgid "Summary"
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:214
+msgid "Failed to load account decisions."
msgstr ""
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:240
-msgid "Review and submit."
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:223
+msgid "Failed to load the account history."
msgstr ""
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:404
-msgid "Decision for account:"
+#. screenid: 111
+#. screenid: 110
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:228
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:82
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:268
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:66
+msgid "This session signature is invalid, contact administrator or create a new one."
msgstr ""
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:411
-msgid "Decision for wallet:"
+#. screenid: 111
+#. screenid: 110
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:235
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:89
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:275
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:73
+msgid ""
+"The designated AML session is not known, contact administrator or create a new "
+"one."
msgstr ""
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:417
-msgid "Decision for bank account:"
+#. screenid: 111
+#. screenid: 110
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:242
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:96
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:282
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:80
+msgid ""
+"The designated AML session is not enabled, contact administrator or create a new "
+"one."
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:88
-msgid "Search account"
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:268
+msgid "Account found"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:154
-msgid "Failed to load account decisions."
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:271
+msgid ""
+"This account has an AML decision history. Open its case to review current rules, "
+"measures, attributes, and past decisions."
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:163
-msgid "Failed to load the account history."
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:283
+msgid "Open account case"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:205
-msgid "Check account details"
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:309
+msgid "Active"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:212
-msgid "Account most recent decisions"
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:311
+msgid "No active decision"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:231
-msgid "When"
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:317
+msgid "Case status"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:265
-msgid "LATEST"
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:321
+msgid "Investigation required"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:270
-msgid "ACTIVE"
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:323
+msgid "No investigation requested"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:297
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:333
msgid "Account not found"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:298
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:335
msgid "There is no history known for this account yet."
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:308
-msgid "You can make a decision for this account anyway."
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:350
+msgid "Start a decision for this account"
msgstr ""
#. screenid: 111
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:357
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:400
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:449
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:490
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:377
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:403
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:445
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:493
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:533
msgid "Search"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:528
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:761
-msgid "IBAN"
-msgstr ""
-
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:532
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:575
msgid "Taler Bank"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:536
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:579
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:364
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:433
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:441
msgid "Wallet"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:540
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:583
msgid "Generic Payto:// URI"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:543
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:586
msgid "Account type"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:553
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:596
msgid "Should be 52 characters."
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:555
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:598
msgid "Failed to parse: %1$s"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:567
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:610
msgid "Address contains invalid characters."
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:569
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:612
msgid "Can't mix uppercased and lowercased characters."
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:571
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:614
msgid "The addr checksum doesn't match."
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:573
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:616
msgid "Missing separator or address type."
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:575
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:618
msgid "Address should have less than 90 characters."
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:577
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:620
msgid "Address should have more than 6 characters."
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:579
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:622
msgid "Decoding issue."
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:581
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:624
msgid "Invalid data"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:591
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:634
msgid "Unsupported country."
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:593
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:636
msgid "IBANs have fewer than 34 characters."
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:595
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:638
msgid "IBANs have more than 4 characters."
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:597
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:640
msgid "IBAN length is invalid for this country."
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:597
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:642
msgid "It should only contain numbers and letters."
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:599
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:644
msgid "The checksum is wrong."
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:617
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:662
msgid "The string should start with payto://"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:619
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:664
msgid "After the target type it should follow a '/' with more information."
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:621
-msgid ""
-"The target type is not supported, only x-taler-bank, taler-reserve or iban"
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:666
+msgid "The target type is not supported, only x-taler-bank, taler-reserve or iban"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:626
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:671
msgid "IBAN is missing"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:628
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:673
msgid "Bitcoin address is missing"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:630
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:675
msgid "Bank host and account is missing"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:632
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:634
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:677
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:679
msgid "Exchange host and account is missing"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:636
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:681
msgid "Ethereum address is missing"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:638
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:683
msgid "Cyclos address is missing"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:640
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:685
msgid "Void address is missing"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:648
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:693
msgid "Invalid IBAN: %1$s"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:655
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:700
msgid "Invalid BTC: %1$s"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:660
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:683
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:696
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:705
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:728
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:741
msgid "Invalid reserve: %1$s"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:671
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:681
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:694
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:715
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:716
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:726
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:739
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:760
msgid "Invalid host"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:707
-msgid "Invalid address"
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:718
+msgid "Invalid account"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:745
-msgid "Payto URI"
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:752
+msgid "Invalid address"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:746
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:791
msgid "As defined by RFC 8905"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:747
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:792
msgid "payto://"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:762
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:807
msgid "International Bank Account Number"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:763
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:808
msgid "DE1231231231"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:775
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:820
msgid "Host"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:776
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:821
msgid "Exchange hostname"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:777
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:822
msgid "exchange.taler.net"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:782
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:829
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:827
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:874
msgid "Remove last '/'"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:784
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:801
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:332
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:376
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:829
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:846
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:426
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:472
msgid "Invalid value"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:792
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:837
msgid "ID"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:793
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:838
msgid "Wallet reserve public key"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:794
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:839
msgid "abcdef1235"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:799
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:844
msgid "Should be 52 characters"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:814
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:268
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:338
-msgid "Account"
-msgstr ""
-
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:815
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:860
msgid "Bank account identification"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:816
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:861
msgid "DE123123123"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:822
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:867
msgid "Hostname"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:823
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:868
msgid "Without the scheme, may include subpath: bank.com, bank.com/path/"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:824
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:869
msgid "bank.demo.taler.net"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:831
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:876
msgid "Invalid hostname"
msgstr ""
#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:71
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:68
+msgid "Failed to load account information."
+msgstr ""
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:77
msgid "Failed to load the account information."
msgstr ""
#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:198
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:204
-msgid "Different form version"
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:115
+msgid "Collection event not found"
msgstr ""
#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:199
-msgid "The collected information don't have the form version used."
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:117
+msgid "There is no collection event with ID %1$s for this account."
msgstr ""
#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:205
-msgid ""
-"The collected information used the form version \"%1$s \" but is not "
-"available."
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:129
+msgid "Attributes unavailable"
msgstr ""
#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:217
-msgid "Case details"
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:131
+msgid "The collection event does not contain readable attributes."
msgstr ""
#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:231
-msgid "Next event"
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:148
+msgid "Form identifier missing"
msgstr ""
#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:245
-msgid "Previous event"
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:150
+msgid "The collected information does not identify the form used to create it."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:66
-msgid "Direction"
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:165
+msgid "Form not available"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:69
-msgid "Credit"
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:167
+msgid "Form %1$s is not configured in this AML Web UI."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:73
-msgid "Debit"
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:255
+msgid "Collected AML/KYC information"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:77
-msgid "KYC Auth"
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:262
+msgid "Form"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:85
-msgid "Minimum amount"
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:267
+msgid "Collected"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:86
-msgid "All amounts below the given threshold will be filtered."
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:270
+msgid "Source"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:114
-msgid "Failed to load transfer list."
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:274
+msgid "Customer process"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:123
-msgid "Failed to load the transfer list."
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:277
+msgid "Event ID"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:160
-msgid "Select transaction type"
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:284
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:292
+msgid "Different form version"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:161
-msgid "Please select a transaction type to show transactions."
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:285
+msgid ""
+"The collected information does not identify the form version used. The latest "
+"configured version is shown and field labels may differ from those used at "
+"collection time."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:176
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:234
-msgid "Transfers history for account"
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:293
+msgid ""
+"Form version %1$s is not configured in this AML Web UI. Version %2$s is shown "
+"and field labels may differ."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:188
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:246
-msgid "Transfers history"
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:301
+msgid "Collected information events"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:195
-msgid "No transfers yet."
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:305
+msgid "Older event"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:197
-msgid "There are no transfers for this account."
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:316
+msgid "Newer event"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:201
-msgid ""
-"There are no transfers reported to the exchange with the current threshold."
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:329
+msgid "Submitted values"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:260
-msgid "Date"
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:369
+msgid "Officer view"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:264
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:310
-msgid "Amount"
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:371
+msgid "Customer view"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:314
-msgid "sent"
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:372
+msgid "JSON view"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:315
-msgid "received"
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:403
+msgid "Submitted information view"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:348
-msgid "to"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:109
+msgid "Incoming"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:349
-msgid "from"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:113
+msgid "Outgoing"
msgstr ""
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:92
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:101
-msgid "Welcome to the exchange configuration"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:117
+msgid "KYC authorization"
msgstr ""
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:372
-msgid "Transfers"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:127
+msgid "Wallet credits (P2P)"
msgstr ""
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:379
-msgid "Profile"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:140
+msgid "Transfer category"
msgstr ""
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:49
-msgid "Failed to load server measures."
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:147
+msgid "Minimum amount"
msgstr ""
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:61
-msgid "Failed to load the measures"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:148
+msgid "All amounts below the given threshold will be filtered."
msgstr ""
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:105
-msgid "A list of all the predefined measures you can use."
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:182
+msgid "Exchange transfer activity"
msgstr ""
-#. screenid: 122
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:165
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:174
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:214
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:222
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:90
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:99
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:62
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:71
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:191
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:200
-msgid "Failed to load available measures."
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:188
+msgid "Wallet credit activity"
msgstr ""
-#. screenid: 122
-#. screenid: 102
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:179
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:104
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:76
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:205
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:403
-msgid "The officer session is invalid."
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:190
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:198
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:241
+msgid "Transfer activity"
msgstr ""
-#. screenid: 122
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:183
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:80
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:209
-msgid "The measures endpoint was not found."
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:196
+msgid "Transfer activity for account"
msgstr ""
-#. screenid: 122
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:189
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:114
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:86
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:215
-msgid "The officer session is disabled."
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:204
+msgid ""
+"Inspect successful P2P credits received by this wallet. Requests that were not "
+"paid are not shown."
msgstr ""
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:182
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:190
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:389
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:398
-msgid "Failed to load the active AML decision."
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:209
+msgid ""
+"Inspect effective bank transfers observed by the exchange. Credit transfers are "
+"incoming, debit transfers are outgoing, and bounced or drain transfers are not "
+"included."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:488
-msgid "The officer session signature is invalid."
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:215
+msgid ""
+"Inspect effective transfers observed by the exchange. Incoming, outgoing, and "
+"KYC authorization entries are bank transfers. Wallet credits are successful P2P "
+"transfers into wallets."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:491
-msgid "The requested AML account or session was not found."
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:233
+msgid "Transfer filters"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:495
-msgid "The officer session is disabled or the account state changed."
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:254
+msgid "Failed to load transfer list."
msgstr ""
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:192
-msgid "Invalid expiration"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:263
+msgid "Failed to load the transfer list."
msgstr ""
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:193
-msgid "Attributes require an expiration date in the future."
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:299
+msgid "Select transaction type"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:288
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:273
-msgid "Too many SKIP measures"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:300
+msgid "Please select a transaction type to show transactions."
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:289
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:274
-msgid "At most one immediate measure may use the SKIP check."
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:314
+msgid "No wallet credits yet."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:491
-msgid "Require all measures"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:315
+msgid "No transfers yet."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:492
-msgid ""
-"Run all selected measures together instead of accepting any one of them."
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:319
+msgid "There are no P2P credits for this wallet."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:172
-msgid "Invalid custom properties"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:323
+msgid "There are no wallet credits reported to the exchange with the current threshold."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:173
-msgid ""
-"Custom property names and values must be non-empty and names must be unique "
-"and different from built-in properties."
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:328
+msgid "There are no transfers for this account."
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:265
-msgid "Unknown measure"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:332
+msgid "There are no transfers reported to the exchange with the current threshold."
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:266
-msgid ""
-"A rule or immediate action references a measure that is not available. "
-"Review the rules and measures before submitting."
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:343
+msgid "Unknown date"
msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:274
-msgid "Requires investigation"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:355
+msgid "Time"
msgstr ""
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:106
-msgid "Collection event not found"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:359
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:406
+msgid "Amount"
msgstr ""
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:107
-msgid "There is no collection event with ID %1$s for this account."
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:393
+msgid "Unknown time"
msgstr ""
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:116
-msgid "Attributes unavailable"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:410
+msgid "credited"
msgstr ""
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:117
-msgid "The collection event does not contain readable attributes."
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:412
+msgid "sent"
msgstr ""
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:131
-msgid "Form identifier missing"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:413
+msgid "received"
msgstr ""
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:132
-msgid "The collected information does not identify the form used to create it."
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:443
+msgid "to"
msgstr ""
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:144
-msgid "Form not available"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:444
+msgid "from"
msgstr ""
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:145
-msgid "Form %1$s is not configured in this AML Web UI."
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:165
+msgid "This exchange is not compatible with the AML WebUI."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:167
+msgid "Officer identity and permissions require exchange protocol v40 or newer."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:191
+msgid "Verifying that this public key is enrolled by the exchange."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:278
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:331
+msgid "Read-only officer access"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:279
+msgid "You can review AML information, but this officer key cannot submit decisions."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:332
+msgid "This officer key cannot create or submit AML decisions."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:340
+msgid "Return to account"
msgstr ""
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:407
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:466
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:475
+msgid "Failed to load the active AML decision."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:484
msgid "The account was not found."
msgstr ""
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:411
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:488
msgid "The account state changed. Reload it and try again."
msgstr ""
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:436
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:511
msgid ""
-"The payto URI does not belong to this account. Return to the account search "
-"and start the decision again."
+"The payto URI does not belong to this account. Return to the account search and "
+"start the decision again."
msgstr ""
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:448
-msgid ""
-"This account has no active decision and its payto URI is unknown. Start the "
-"decision from the account search so the account type can be determined "
-"safely."
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:571
+msgid "AML configuration"
msgstr ""
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:458
-msgid "Return to account"
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:577
+msgid "Session"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:585
+msgid "AML navigation"
+msgstr ""
+
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:49
+msgid "Failed to load server measures."
msgstr ""
+
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:61
+msgid "Failed to load the measures"
+msgstr ""
+
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:102
+msgid "Measures"
+msgstr ""
+
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:105
+msgid "A list of all the predefined measures you can use."
+msgstr ""
+
diff --git a/packages/taler-exchange-aml-webui/src/i18n/de.po b/packages/taler-exchange-aml-webui/src/i18n/de.po
@@ -1,3 +1,4 @@
+#
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: taler@gnu.org\n"
@@ -5,2399 +6,5273 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
#. screenid: 118
-#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:103
-msgid "Use testing dialect"
-msgstr "Test-Dialekt verwenden"
-
-#. screenid: 118
-#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:105
+#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:114
msgid "Allow Insecure password"
msgstr "Unsichere Passwörter erlauben"
#. screenid: 118
-#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:107
+#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:116
msgid "Keep session after reload"
msgstr "Sitzung nach Neuladen beibehalten"
#. screenid: 118
-#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:109
+#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:118
msgid "Don't compress request"
msgstr "Anfragen nicht komprimieren"
#. screenid: 101
-#: packages/taler-exchange-aml-webui/src/ExchangeAmlFrame.tsx:75
-msgid "Preferences"
-msgstr "Einstellungen"
+#: packages/taler-exchange-aml-webui/src/ExchangeAmlFrame.tsx:85
+msgid "Lock session"
+msgstr "Sitzung sperren"
#. screenid: 101
-#: packages/taler-exchange-aml-webui/src/ExchangeAmlFrame.tsx:120
-#, fuzzy
-msgid "Show debug information"
-msgstr "Debug-Informationen ansehen"
+#: packages/taler-exchange-aml-webui/src/ExchangeAmlFrame.tsx:90
+msgid "Lock"
+msgstr "Sperren"
#. screenid: 125
#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:46
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:45
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:94
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:47
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:47
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:115
msgid "Password"
msgstr "Passwort"
#. screenid: 125
#. screenid: 122
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:50
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:71
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:555
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:996
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:749
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:780
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:797
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:827
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:841
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:51
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:72
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:629
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1108
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:794
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:825
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:842
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:872
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:886
msgid "Required"
msgstr "Erforderlich"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:54
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:55
msgid "should have at least 12 characters"
msgstr "sollte mindestens 12 Zeichen haben"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:56
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:57
msgid "should have lowercase and uppercase characters"
msgstr "sollte Klein- und Großbuchstaben enthalten"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:58
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:59
msgid "should have numbers"
msgstr "sollte Zahlen enthalten"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:60
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:61
msgid "should have at least one character which is not a number or letter"
msgstr ""
"sollte mindestens ein Zeichen enthalten, das keine Zahl oder kein Buchstabe "
"ist"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:67
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:68
msgid "Repeat password"
msgstr "Passwort wiederholen"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:73
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:74
msgid "doesn't match"
msgstr "stimmt nicht überein"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:105
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:112
#, fuzzy
msgid "Create session"
msgstr "Konto erstellen"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:117
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:139
msgid "Create"
msgstr "Erstellen"
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:66
-msgid "Failed to unlock the session."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountBadges.tsx:28
+msgid "Wallet account"
+msgstr "Wallet-Konto"
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:69
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:243
-msgid "Authorization denied for this session. Contact the administrator."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountBadges.tsx:28
+msgid "Bank account"
+msgstr "Bankkonto"
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:80
-#, fuzzy
-msgid "Session locked"
-msgstr "Konto gesperrt"
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/components/AccountBadges.tsx:40
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:93
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:245
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:296
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:100
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:130
+msgid "Under investigation"
+msgstr "In Untersuchung"
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:83
-#, fuzzy
-msgid ""
-"Your session is normally locked anytime you reload. To unlock type your "
-"password again."
-msgstr ""
-"Ihr Konto wird normalerweise bei jedem Neuladen gesperrt. Geben Sie zum "
-"Entsperren Ihr Passwort erneut ein."
+#: packages/taler-exchange-aml-webui/src/components/AccountBadges.tsx:89
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:101
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:254
+msgid "High risk"
+msgstr "Hohes Risiko"
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:108
-msgid "Unlock"
-msgstr "Entsperren"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:51
+msgid "Payment target type"
+msgstr ""
-#. screenid: 119
-#. screenid: 112
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:116
-#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:81
-#, fuzzy
-msgid "Forget session"
-msgstr "Konto vergessen"
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:81
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:199
+msgid "Account holder"
+msgstr "Kontoinhaber"
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:55
-msgid "There are no rules for operations"
-msgstr "Es gibt keine Regeln für Vorgänge"
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:107
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:110
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:571
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:806
+msgid "IBAN"
+msgstr "IBAN"
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:58
-#, fuzzy
-msgid "This means that no operation has any limit."
-msgstr "Das bedeutet, dass alle Vorgänge keine Begrenzung haben."
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:109
+msgid "BIC"
+msgstr ""
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:69
-msgid "Add custom rule"
-msgstr "Benutzerdefinierte Regel hinzufügen"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:114
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:119
+msgid "Bank"
+msgstr ""
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:94
-msgid "Operation"
-msgstr "Vorgang"
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:115
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:120
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:154
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:160
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:295
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:859
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:364
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:435
+msgid "Account"
+msgstr "Konto"
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:100
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:625
-msgid "Threshold"
-msgstr "Schwellenwert"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:116
+msgid "Taler bank"
+msgstr "Taler-Bank"
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:106
-msgid "Escalation"
-msgstr "Eskalation"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:121
+msgid "Cyclos"
+msgstr ""
-#. screenid: 121
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:120
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:243
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:800
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:844
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:902
-msgid "%1$s"
-msgstr "%1$s"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:124
+msgid "Bitcoin address"
+msgstr ""
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:195
-msgctxt "threshold"
-msgid "%1$s every %2$s"
-msgstr "%1$s alle %2$s"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:129
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:144
+msgid "Reserve public key"
+msgstr ""
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:213
-msgid "(all)"
-msgstr "(alle)"
-
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:59
-#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:69
-msgid "Since"
-msgstr "Seit"
-
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:70
-msgid "Expired"
-msgstr "Abgelaufen"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:133
+msgid "Bitcoin"
+msgstr ""
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:72
-msgid "Expires"
-msgstr "Läuft ab"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:136
+msgid "Ethereum address"
+msgstr ""
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:82
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:724
-msgid "Successor measure"
-msgstr "Nachfolgemaßnahme"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:139
+msgid "Ethereum"
+msgstr ""
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:140
-msgid "AML officer justification"
-msgstr "Begründung des AML-Sachbearbeiters"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:142
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:70
+msgid "Exchange"
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/components/ShowDefaultRules.tsx:11
-msgid "Default rules"
-msgstr "Standardregeln"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:149
+msgid "Taler reserve"
+msgstr "Taler-Reserve"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:42
-msgid "Forms"
-msgstr "Formulare"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:150
+msgid "Taler reserve (HTTP)"
+msgstr ""
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:45
-#, fuzzy
-msgid "Measures used to gather information about the customer."
-msgstr "Maßnahmen zur Erfassung von Informationen über den Kunden."
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:157
+msgid "Test account"
+msgstr "Testkonto"
-#. screenid: 123
-#. screenid: 108
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:69
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:162
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:248
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:153
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:552
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:992
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:192
-msgid "Name"
-msgstr "Name"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:180
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:225
+msgid "Account details unavailable"
+msgstr ""
-#. screenid: 123
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:76
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:169
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:584
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:837
-msgid "Check"
-msgstr "Überprüfen"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:54
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:96
+msgid "Not opened"
+msgstr "Nicht eröffnet"
-#. screenid: 123
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:82
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:255
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:564
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:791
-msgid "Program"
-msgstr "Programm"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:59
+msgid "Opened:"
+msgstr "Eröffnet:"
-#. screenid: 123
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:88
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:175
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:267
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:607
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:805
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:893
-msgid "Context"
-msgstr "Kontext"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:68
+msgid "Closed:"
+msgstr "Geschlossen:"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:102
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:189
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:281
-msgid "Modify"
-msgstr "Ändern"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:94
+msgid "Closed"
+msgstr "Geschlossen"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:135
-msgid "Info"
-msgstr "Info"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:95
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:263
+msgid "Open"
+msgstr "Offen"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:138
-msgid "Will show information to the user."
-msgstr "Zeigt dem Benutzer Informationen an."
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:125
+msgid "No note"
+msgstr "Keine Notiz"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:221
-msgid "Instant measures"
-msgstr "Sofortmaßnahmen"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:136
+msgid "Show full note"
+msgstr "Vollständige Notiz anzeigen"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:224
-msgid "Triggered immediately without customer interaction."
-msgstr "Wird sofort ohne Kundeninteraktion ausgelöst."
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:146
+msgid "System information"
+msgstr "Systeminformation"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:261
-msgid "Input requirement"
-msgstr "Eingabeanforderung"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:149
+msgid "Transactions remain below the threshold that opens an AML file."
+msgstr ""
+"Die Transaktionen liegen weiterhin unter dem Schwellenwert, ab dem eine AML-"
+"Akte eröffnet wird."
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:78
-msgid "Already completed."
-msgstr "Bereits abgeschlossen."
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:122
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:202
+msgid "Account case"
+msgstr "Kontofall"
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:80
-msgid "Waiting to be completed."
-msgstr "Wartet auf Abschluss."
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:149
+msgid "Failed to download AML file."
+msgstr "Die AML-Akte konnte nicht heruntergeladen werden."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:183
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:365
-msgid "Current active rules"
-msgstr "Aktuell aktive Regeln"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:152
+msgid "No AML file is available for this account."
+msgstr "Für dieses Konto ist keine AML-Akte verfügbar."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:188
-msgid "There are no rules for this account yet."
-msgstr "Für dieses Konto gibt es noch keine Regeln."
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:154
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:72
+msgid "Authorization denied for this session. Contact the administrator."
+msgstr ""
+"Autorisierung für diese Sitzung verweigert. Wenden Sie sich an den "
+"Administrator."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:238
-msgid "New rule form"
-msgstr "Formular für neue Regel"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:156
+msgid "The account or session was not found."
+msgstr "Das Konto oder die Sitzung wurde nicht gefunden."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:250
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:230
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:412
-msgid "Add"
-msgstr "Hinzufügen"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:158
+msgid "The session is disabled. Contact the administrator."
+msgstr "Die Sitzung ist deaktiviert. Wenden Sie sich an den Administrator."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:258
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:221
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:403
-msgid "Cancel"
-msgstr "Abbrechen"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:160
+msgid "The exchange does not support PDF reports."
+msgstr "Der Exchange unterstützt keine PDF-Berichte."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:356
-msgid "Basic plan"
-msgstr "Basisplan"
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:175
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:354
+msgid "Read-only officers cannot create AML decisions."
+msgstr ""
+"Sachbearbeiter mit Lesezugriff können keine AML-Entscheidungen erstellen."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:367
-msgid "Premium"
-msgstr "Premium"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:177
+msgid "A payto URI is required to create a new decision."
+msgstr ""
+"Zum Erstellen einer neuen Entscheidung ist eine Payto-URI erforderlich."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:378
-msgid "E-commerce"
-msgstr "E-Commerce"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:194
+msgid "Back to accounts"
+msgstr "Zurück zu den Konten"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:389
-msgid "Point of Sale"
-msgstr "Point-of-Sale"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:224
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:505
+msgid "File no. %1$s"
+msgstr "Aktennr. %1$s"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:408
-msgid "Check rules"
-msgstr "Regeln überprüfen"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:253
+msgid "New decision"
+msgstr "Neue Entscheidung"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:428
-msgid ""
-"The account is a wallet and there are bank account operation's limits which "
-"may trigger actions that are not required: %1$s"
-msgstr ""
-"Das Konto ist eine Wallet, und es bestehen Limits für Bankkonto-Vorgänge, "
-"die möglicherweise nicht erforderliche Aktionen auslösen: %1$s"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:265
+msgid "Download AML file (PDF)"
+msgstr "AML-Akte herunterladen (PDF)"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:437
-msgid ""
-"The account isn't a wallet and there are wallet operation's limits which may "
-"trigger actions that are not required: %1$s"
-msgstr ""
-"Das Konto ist keine Wallet, und es bestehen Limits für Wallet-Vorgänge, die "
-"möglicherweise nicht erforderliche Aktionen auslösen: %1$s"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:278
+msgid "AML file download started."
+msgstr "Der Download der AML-Akte wurde gestartet."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:446
-msgid ""
-"The account is a wallet and there are wallet operation's limits which are "
-"not limited: %1$s"
-msgstr ""
-"Das Konto ist eine Wallet, und es bestehen Limits für Wallet-Vorgänge, die "
-"nicht begrenzt sind: %1$s"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:284
+#, fuzzy
+#| msgid "Account open"
+msgid "Account notes"
+msgstr "Konto eröffnet"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:454
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:293
#, fuzzy
-msgid ""
-"The AML account is a bank account, but not all account-related operations "
-"are limited ( %1$s)."
+#| msgid "Account assessment could not be loaded"
+msgid "Current account status and notes could not be loaded."
+msgstr "Die Kontobewertung konnte nicht geladen werden"
+
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:302
+msgid "Try again"
msgstr ""
-"Das AML-Konto ist ein Bankkonto, aber nicht alle kontobezogenen Vorgänge "
-"sind begrenzt (%1$s)."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:482
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:269
-msgid "New rules"
-msgstr "Neue Regeln"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:316
+msgid "Account identifiers"
+msgstr "Kontokennungen"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:503
-msgid "Reset rules to current state"
-msgstr "Regeln auf aktuellen Stand zurücksetzen"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:325
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:509
+msgid "Technical identifiers"
+msgstr "Technische Kennungen"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:511
-msgid "Set rules to default"
-msgstr "Regeln auf Standard setzen"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:329
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:513
+msgid "Full payto URI"
+msgstr "Vollständige Payto-URI"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:519
-msgid "Freeze account"
-msgstr "Konto einfrieren"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:331
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:144
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:155
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:173
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:190
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:390
+msgid "Unavailable"
+msgstr "Nicht verfügbar"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:535
-msgid "Behavior on rule expiration"
-msgstr "Verhalten bei Ablauf der Regel"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:332
+msgid "Copy payto URI"
+msgstr "Payto-URI kopieren"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:546
-msgid "Reset measure"
-msgstr "Maßnahme zurücksetzen"
+#. screenid: 113
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:335
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:517
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:188
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:157
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:289
+msgid "Normalized payto hash"
+msgstr "Normalisierter Payto-Hash"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:558
-msgid "Reset expiration"
-msgstr "Ablauf zurücksetzen"
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:337
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:194
+msgid "Copy normalized payto hash"
+msgstr "Normalisierten Payto-Hash kopieren"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:583
-msgctxt "operation type"
-msgid "Withdraw"
-msgstr "Abheben"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:341
+#, fuzzy
+#| msgid "number"
+msgid "File number"
+msgstr "number"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:585
-msgctxt "operation type"
-msgid "Deposit"
-msgstr "Einzahlung"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:343
+#, fuzzy
+#| msgid "Not a number"
+msgid "Copy file number"
+msgstr "Keine Zahl"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:587
-msgctxt "operation type"
-msgid "Merge"
-msgstr "Zusammenführen"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:351
+msgid "Account case views"
+msgstr "Ansichten des Kontofalls"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:589
-msgctxt "operation type"
-msgid "Aggregate"
-msgstr "Aggregieren"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:355
+msgid "Overview"
+msgstr "Übersicht"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:591
-msgctxt "operation type"
-msgid "Balance"
-msgstr "Saldo"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:360
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:565
+msgid "Transfers"
+msgstr "Überweisungen"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:593
-msgctxt "operation type"
-msgid "Refund"
-msgstr "Rückerstattung"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:365
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:67
+msgid "Decision history"
+msgstr "Entscheidungsverlauf"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:595
-msgctxt "operation type"
+#: packages/taler-exchange-aml-webui/src/components/ConfirmationModal.tsx:73
msgid "Close"
msgstr "Schließen"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:597
-msgctxt "operation type"
-msgid "Transaction"
-msgstr "Transaktion"
-
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:612
-msgid "Operation type"
-msgstr "Vorgangstyp"
-
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:633
-msgid "Timeframe"
-msgstr "Zeitraum"
-
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:639
-msgid "Exposed"
-msgstr "Sichtbar"
-
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:640
-msgid "Is this limit communicated to the customer?"
-msgstr "Wird dieses Limit dem Kunden mitgeteilt?"
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/ConfirmationModal.tsx:91
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:207
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:534
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:280
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:469
+msgid "Cancel"
+msgstr "Abbrechen"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:652
-msgid "Escalation measure"
-msgstr "Eskalationsmaßnahme"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:36
+msgid "AML officer enrollment request"
+msgstr "Antrag auf Registrierung eines AML-Sachbearbeiters"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:653
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:37
msgid ""
-"Measures that the customer will need to satisfy to apply for a new threshold."
+"Please enroll this AML officer public key:\n"
+"\n"
+"%1$s"
msgstr ""
-"Maßnahmen, die der Kunde erfüllen muss, um einen neuen Schwellenwert zu "
-"beantragen."
+"Bitte registrieren Sie diesen öffentlichen Schlüssel des AML-"
+"Sachbearbeiters:\n"
+"\n"
+"%1$s"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:658
-msgid "All measures"
-msgstr "Alle Maßnahmen"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:59
+msgid "Officer key awaiting enrollment"
+msgstr "Schlüssel des AML-Sachbearbeiters wartet auf Registrierung"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:659
-msgid "Hint the customer that all measures should be completed"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:62
+msgid ""
+"This browser has created an AML officer key, but the exchange has not "
+"granted it access. Ask the exchange operator or administrator to enroll the "
+"public key below."
msgstr ""
-"Den Kunden darauf hinweisen, dass alle Maßnahmen abgeschlossen werden sollten"
+"Dieser Browser hat einen Schlüssel für einen AML-Sachbearbeiter erstellt, "
+"aber der Exchange hat ihm noch keinen Zugriff gewährt. Bitten Sie den "
+"Betreiber oder Administrator des Exchange, den unten angegebenen "
+"öffentlichen Schlüssel zu registrieren."
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:672
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:157
-msgid "Expiration"
-msgstr "Ablauf"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:70
+msgid "AML officer public key"
+msgstr "Öffentlicher Schlüssel des AML-Sachbearbeiters"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:673
-msgid "Predefined shortcuts"
-msgstr "Vordefinierte Schnellauswahl"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:76
+msgid "Copy AML officer public key"
+msgstr "Öffentlichen Schlüssel des AML-Sachbearbeiters kopieren"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:677
-msgid "In a week"
-msgstr "In einer Woche"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:82
+msgid "After the operator confirms enrollment, retry the access check."
+msgstr ""
+"Nachdem der Betreiber die Registrierung bestätigt hat, prüfen Sie den "
+"Zugriff erneut."
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:92
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:69
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:212
+msgid "Retry access check"
+msgstr "Zugriff erneut prüfen"
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:101
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:188
+msgid "Checking officer access"
+msgstr "Zugriff des AML-Sachbearbeiters wird geprüft"
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:104
+msgid "Last checked at %1$s"
+msgstr "Zuletzt geprüft um %1$s"
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:114
+msgid "Request enrollment"
+msgstr "Registrierung anfordern"
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:121
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:128
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:77
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:85
+msgid "Discard this key"
+msgstr "Diesen Schlüssel verwerfen"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:685
-msgid "In a month"
-msgstr "In einem Monat"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:127
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:84
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:250
+msgid "Confirmation required"
+msgstr "Bestätigung erforderlich"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:693
-msgid "In a year"
-msgstr "In einem Jahr"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:135
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:92
+msgid ""
+"Discarding this key removes the officer session from this browser. You will "
+"need to create a new key to use the AML WebUI again."
+msgstr ""
+"Wenn Sie diesen Schlüssel verwerfen, wird die Sitzung des AML-"
+"Sachbearbeiters aus diesem Browser entfernt. Sie müssen einen neuen "
+"Schlüssel erstellen, um die AML-Weboberfläche erneut zu verwenden."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:701
-msgid "Never"
-msgstr "Nie"
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:41
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:205
+msgid "Failed to check AML officer access."
+msgstr "Der Zugriff des AML-Sachbearbeiters konnte nicht geprüft werden."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:712
-msgid "Expiration date"
-msgstr "Ablaufdatum"
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:45
+msgid ""
+"This officer key cannot authenticate with the exchange. Retry the check or "
+"discard the key and create a new session."
+msgstr ""
+"Dieser Sachbearbeiterschlüssel kann sich nicht beim Exchange "
+"authentifizieren. Wiederholen Sie die Prüfung oder verwerfen Sie den "
+"Schlüssel und erstellen Sie eine neue Sitzung."
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:50
+msgid "The exchange rejected the officer access check."
+msgstr "Der Exchange hat die Zugriffsprüfung des Sachbearbeiters abgelehnt."
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:57
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:211
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:522
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:101
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:612
+msgid "Technical details"
+msgstr "Technische Details"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:713
-msgid "Until when are the new rules active."
-msgstr "Bis wann die neuen Regeln aktiv sind."
-
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:725
-msgid "Measure taken automatically upon expiration of the current decision."
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:69
+msgid "Failed to unlock the session."
msgstr ""
-"Maßnahme, die automatisch bei Ablauf der aktuellen Entscheidung ergriffen "
-"wird."
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:107
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:62
-msgid "Failed to load account information."
-msgstr ""
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:95
+#, fuzzy
+msgid "Session locked"
+msgstr "Konto gesperrt"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:125
-msgid "Failed to load decision history."
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:98
+#, fuzzy
+msgid ""
+"Your session is normally locked anytime you reload. To unlock type your "
+"password again."
msgstr ""
+"Ihr Konto wird normalerweise bei jedem Neuladen gesperrt. Geben Sie zum "
+"Entsperren Ihr Passwort erneut ein."
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:143
-msgid "Failed to load current legitimizations."
-msgstr ""
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:136
+msgid "Unlock"
+msgstr "Entsperren"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:188
-msgid "New decision"
-msgstr "Neue Entscheidung"
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:144
+msgid "Forget session"
+msgstr "Sitzung vergessen"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:196
-msgid "Show transfers"
-msgstr "Überweisungen anzeigen"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:162
+#, fuzzy
+#| msgid "No account properties"
+msgid "Review derived account properties"
+msgstr "Keine Kontoeigenschaften"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:236
-msgid "Failed to download report."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:165
+msgid ""
+"Values may be derived from the selected AML/KYC form. Confirm them against "
+"the case record and change only values that require an officer override."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:241
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:187
#, fuzzy
-msgid "The account has no KYC info."
-msgstr "Das Konto wurde nicht gefunden"
+#| msgid "Reset to default"
+msgid "Reset to derived values"
+msgstr "Auf Standard zurücksetzen"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:245
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:183
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:195
-msgid "Session not found. Contact the administrator."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:192
+msgid "Invalid custom properties"
+msgstr "Ungültige benutzerdefinierte Eigenschaften"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:247
-msgid "The session is disabled. Contact the administrator."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:193
+msgid ""
+"Custom property names and values must be non-empty and names must be unique "
+"and different from built-in properties."
msgstr ""
+"Namen und Werte benutzerdefinierter Eigenschaften dürfen nicht leer sein; "
+"die Namen müssen eindeutig sein und sich von integrierten Eigenschaften "
+"unterscheiden."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:216
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:466
+msgid "Properties"
+msgstr "Eigenschaften"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:249
-msgid "The server doesn't support PDF download. Contact the administrator."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:217
+msgid "Built-in property names are preserved when the decision is submitted."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:260
-msgid "Case history for selected account"
-msgstr "Fallverlauf für ausgewähltes Konto"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:223
+msgid "Custom properties"
+msgstr "Benutzerdefinierte Eigenschaften"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:224
+msgid "Add more properties that are not listed above."
+msgstr "Weitere Eigenschaften hinzufügen, die oben nicht aufgeführt sind."
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:229
+msgid "New properties"
+msgstr "Neue Eigenschaften"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:265
-msgid "ID:"
-msgstr "ID:"
+#. screenid: 123
+#. screenid: 108
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:234
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:73
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:171
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:261
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:204
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:626
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1104
+msgid "Name"
+msgstr "Name"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:271
-msgid "Payto:"
-msgstr "Payto:"
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:240
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:720
+msgid "Value"
+msgstr "Wert"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:282
-msgid "Export as PDF"
-msgstr "Als PDF exportieren"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:262
+msgid "Current note on the GwG file"
+msgstr "Aktuelle Notiz zur GwG-Akte"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:298
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:279
-msgid "Export completed"
-msgstr "Export abgeschlossen"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:267
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:63
+msgid "Customer name or internal alias."
+msgstr "Kundenname oder interner Alias."
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:301
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:282
-msgid "Click here to save the file in your computer."
-msgstr "Klicken Sie hier, um die Datei auf Ihrem Computer zu speichern."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:272
+msgid "Is the account active for deposit and payments?"
+msgstr "Ist das Konto für Einzahlungen und Zahlungen aktiv?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:310
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:411
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:208
-msgid "Under investigation"
-msgstr "In Untersuchung"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:277
+msgid "Is the account idle?"
+msgstr "Ist das Konto inaktiv?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:311
-msgid ""
-"This account requires a manual review and is waiting for a decision to be "
-"made."
-msgstr ""
-"Dieses Konto erfordert eine manuelle Überprüfung und wartet auf eine "
-"Entscheidung."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:278
+msgid "No operation for a period of time"
+msgstr "Keine Vorgänge über einen bestimmten Zeitraum"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:322
-msgid "Collected information"
-msgstr "Erfasste Informationen"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:283
+msgid "Does account belong to a domestic PEP?"
+msgstr "Gehört das Konto zu einer inländischen PEP?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:325
-msgid "Every attribute collection event (via form upload or KYC provider)."
-msgstr ""
-"Jedes Ereignis der Attributerfassung (über Formular-Upload oder KYC-"
-"Anbieter)."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:288
+msgid "Does account belong to a foreign PEP?"
+msgstr "Gehört das Konto zu einer ausländischen PEP?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:333
-msgid "No collected attributes for this account."
-msgstr "Keine erfassten Attribute für dieses Konto."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:293
+msgid "Does account belong to an international-organization PEP?"
+msgstr "Gehört das Konto zu einer PEP einer internationalen Organisation?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:347
-msgid "Current account properties"
-msgstr "Aktuelle Kontoeigenschaften"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:298
+msgid "Does account belong to a high risk customer?"
+msgstr "Gehört das Konto zu einem Hochrisikokunden?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:354
-msgid "No active decision found"
-msgstr "Keine aktive Entscheidung gefunden"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:303
+msgid "Does account belong to a person from a high risk country?"
+msgstr "Gehört das Konto zu einer Person aus einem Hochrisikoland?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:355
-msgid ""
-"There is no decision for this account yet. The account is limited by the "
-"default rules."
-msgstr ""
-"Für dieses Konto liegt noch keine Entscheidung vor. Das Konto unterliegt den "
-"Standardregeln."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:308
+msgid "The MROS reporting state for the account."
+msgstr "Der MROS-Meldestatus für das Konto."
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:384
-msgid "Previous AML decisions"
-msgstr "Frühere AML-Entscheidungen"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:313
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:307
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:175
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:199
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:497
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:630
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:653
+msgid "None"
+msgstr "Keine"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:403
-msgid "No AML history found"
-msgstr "Kein AML-Verlauf gefunden"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:317
+msgid "Pending investigation"
+msgstr "Untersuchung ausstehend"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:409
-msgid "Current active measures"
-msgstr "Aktuell aktive Maßnahmen"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:321
+msgid "Investigated without suspicion"
+msgstr "Untersucht, kein Verdacht"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:537
-msgid "Now"
-msgstr "Jetzt"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:325
+msgid "Reported simple suspicion"
+msgstr "Einfacher Verdacht gemeldet"
-#. screenid: 112
-#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:43
-#, fuzzy
-msgid "Session public key"
-msgstr "Öffentlicher Schlüssel"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:329
+msgid "Reported substantiated suspicion"
+msgstr "Begründeter Verdacht gemeldet"
-#. screenid: 112
-#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:59
-#, fuzzy
-msgid "Request session activation"
-msgstr "Kontoaktivierung anfordern"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:336
+msgid "Informal reason why the AML investigation was triggered"
+msgstr "Informeller Grund für die Auslösung der AML-Untersuchung"
-#. screenid: 112
-#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:70
-msgid "Lock session"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:341
+msgid "Identifies the sanction list entry that the account matched against"
msgstr ""
+"Identifiziert den Sanktionslisteneintrag, mit dem das Konto übereinstimmte"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:73
-msgid "Failed to load accounts"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:343
+msgid "Best match, does not mean it was a good match."
msgstr ""
+"Beste Übereinstimmung, bedeutet nicht, dass es eine gute Übereinstimmung war."
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:83
-#, fuzzy
-msgid "Failed to load the accounts"
-msgstr "Fallverlauf für ausgewähltes Konto"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:347
+msgid "Score for how good the sanction list match was"
+msgstr "Bewertung, wie gut die Übereinstimmung mit der Sanktionsliste war"
-#. screenid: 111
-#. screenid: 110
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:88
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:168
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:76
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:128
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:66
-#, fuzzy
-msgid ""
-"This session signature is invalid, contact administrator or create a new one."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:349
+msgid "Integer score from 0 (no match) to 1,000,000,000 (best match)."
msgstr ""
-"Diese Kontosignatur ist ungültig. Wenden Sie sich an den Administrator oder "
-"erstellen Sie eine neue."
-#. screenid: 111
-#. screenid: 110
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:95
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:175
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:83
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:135
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:73
-#, fuzzy
-msgid ""
-"The designated AML session is not known, contact administrator or create a "
-"new one."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:353
+msgid "Score for how much supporting data we had for the sanction list match"
msgstr ""
-"Das vorgesehene AML-Konto ist nicht bekannt. Wenden Sie sich an den "
-"Administrator oder erstellen Sie ein neues."
+"Bewertung, wie viele Belegdaten für die Übereinstimmung mit der "
+"Sanktionsliste vorlagen"
-#. screenid: 111
-#. screenid: 110
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:102
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:182
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:90
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:142
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:80
-#, fuzzy
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:355
msgid ""
-"The designated AML session is not enabled, contact administrator or create a "
-"new one."
+"Integer score from 0 (no supporting data) to 1,000,000,000 (highest "
+"confidence)."
msgstr ""
-"Das vorgesehene AML-Konto ist nicht aktiviert. Wenden Sie sich an den "
-"Administrator oder erstellen Sie ein neues."
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:122
-msgid "High risk accounts. Only with custom rules."
-msgstr "Hochrisikokonten. Nur mit benutzerdefinierten Regeln."
-
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:123
-msgid "Account with custom rules."
-msgstr "Konto mit benutzerdefinierten Regeln."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:359
+msgid ""
+"Suppress flagging this account when it creates a hit on a sanctions list, "
+"this is a false-positive"
+msgstr ""
+"Markierung dieses Kontos unterdrücken, wenn es einen Treffer auf einer "
+"Sanktionsliste erzeugt; dies ist ein Fehlalarm"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:125
-msgid "High risk accounts"
-msgstr "Hochrisikokonten"
+#: packages/taler-exchange-aml-webui/src/components/DecisionProperties.tsx:46
+#, fuzzy
+#| msgid "No account properties"
+msgid "No account properties were recorded."
+msgstr "Keine Kontoeigenschaften"
+
+#: packages/taler-exchange-aml-webui/src/components/DecisionProperties.tsx:91
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:317
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:509
+msgid "Yes"
+msgstr "Ja"
+
+#: packages/taler-exchange-aml-webui/src/components/DecisionProperties.tsx:91
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:317
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:509
+msgid "No"
+msgstr "Nein"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:126
-msgid "All known accounts."
-msgstr "Alle bekannten Konten."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:59
+msgid "There are no rules for operations"
+msgstr "Es gibt keine Regeln für Vorgänge"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:130
-msgid "High risk accounts under investigation. Only with custom rules."
-msgstr "Hochrisikokonten in Untersuchung. Nur mit benutzerdefinierten Regeln."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:62
+msgid "This means that no operation has any limit."
+msgstr "Das bedeutet, dass kein Vorgang begrenzt ist."
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:131
-msgid "Accounts under investigation. Only with custom rules."
-msgstr "Konten in Untersuchung. Nur mit benutzerdefinierten Regeln."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:90
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:312
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:500
+msgid "Operation"
+msgstr "Vorgang"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:133
-msgid "High risk accounts under investigation."
-msgstr "Hochrisikokonten in Untersuchung."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:96
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:695
+msgid "Threshold"
+msgstr "Schwellenwert"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:134
-msgid "Accounts under investigation."
-msgstr "Konten in Untersuchung."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:102
+msgid "Escalation"
+msgstr "Eskalation"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:137
-msgid "High risk accounts without investigation. Only with custom rules."
-msgstr ""
-"Hochrisikokonten ohne Untersuchung. Nur mit benutzerdefinierten Regeln."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:108
+msgid "Visibility"
+msgstr "Sichtbarkeit"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:138
-msgid "Accounts without investigation. Only with custom rules."
-msgstr "Konten ohne Untersuchung. Nur mit benutzerdefinierten Regeln."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:114
+msgid "Priority"
+msgstr "Priorität"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:140
-msgid "High risk accounts without investigation."
-msgstr "Hochrisikokonten ohne Untersuchung."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:121
+msgid "Actions"
+msgstr "Aktionen"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:141
-msgid "Accounts without investigation."
-msgstr "Konten ohne Untersuchung."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:142
+msgctxt "threshold"
+msgid "%1$s every %2$s"
+msgstr "%1$s alle %2$s"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:174
-msgid "Failed to download"
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:161
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:725
+msgid "Block operation"
+msgstr "Vorgang sperren"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:177
-#, fuzzy
-msgid "There are no accounts in the resultset."
-msgstr "Für dieses Konto gibt es noch keine Regeln."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:163
+msgid "All required:"
+msgstr "Alle erforderlich:"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:179
-msgid "The format requested is not acceptable from the service provider."
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:165
+msgid "Any one:"
+msgstr "Eine beliebige:"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:181
-msgid "Authorization denied for this session."
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:182
+msgid "Customer-visible"
+msgstr "Für Kunden sichtbar"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:185
-msgid "The session is disabled. Contact the administrator"
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:184
+msgid "Internal"
+msgstr "Intern"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:240
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:368
-msgid "Accounts"
-msgstr "Konten"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:197
+msgid "Move %1$s rule up"
+msgstr "%1$s-Regel nach oben verschieben"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:247
-msgid "Export as file"
-msgstr "Als Datei exportieren"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:206
+msgid "Move %1$s rule down"
+msgstr "%1$s-Regel nach unten verschieben"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:318
-msgid "No results"
-msgstr "Keine Ergebnisse"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:217
+msgid "Edit %1$s rule"
+msgstr "%1$s-Regel bearbeiten"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:329
-msgid "#"
-msgstr "#"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:240
+msgid "Remove %1$s rule"
+msgstr "%1$s-Regel entfernen"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:335
-msgid "Account Identification"
-msgstr "Kontokennung"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:282
+msgctxt "operation type"
+msgid "Withdraw"
+msgstr "Abheben"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:341
-msgid "Open time"
-msgstr "Eröffnungszeit"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:284
+msgctxt "operation type"
+msgid "Deposit"
+msgstr "Einzahlung"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:347
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:243
-msgid "Status"
-msgstr "Status"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:286
+msgctxt "operation type"
+msgid "Merge"
+msgstr "Zusammenführen"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:365
-msgid "From %1$s %2$s To %3$s"
-msgstr "Von %1$s %2$s Bis %3$s"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:288
+msgctxt "operation type"
+msgid "Aggregate"
+msgstr "Aggregieren"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:371
-msgid "Since %1$s"
-msgstr "Seit %1$s"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:290
+msgctxt "operation type"
+msgid "Balance"
+msgstr "Saldo"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:374
-msgid "Not opened"
-msgstr "Nicht eröffnet"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:292
+msgctxt "operation type"
+msgid "Refund"
+msgstr "Rückerstattung"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:419
-msgid "High risk"
-msgstr "Hohes Risiko"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:294
+msgctxt "operation type"
+msgid "Close"
+msgstr "Schließen"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:427
-msgid "With custom rules"
-msgstr "Mit benutzerdefinierten Regeln"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:296
+msgctxt "operation type"
+msgid "Transaction"
+msgstr "Transaktion"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:642
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:673
-msgid "Invalid account"
-msgstr "Ungültiges Konto"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:83
+#, fuzzy
+#| msgid "Decision date"
+msgid "Decision provenance"
+msgstr "Entscheidungsdatum"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:657
-msgid "Search by ID"
-msgstr "Nach ID suchen"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:85
+#, fuzzy
+#| msgid "Decision date"
+msgid "Decision made by"
+msgstr "Entscheidungsdatum"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:687
-msgid "Under investigation: "
-msgstr "In Untersuchung: "
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:88
+#, fuzzy
+#| msgid "AML officer public key"
+msgid "AML officer (name unavailable)"
+msgstr "Öffentlicher Schlüssel des AML-Sachbearbeiters"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:696
-msgid "High risk:"
-msgstr "Hochrisiko:"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:89
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:369
+msgid "Automated outcome"
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:705
-msgid "Custom rules:"
-msgstr "Benutzerdefinierte Regeln:"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:91
+msgid "Resulting case disposition"
+msgstr ""
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:47
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:366
-msgid "Dashboard"
-msgstr "Dashboard"
-
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:88
-msgid "Failed to load TOPS statistics."
-msgstr ""
-
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:99
-msgid "Statistics"
-msgstr "Statistiken"
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:94
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:246
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:105
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:132
+msgid "Not under investigation"
+msgstr "Nicht in Untersuchung"
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:99
+#, fuzzy
+#| msgid "Justification"
+msgid "Justification:"
+msgstr "Begründung"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:187
-msgid "Accounts open"
-msgstr "Eröffnete Konten"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:101
+msgid "No justification was recorded."
+msgstr "Es wurde keine Begründung erfasst."
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:190
-msgid "New files last year"
-msgstr "Neue Akten im letzten Jahr"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:112
+#, fuzzy
+#| msgid "System information"
+msgid "View submitted customer information"
+msgstr "Systeminformation"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:193
-msgid "Closed files last year"
-msgstr "Geschlossene Akten im letzten Jahr"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:120
+#, fuzzy
+#| msgid "Instant measures"
+msgid "Immediate measures requested"
+msgstr "Sofortmaßnahmen"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:196
-msgid "MROS substantiated"
-msgstr "MROS begründet"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:123
+msgid "This decision did not request an immediate measure."
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:199
-msgid "MROS simple"
-msgstr "MROS einfach"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:131
+#, fuzzy
+#| msgid "All listed measures must be completed."
+msgid "All listed measures were requested (AND)."
+msgstr "Alle aufgeführten Maßnahmen müssen abgeschlossen werden."
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:202
-msgid "High risk files"
-msgstr "Hochrisiko-Akten"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:132
+#, fuzzy
+#| msgid "Any one listed measure may be completed."
+msgid "Any listed measure may satisfy the request (OR)."
+msgstr "Eine beliebige der aufgeführten Maßnahmen kann abgeschlossen werden."
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:205
-msgid "PEP files"
-msgstr "PEP-Akten"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:151
+msgid "Operation rules"
+msgstr "Vorgangsregeln"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:267
-msgid "Number of accounts that are opened"
-msgstr "Anzahl der eröffneten Konten"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:156
+msgid "No operation-specific rules were stored."
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:270
-msgid "Number of new GwG files in the last year"
-msgstr "Anzahl neuer GwG-Akten im letzten Jahr"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:163
+#, fuzzy
+#| msgid "Select transaction type"
+msgid "Policy transition"
+msgstr "Transaktionstyp auswählen"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:273
-msgid "Number of GwG files closed in the last year"
-msgstr "Anzahl der im letzten Jahr geschlossenen GwG-Akten"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:165
+msgid "Policy expires"
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:276
-msgid "Number of MROS reports based on Art 9 Abs. 1 GwG (per year)"
-msgstr "Anzahl der MROS-Meldungen gemäß Art. 9 Abs. 1 GwG (pro Jahr)"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:173
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:796
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:362
+msgid "Successor measure"
+msgstr "Nachfolgemaßnahme"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:279
-msgid "Number of MROS reports based on Art 305ter Abs. 2 StGB (per year)"
-msgstr "Anzahl der MROS-Meldungen gemäß Art. 305ter Abs. 2 StGB (pro Jahr)"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:174
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:479
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:163
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:365
+msgid "Exchange defaults"
+msgstr "Exchange-Standardregeln"
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:179
+#, fuzzy
+#| msgid "Custom measures"
+msgid "Custom measure definitions"
+msgstr "Benutzerdefinierte Maßnahmen"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:282
-msgid "Number of GwG files of high-risk customers"
-msgstr "Anzahl der GwG-Akten von Hochrisikokunden"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:182
+#, fuzzy
+#| msgid "No active measure has been selected."
+msgid "No custom measures were stored."
+msgstr "Es wurde keine aktive Maßnahme ausgewählt."
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:285
-msgid "Number of GwG files managed with “increased risk” due to PEP status"
-msgstr "Anzahl der GwG-Akten mit „erhöhtem Risiko“ aufgrund des PEP-Status"
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:202
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:278
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:128
+msgid "Account properties"
+msgstr "Kontoeigenschaften"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:288
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:214
#, fuzzy
-msgid "Number of customers with open proceeding."
-msgstr "Anzahl der eröffneten Konten"
+#| msgid "Decision date"
+msgid "Decision row"
+msgstr "Entscheidungsdatum"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:343
-msgid "previous"
-msgstr "vorherig"
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:217
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:174
+msgid "Officer public key"
+msgstr "Öffentlicher Schlüssel des Sachbearbeiters"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:386
-msgid "Decreased by"
-msgstr "Verringert um"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:219
+msgid "Not applicable"
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:390
-msgid "Increased by"
-msgstr "Erhöht um"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:277
+#, fuzzy
+#| msgid "System information"
+msgid "Stored custom definition"
+msgstr "Systeminformation"
-#. screenid: 108
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:115
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:217
-msgid "Events"
-msgstr "Ereignisse"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:284
+msgid ""
+"Current measure metadata is still loading; the stored machine name is shown."
+msgstr ""
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:116
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:286
msgid ""
-"The events will be triggered only after the decision has been confirmed."
+"The current measure configuration could not be loaded; the stored machine "
+"name is shown."
msgstr ""
-"Die Ereignisse werden erst ausgelöst, nachdem die Entscheidung bestätigt "
-"wurde."
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:121
-msgid "Calculated"
-msgstr "Berechnet"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:287
+msgid ""
+"No stored or currently configured definition is available for this reference."
+msgstr ""
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:122
-msgid "Events based on properties and new attributes that should be triggered"
+#. screenid: 123
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:291
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:80
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:178
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:659
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:938
+msgid "Check"
+msgstr "Überprüfen"
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:295
+msgid "Built-in check that requires no customer interaction."
msgstr ""
-"Ereignisse, die auf Grundlage von Eigenschaften und neuen Attributen "
-"ausgelöst werden sollen"
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:134
-msgid "Others"
-msgstr "Sonstige"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:296
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:304
+#, fuzzy
+#| msgid "Attributes unavailable"
+msgid "Description unavailable"
+msgstr "Attribute nicht verfügbar"
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:135
-msgid "Events that can be triggered manually"
-msgstr "Ereignisse, die manuell ausgelöst werden können"
+#. screenid: 123
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:299
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:86
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:268
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:639
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:891
+msgid "Program"
+msgstr "Programm"
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:147
-msgid "Custom list"
-msgstr "Benutzerdefinierte Liste"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:316
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:508
+msgid "Voluntary"
+msgstr ""
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:148
-msgid "Events without built-in support."
-msgstr "Ereignisse ohne integrierte Unterstützung."
+#. screenid: 123
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:320
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:92
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:184
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:280
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:682
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:907
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:644
+msgid "Context"
+msgstr "Kontext"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:132
-msgid "Complete the form"
-msgstr "Formular ausfüllen"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:349
+msgid "Decision date"
+msgstr "Entscheidungsdatum"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:135
-msgid "These measures will ask the customer for information."
-msgstr "Diese Maßnahmen fordern den Kunden zur Angabe von Informationen auf."
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:357
+msgid "Expired"
+msgstr "Abgelaufen"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:153
-msgid "change form"
-msgstr "Formular ändern"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:357
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:419
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:354
+msgid "Expires"
+msgstr "Läuft ab"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:158
-msgid "Expiration date of the information filled in this form."
-msgstr "Ablaufdatum der in diesem Formular eingegebenen Informationen."
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:362
+#, fuzzy
+#| msgid "Decision date"
+msgid "Decision status"
+msgstr "Entscheidungsdatum"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:217
-msgid "Include new information"
-msgstr "Neue Informationen einbeziehen"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:363
+#, fuzzy
+#| msgid "Send decision"
+msgid "Current"
+msgstr "Entscheidung senden"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:218
-msgid ""
-"Select a form to submit new information about the customer or continue to "
-"the next step"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:363
+msgid "Historical"
msgstr ""
-"Wählen Sie ein Formular aus, um neue Informationen über den Kunden zu "
-"übermitteln, oder fahren Sie mit dem nächsten Schritt fort"
-
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:223
-msgid "Form:"
-msgstr "Formular:"
-#. screenid: 106
-#. screenid: 113
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:81
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:227
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:237
-msgid "Justification"
-msgstr "Begründung"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:365
+msgid "Made by"
+msgstr ""
-#. screenid: 106
-#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:86
-msgid "Keep investigation?"
-msgstr "Untersuchung beibehalten?"
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:368
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:272
+#, fuzzy
+#| msgid "AML officer public key"
+msgid "AML officer"
+msgstr "Öffentlicher Schlüssel des AML-Sachbearbeiters"
-#. screenid: 106
-#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:91
-msgid "Account holder"
-msgstr "Kontoinhaber"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:44
+msgid "Forms"
+msgstr "Formulare"
-#. screenid: 106
-#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:93
-msgid "Full name of the account holder"
-msgstr "Vollständiger Name des Kontoinhabers"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:47
+msgid "Measures used to gather information about the customer."
+msgstr "Maßnahmen zur Erfassung von Informationen über den Kunden."
-#. screenid: 122
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:90
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:394
-msgid "loading..."
-msgstr "wird geladen..."
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:62
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:160
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:250
+msgid "Select"
+msgstr "Auswählen"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:239
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:421
-msgid "Update"
-msgstr "Aktualisieren"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:107
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:199
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:295
+msgid "Modify"
+msgstr "Ändern"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:246
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:428
-msgid "Remove"
-msgstr "Entfernen"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:141
+#, fuzzy
+#| msgid "System information"
+msgid "Information"
+msgstr "Systeminformation"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:473
-msgid "Configure verification type: %1$s"
-msgstr "Verifizierungstyp konfigurieren: %1$s"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:144
+#, fuzzy
+#| msgid "KYC information filed by the customer or an AML officer."
+msgid "Shows information to the customer without running an AML program."
+msgstr ""
+"Vom Kunden oder einem AML-Sachbearbeiter eingereichte KYC-Informationen."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:484
-msgid "Show complete form"
-msgstr "Vollständiges Formular anzeigen"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:232
+msgid "Instant measures"
+msgstr "Sofortmaßnahmen"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:505
-msgid "Configure measure"
-msgstr "Maßnahme konfigurieren"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:235
+msgid "Triggered immediately without customer interaction."
+msgstr "Wird sofort ohne Kundeninteraktion ausgelöst."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:515
-msgid "Show as verification"
-msgstr "Als Verifizierung anzeigen"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:274
+msgid "Input requirement"
+msgstr "Eingabeanforderung"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:557
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:998
-msgid "There is already a measure with that name"
-msgstr "Es gibt bereits eine Maßnahme mit diesem Namen"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:56
+msgid "Started"
+msgstr "Begonnen"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:571
-msgid "Only required when no check is specified"
-msgstr "Nur erforderlich, wenn keine Prüfung angegeben ist"
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:64
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:301
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:140
+msgid "Status"
+msgstr "Status"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:575
-msgid "Missing check or program"
-msgstr "Prüfung oder Programm fehlt"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:76
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:447
+msgid "Forbidden"
+msgstr "Verboten"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:585
-msgid "Without a check the program will run automatically"
-msgstr "Ohne Prüfung wird das Programm automatisch ausgeführt"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:78
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:443
+msgid "Completed"
+msgstr "Abgeschlossen"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:614
-msgid "Field name"
-msgstr "Feldname"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:79
+msgid "Waiting for customer"
+msgstr "Wartet auf den Kunden"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:619
-msgid "Type"
-msgstr "Typ"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:92
+msgid "The operation is categorically forbidden by this requirement."
+msgstr "Der Vorgang ist aufgrund dieser Anforderung grundsätzlich verboten."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:623
-msgid "string"
-msgstr "string"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:100
+msgid "All listed measures must be completed."
+msgstr "Alle aufgeführten Maßnahmen müssen abgeschlossen werden."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:627
-msgid "number"
-msgstr "number"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:104
+msgid "Any one listed measure may be completed."
+msgstr "Eine beliebige der aufgeführten Maßnahmen kann abgeschlossen werden."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:631
-msgid "boolean"
-msgstr "boolean"
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:24
+msgid "Expiration shortcuts"
+msgstr "Schnellauswahl für den Ablauf"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:635
-msgid "json"
-msgstr "json"
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:29
+msgid "In a week"
+msgstr "In einer Woche"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:644
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:197
-msgid "Value"
-msgstr "Wert"
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:30
+msgid "In a month"
+msgstr "In einem Monat"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:663
-msgid "There are unsatisfied inputs: %1$s"
-msgstr "Es gibt nicht erfüllte Eingaben: %1$s"
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:31
+msgid "In a year"
+msgstr "In einem Jahr"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:674
-msgid "There are missing inputs: %1$s"
-msgstr "Es fehlen Eingaben: %1$s"
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:50
+msgid "Never"
+msgstr "Nie"
#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:694
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:711
-msgid "There are missing requirements: %1$s"
-msgstr "Es fehlen Anforderungen: %1$s"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:115
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:98
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:63
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:72
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:209
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:218
+msgid "Failed to load available measures."
+msgstr "Die verfügbaren Maßnahmen konnten nicht geladen werden."
#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:751
-msgid "Can't be empty"
-msgstr "Darf nicht leer sein"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:120
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:112
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:77
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:223
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:294
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:480
+msgid "The officer session is invalid."
+msgstr "Die Sitzung des AML-Sachbearbeiters ist ungültig."
#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:755
-msgid "It should be a number"
-msgstr "Es sollte eine Zahl sein"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:124
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:116
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:81
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:227
+msgid "The measures endpoint was not found."
+msgstr "Der Endpunkt für Maßnahmen wurde nicht gefunden."
#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:757
-msgid "Not a number"
-msgstr "Keine Zahl"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:130
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:122
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:87
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:233
+msgid "The officer session is disabled."
+msgstr "Die Sitzung des AML-Sachbearbeiters ist deaktiviert."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:759
-msgid "It should be finite"
-msgstr "Es sollte endlich sein"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:195
+msgid "Edit proposed rule"
+msgstr "Vorgeschlagene Regel bearbeiten"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:761
-msgid "It should be a safe integer"
-msgstr "Es sollte eine sichere Ganzzahl sein"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:197
+msgid "Add proposed rule"
+msgstr "Vorgeschlagene Regel hinzufügen"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:766
-msgid "It should be either \"true\" or \"false\""
-msgstr "Es sollte entweder \"true\" oder \"false\" sein"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:216
+msgid "Save rule"
+msgstr "Regel speichern"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:771
-msgid "Couldn't parse as json string: %1$s"
-msgstr "Konnte nicht als JSON-String geparst werden: %1$s"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:218
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:372
+msgid "Add rule"
+msgstr "Regel hinzufügen"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:797
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:940
-msgid "Description"
-msgstr "Beschreibung"
-
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:813
-msgid "Inputs"
-msgstr "Eingaben"
-
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:849
-msgid "Output"
-msgstr "Ausgabe"
-
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:859
-msgid "Requires"
-msgstr "Erfordert"
-
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:867
-msgid "Fallback"
-msgstr "Fallback"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:356
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:348
+#, fuzzy
+#| msgid "Properties"
+msgid "Proposed rules"
+msgstr "Eigenschaften"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:993
-msgid "Name of the verification measure"
-msgstr "Name der Verifizierungsmaßnahme"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:359
+msgid ""
+"This complete rule set replaces the currently applied rules and exchange "
+"defaults until it expires. Higher rows take precedence."
+msgstr ""
+"Dieser vollständige Regelsatz ersetzt bis zu seinem Ablauf die derzeit "
+"angewendeten Regeln und die Standardregeln der Börse. Weiter oben stehende "
+"Regeln haben Vorrang."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1005
-msgid "Read only"
-msgstr "Nur lesen"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:390
+msgid "Rules for another account type"
+msgstr "Regeln für einen anderen Kontotyp"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1006
-msgid "Prevent the customer from changing the address"
-msgstr "Verhindert, dass der Kunde die Adresse ändert"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:393
+msgid "These operations do not apply to this account type: %1$s."
+msgstr "Diese Vorgänge gelten nicht für diesen Kontotyp: %1$s."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:256
-msgid "Configure verification measure: \"%1$s\""
-msgstr "Verifizierungsmaßnahme konfigurieren: \"%1$s\""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:400
+msgid "Operations without limits"
+msgstr "Vorgänge ohne Limits"
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:294
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:115
-msgid "Add custom measure"
-msgstr "Benutzerdefinierte Maßnahme hinzufügen"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:401
+msgid "No proposed rule limits these operations: %1$s."
+msgstr "Keine vorgeschlagene Regel begrenzt diese Vorgänge: %1$s."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:300
-msgid "Custom measures"
-msgstr "Benutzerdefinierte Maßnahmen"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:408
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:336
+msgid "Invalid proposed rules"
+msgstr "Ungültige vorgeschlagene Regeln"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:329
-msgid "Server measures"
-msgstr "Server-Maßnahmen"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:409
+msgid ""
+"Edit the highlighted rule set before continuing. Hard blocks cannot be "
+"combined with measures, and Balance and Refund rules must use an instant "
+"timeframe."
+msgstr ""
+"Bearbeiten Sie den hervorgehobenen Regelsatz, bevor Sie fortfahren. Harte "
+"Sperren können nicht mit Maßnahmen kombiniert werden, und Regeln für Saldo "
+"und Rückerstattung müssen einen sofortigen Zeitraum verwenden."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:426
-msgid "New measures"
-msgstr "Neue Maßnahmen"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:432
+msgid "Remove proposed rule?"
+msgstr "Vorgeschlagene Regel entfernen?"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:427
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:434
msgid ""
-"Measures that are available/executed directly after the decision is "
-"confirmed."
+"This is the final rule. Removing it leaves every applicable operation "
+"unlimited."
msgstr ""
-"Maßnahmen, die direkt nach Bestätigung der Entscheidung verfügbar sind/"
-"ausgeführt werden."
-
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:154
-msgid "Reset to default"
-msgstr "Auf Standard zurücksetzen"
+"Dies ist die letzte Regel. Wenn Sie sie entfernen, bleiben alle zutreffenden "
+"Vorgänge unbegrenzt."
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:175
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:234
-msgid "Properties"
-msgstr "Eigenschaften"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:439
+msgid "The rule will be removed from the proposed set."
+msgstr "Die Regel wird aus dem vorgeschlagenen Satz entfernt."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:181
-msgid "Custom properties"
-msgstr "Benutzerdefinierte Eigenschaften"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:449
+msgid "Keep rule"
+msgstr "Regel behalten"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:182
-msgid "Add more properties that are not listed above."
-msgstr "Weitere Eigenschaften hinzufügen, die oben nicht aufgeführt sind."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:459
+msgid "Remove rule"
+msgstr "Regel entfernen"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:187
-msgid "New properties"
-msgstr "Neue Eigenschaften"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:467
+msgid "Replace proposed rules"
+msgstr "Vorgeschlagene Regeln ersetzen"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:218
-msgid "Current note on the GwG file"
-msgstr "Aktuelle Notiz zur GwG-Akte"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:470
+msgid "Preview a complete replacement before applying it."
+msgstr ""
+"Zeigen Sie vor der Anwendung eine Vorschau des vollständigen Ersatzes an."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:223
-msgid "Customer name or internal alias."
-msgstr "Kundenname oder interner Alias."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:476
+msgid "Currently applied"
+msgstr "Derzeit angewendet"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:228
-msgid "Is the account active for deposit and payments?"
-msgstr "Ist das Konto für Einzahlungen und Zahlungen aktiv?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:486
+msgid "E-commerce"
+msgstr "E-Commerce"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:233
-msgid "Is the account idle?"
-msgstr "Ist das Konto inaktiv?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:489
+msgid "Point of Sale"
+msgstr "Point-of-Sale"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:234
-msgid "No operation for a period of time"
-msgstr "Keine Vorgänge über einen bestimmten Zeitraum"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:496
+msgid "Basic plan"
+msgstr "Basisplan"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:239
-msgid "Does account belong to a domestic PEP?"
-msgstr "Gehört das Konto zu einer inländischen PEP?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:501
+msgid "Premium"
+msgstr "Premium"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:244
-msgid "Does account belong to a foreign PEP?"
-msgstr "Gehört das Konto zu einer ausländischen PEP?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:510
+msgid "Freeze account"
+msgstr "Konto einfrieren"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:249
-msgid "Does account belong to an international-organization PEP?"
-msgstr "Gehört das Konto zu einer PEP einer internationalen Organisation?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:518
+msgid "Replacement preview"
+msgstr "Vorschau des Ersatzes"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:254
-msgid "Does account belong to a high risk customer?"
-msgstr "Gehört das Konto zu einem Hochrisikokunden?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:521
+msgid "Confirm account freeze"
+msgstr "Kontosperrung bestätigen"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:259
-msgid "Does account belong to a person from a high risk country?"
-msgstr "Gehört das Konto zu einer Person aus einem Hochrisikoland?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:522
+msgid "Every applicable operation will receive a zero hard limit."
+msgstr "Jeder zutreffende Vorgang erhält ein hartes Limit von null."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:264
-msgid "The MROS reporting state for the account."
-msgstr "Der MROS-Meldestatus für das Konto."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:548
+msgid "Apply replacement"
+msgstr "Ersatz anwenden"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:269
-msgid "None"
-msgstr "Keine"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:556
+#, fuzzy
+#| msgid "Reset expiration"
+msgid "Rule expiration"
+msgstr "Ablauf zurücksetzen"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:273
-msgid "Pending investigation"
-msgstr "Untersuchung ausstehend"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:559
+msgid "Choose how long the proposed rules apply and what happens afterwards."
+msgstr ""
+"Legen Sie fest, wie lange die vorgeschlagenen Regeln gelten und was danach "
+"geschieht."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:277
-msgid "Investigated without suspicion"
-msgstr "Untersucht, kein Verdacht"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:578
+msgid "The proposed rules never expire, so no successor action will run."
+msgstr ""
+"Die vorgeschlagenen Regeln laufen nie ab, daher wird keine Nachfolgeaktion "
+"ausgeführt."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:281
-msgid "Reported simple suspicion"
-msgstr "Einfacher Verdacht gemeldet"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:598
+msgid "Restore currently applied expiration"
+msgstr "Derzeit angewendeten Ablauf wiederherstellen"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:285
-msgid "Reported substantiated suspicion"
-msgstr "Begründeter Verdacht gemeldet"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:682
+msgid "Operation type"
+msgstr "Vorgangstyp"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:292
-msgid "Informal reason why the AML investigation was triggered"
-msgstr "Informeller Grund für die Auslösung der AML-Untersuchung"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:704
+msgid "Timeframe"
+msgstr "Zeitraum"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:297
-msgid "Identifies the sanction list entry that the account matched against"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:705
+msgid ""
+"Use Y, M, D, h, m or s after each number. Forever accumulates over the "
+"account's full history."
msgstr ""
-"Identifiziert den Sanktionslisteneintrag, mit dem das Konto übereinstimmte"
+"Verwenden Sie Y, M, D, h, m oder s nach jeder Zahl. „Für immer“ summiert "
+"über den gesamten Verlauf des Kontos."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:299
-msgid "Best match, does not mean it was a good match."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:709
+msgid "Instant timeframe"
+msgstr "Sofortiger Zeitraum"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:710
+msgid ""
+"Balance and Refund limits apply to one balance or transaction, so their "
+"timeframe is fixed to zero."
msgstr ""
-"Beste Übereinstimmung, bedeutet nicht, dass es eine gute Übereinstimmung war."
+"Limits für Saldo und Rückerstattung gelten für einen einzelnen Saldo "
+"beziehungsweise eine einzelne Transaktion; ihr Zeitraum ist daher fest auf "
+"null gesetzt."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:303
-msgid "Score for how good the sanction list match was"
-msgstr "Bewertung, wie gut die Übereinstimmung mit der Sanktionsliste war"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:716
+msgid "Exposed"
+msgstr "Sichtbar"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:308
-msgid "Score for how much supporting data we had for the sanction list match"
-msgstr ""
-"Bewertung, wie viele Belegdaten für die Übereinstimmung mit der "
-"Sanktionsliste vorlagen"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:717
+msgid "Is this limit communicated to the customer?"
+msgstr "Wird dieses Limit dem Kunden mitgeteilt?"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:313
-msgid ""
-"Suppress flagging this account when it creates a hit on a sanctions list, "
-"this is a false-positive"
-msgstr ""
-"Markierung dieses Kontos unterdrücken, wenn es einen Treffer auf einer "
-"Sanktionsliste erzeugt; dies ist ein Fehlalarm"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:723
+msgid "When the threshold is crossed"
+msgstr "Wenn der Schwellenwert überschritten wird"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:190
-#, fuzzy
-msgid "Failed to make the decision."
-msgstr "Die Entscheidung beschreiben."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:726
+msgid "Require measures"
+msgstr "Maßnahmen verlangen"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:193
-#, fuzzy
-msgid "Invalid credentials."
-msgstr "Ungültiges Konto"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:740
+msgid "Required measures"
+msgstr "Erforderliche Maßnahmen"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:197
-#, fuzzy
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:741
msgid ""
-"The session is disabled or a more recent decision was already submitted."
+"Measures that the customer will need to satisfy to apply for a new threshold."
msgstr ""
-"Sachbearbeiter deaktiviert oder es wurde bereits eine neuere Entscheidung "
-"übermittelt."
+"Maßnahmen, die der Kunde erfüllen muss, um einen neuen Schwellenwert zu "
+"beantragen."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:208
-msgid "Confirmation required"
-msgstr "Bestätigung erforderlich"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:747
+msgid "All measures"
+msgstr "Alle Maßnahmen"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:209
-#, fuzzy
-msgid ""
-"This decision declares that the MROS report has concluded. Please make sure "
-"that this is the case"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:748
+msgid "Hint the customer that all measures should be completed"
msgstr ""
-"Diese Entscheidung erklärt, dass die MROS-Meldung abgeschlossen ist. Bitte "
-"stellen Sie sicher, dass dies zutrifft"
+"Den Kunden darauf hinweisen, dass alle Maßnahmen abgeschlossen werden sollten"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:222
-msgid "I want to check first!"
-msgstr "Ich möchte zuerst prüfen!"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:767
+msgid "Expiration date"
+msgstr "Ablaufdatum"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:229
-msgid "Confirm decision"
-msgstr "Entscheidung bestätigen"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:768
+msgid "Until when are the new rules active."
+msgstr "Bis wann die neuen Regeln aktiv sind."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:245
-msgid "Missing deadline"
-msgstr "Frist fehlt"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:773
+msgid "Choose a future expiration date or Never."
+msgstr "Wählen Sie ein zukünftiges Ablaufdatum oder „Nie“."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:248
-msgid ""
-"Deadline should specify when this rules ends and what is the next measures "
-"to apply after expiration."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:779
+msgid "After expiration"
+msgstr "Nach dem Ablauf"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:781
+msgid "Return to exchange defaults"
+msgstr "Zu den Börsenstandards zurückkehren"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:782
+msgid "Trigger a successor measure"
+msgstr "Eine Nachfolgemaßnahme auslösen"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:797
+msgid "Measure taken automatically upon expiration of the current decision."
msgstr ""
-"Die Frist sollte angeben, wann diese Regel endet und welche Maßnahmen nach "
-"Ablauf anzuwenden sind."
+"Maßnahme, die automatisch bei Ablauf der aktuellen Entscheidung ergriffen "
+"wird."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:257
-msgid "Missing rules"
-msgstr "Regeln fehlen"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:805
+msgid "This successor measure is no longer available."
+msgstr "Diese Nachfolgemaßnahme ist nicht mehr verfügbar."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:260
-msgid "Can't make a decision without rules."
-msgstr "Ohne Regeln kann keine Entscheidung getroffen werden."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:133
+msgid "Case summary"
+msgstr "Fallübersicht"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:284
-msgid "Missing active measure"
-msgstr "Aktive Maßnahme fehlt"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:134
+msgid "Current review state and the latest account activity."
+msgstr "Aktueller Prüfstatus und letzte Kontoaktivität."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:287
-msgid "You should specify in the measure section."
-msgstr "Sie sollten dies im Abschnitt Maßnahmen angeben."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:138
+msgid "Review status"
+msgstr "Prüfstatus"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:294
-msgid "No customer action required."
-msgstr "Keine Kundenaktion erforderlich."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:142
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:153
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:171
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:188
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:492
+msgid "Loading…"
+msgstr "Wird geladen…"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:297
-msgid "No active measure has been selected."
-msgstr "Es wurde keine aktive Maßnahme ausgewählt."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:146
+msgid "Manual review required — waiting for an AML decision."
+msgstr "Manuelle Prüfung erforderlich — wartet auf eine AML-Entscheidung."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:305
-msgid "Missing properties"
-msgstr "Eigenschaften fehlen"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:147
+msgid "No manual review"
+msgstr "Keine manuelle Prüfung"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:308
-msgid "You should specify in the properties section."
-msgstr "Sie sollten dies im Abschnitt Eigenschaften angeben."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:150
+msgid "Effective decision"
+msgstr "Wirksame Entscheidung"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:318
-msgid "Missing events"
-msgstr "Ereignisse fehlen"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:168
+msgid "Requirements"
+msgstr "Anforderungen"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:321
-msgid "You should specify in the events section."
-msgstr "Sie sollten dies im Abschnitt Ereignisse angeben."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:185
+msgid "Latest collected information"
+msgstr "Neueste erfasste Informationen"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:331
-msgid "Missing justification"
-msgstr "Begründung fehlt"
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:208
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:305
+#, fuzzy
+#| msgid "Send decision"
+msgid "Current decision"
+msgstr "Entscheidung senden"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:334
-msgid "You must complete the justification section."
-msgstr "Sie müssen den Abschnitt Begründung ausfüllen."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:209
+#, fuzzy
+#| msgid ""
+#| "The AML decision and operation rules currently applied to this account."
+msgid "The complete AML decision currently applied to this account."
+msgstr ""
+"Die derzeit für dieses Konto geltende AML-Entscheidung und die "
+"Vorgangsregeln."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:344
-msgid "Invalid attributes"
-msgstr "Ungültige Attribute"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:216
+msgid "Effective policy could not be loaded"
+msgstr "Die geltende Richtlinie konnte nicht geladen werden"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:347
-msgid "You should check form errors or submit a decision without attributes."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:234
+msgid "Exchange defaults apply"
+msgstr "Exchange-Standardregeln gelten"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:235
+msgid "No AML officer decision is active for this account."
msgstr ""
-"Sie sollten Formularfehler prüfen oder eine Entscheidung ohne Attribute "
-"übermitteln."
+"Für dieses Konto ist keine Entscheidung eines AML-Sachbearbeiters aktiv."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:361
-msgid "Clear"
-msgstr "Leeren"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:238
+msgid "Account type unavailable"
+msgstr "Kontotyp nicht verfügbar"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:368
-msgid "Send decision"
-msgstr "Entscheidung senden"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:239
+msgid ""
+"Open this case from the account directory or payto search to see the "
+"applicable default rules."
+msgstr ""
+"Öffnen Sie diesen Fall über das Kontoverzeichnis oder die Payto-Suche, um "
+"die geltenden Standardregeln anzuzeigen."
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:173
-msgid "Prev"
-msgstr "Zurück"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:248
+msgid "Default rules could not be loaded"
+msgstr "Standardregeln konnten nicht geladen werden"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:182
-msgid "Next"
-msgstr "Weiter"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:255
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:419
+#: packages/taler-exchange-aml-webui/src/components/ShowDefaultRules.tsx:11
+msgid "Default rules"
+msgstr "Standardregeln"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:207
-msgid "Attributes"
-msgstr "Attribute"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:266
+msgid "Collected information"
+msgstr "Erfasste Informationen"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:208
-msgid "Add more information about the customer"
-msgstr "Weitere Informationen über den Kunden hinzufügen"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:267
+msgid "KYC information filed by the customer or an AML officer."
+msgstr ""
+"Vom Kunden oder einem AML-Sachbearbeiter eingereichte KYC-Informationen."
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:212
-msgid "Rules"
-msgstr "Regeln"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:273
+msgid "Collected information could not be loaded"
+msgstr "Erfasste Informationen konnten nicht geladen werden"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:213
-msgid "Set the limit of the operations"
-msgstr "Das Limit der Vorgänge festlegen"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:279
+msgid "No collected information"
+msgstr "Keine erfassten Informationen"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:218
-msgid "Trigger notifications."
-msgstr "Benachrichtigungen auslösen."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:280
+msgid "No KYC information has been collected for this account."
+msgstr "Für dieses Konto wurden keine KYC-Informationen erfasst."
-#. screenid: 113
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:222
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:102
-msgid "Measures"
-msgstr "Maßnahmen"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:302
+msgid "Active requirements"
+msgstr "Aktive Anforderungen"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:223
-msgid "Ask the customer to take action."
-msgstr "Den Kunden zum Handeln auffordern."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:303
+msgid "Measures the customer must complete under the current policy."
+msgstr ""
+"Maßnahmen, die der Kunde gemäß der aktuellen Richtlinie abschließen muss."
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:228
-msgid "Describe the decision."
-msgstr "Die Entscheidung beschreiben."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:309
+msgid "Active requirements could not be loaded"
+msgstr "Aktive Anforderungen konnten nicht geladen werden"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:235
-msgid "Flag the current account state."
-msgstr "Den aktuellen Kontostatus markieren."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:315
+msgid "No active requirements"
+msgstr "Keine aktiven Anforderungen"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:239
-msgid "Summary"
-msgstr "Zusammenfassung"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:316
+msgid "The customer has no active legitimization measures to complete."
+msgstr "Der Kunde muss keine aktiven Legitimierungsmaßnahmen abschließen."
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:240
-msgid "Review and submit."
-msgstr "Überprüfen und absenden."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:413
+msgid "Officer decision"
+msgstr "Entscheidung des Sachbearbeiters"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:404
-msgid "Decision for account:"
-msgstr "Entscheidung für Konto:"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:416
+msgid "Does not expire"
+msgstr "Läuft nicht ab"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:411
-msgid "Decision for wallet:"
-msgstr "Entscheidung für Wallet:"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:439
+msgid "Waiting"
+msgstr "Ausstehend"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:417
-msgid "Decision for bank account:"
-msgstr "Entscheidung für Bankkonto:"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:451
+msgid "More on later pages"
+msgstr "Weitere auf nachfolgenden Seiten"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:88
-msgid "Search account"
-msgstr "Konto suchen"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:510
+msgid "Try loading this section again."
+msgstr "Versuchen Sie, diesen Abschnitt erneut zu laden."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:154
-msgid "Failed to load account decisions."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:518
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:97
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:633
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:205
+msgid "Retry"
+msgstr "Erneut versuchen"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:163
-#, fuzzy
-msgid "Failed to load the account history."
-msgstr "Vollständiger Name des Kontoinhabers"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:566
+msgid "Unconfigured form"
+msgstr "Nicht konfiguriertes Formular"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:205
-msgid "Check account details"
-msgstr "Kontodetails überprüfen"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:567
+msgid "Form not identified"
+msgstr "Formular nicht identifiziert"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:212
-msgid "Account most recent decisions"
-msgstr "Jüngste Entscheidungen zum Konto"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:576
+msgid "Filed by an AML officer"
+msgstr "Von einem AML-Sachbearbeiter eingereicht"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:231
-msgid "When"
-msgstr "Wann"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:577
+msgid "Provided by the customer"
+msgstr "Vom Kunden bereitgestellt"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:265
-msgid "LATEST"
-msgstr "NEUESTE"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:581
+msgid "Attribute data is unavailable."
+msgstr "Attributdaten sind nicht verfügbar."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:270
-msgid "ACTIVE"
-msgstr "AKTIV"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:595
+msgid "View details"
+msgstr "Details anzeigen"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:297
-msgid "Account not found"
-msgstr "Konto nicht gefunden"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:70
+msgid ""
+"Review superseded AML decisions for this account, from newest to oldest."
+msgstr ""
+"Abgelöste AML-Entscheidungen für dieses Konto von der neuesten bis zur "
+"ältesten prüfen."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:298
-msgid "There is no history known for this account yet."
-msgstr "Für dieses Konto ist noch kein Verlauf bekannt."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:79
+msgid "Loading decision history…"
+msgstr "Entscheidungsverlauf wird geladen…"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:308
-msgid "You can make a decision for this account anyway."
-msgstr "Sie können trotzdem eine Entscheidung für dieses Konto treffen."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:84
+msgid "Decision history could not be loaded"
+msgstr "Entscheidungsverlauf konnte nicht geladen werden"
-#. screenid: 111
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:357
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:400
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:449
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:490
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:377
-msgid "Search"
-msgstr "Suchen"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:87
+msgid "Try loading the decision history again."
+msgstr "Versuchen Sie erneut, den Entscheidungsverlauf zu laden."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:528
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:761
-msgid "IBAN"
-msgstr "IBAN"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:111
+msgid "No previous decisions"
+msgstr "Keine früheren Entscheidungen"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:532
-msgid "Taler Bank"
-msgstr "Taler-Bank"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:114
+msgid "No superseded AML decisions have been recorded for this account."
+msgstr "Für dieses Konto wurden keine abgelösten AML-Entscheidungen erfasst."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:536
-msgid "Wallet"
-msgstr "Wallet"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:125
+msgid "Previous decisions"
+msgstr "Frühere Entscheidungen"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:540
-msgid "Generic Payto:// URI"
-msgstr "Allgemeine Payto://-URI"
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:153
+msgid "The export could not be prepared. Try again."
+msgstr "Der Export konnte nicht erstellt werden. Versuchen Sie es erneut."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:543
-msgid "Account type"
-msgstr "Kontotyp"
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:164
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:173
+msgid "Failed to load accounts"
+msgstr "Konten konnten nicht geladen werden"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:553
-msgid "Should be 52 characters."
-msgstr "Sollte 52 Zeichen haben."
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:193
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:552
+msgid "Accounts"
+msgstr "Konten"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:555
-msgid "Failed to parse: %1$s"
-msgstr "Konnte nicht geparst werden: %1$s"
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:196
+msgid "Review accounts known to the exchange for AML and KYC handling."
+msgstr ""
+"Prüfen Sie die dem Exchange bekannten Konten zur AML- und KYC-Bearbeitung."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:567
-msgid "Address contains invalid characters."
-msgstr "Die Adresse enthält ungültige Zeichen."
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:203
+msgid "Export filtered accounts"
+msgstr "Gefilterte Konten exportieren"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:569
-msgid "Can't mix uppercased and lowercased characters."
-msgstr "Groß- und Kleinbuchstaben dürfen nicht gemischt werden."
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:211
+msgid "Download CSV"
+msgstr "CSV herunterladen"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:571
-msgid "The addr checksum doesn't match."
-msgstr "Die Adress-Prüfsumme stimmt nicht überein."
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:218
+msgid "Download Excel"
+msgstr "Excel-Datei herunterladen"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:573
-msgid "Missing separator or address type."
-msgstr "Trennzeichen oder Adresstyp fehlt."
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:226
+msgid "Preparing export…"
+msgstr "Export wird vorbereitet…"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:230
+msgid "Export failed"
+msgstr "Export fehlgeschlagen"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:236
+msgid "Account filters"
+msgstr "Kontofilter"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:242
+msgid "Investigation"
+msgstr "Untersuchung"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:244
+msgid "All accounts"
+msgstr "Alle Konten"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:251
+msgid "Risk"
+msgstr "Risiko"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:253
+msgid "All risk levels"
+msgstr "Alle Risikostufen"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:255
+msgid "Not high risk"
+msgstr "Kein hohes Risiko"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:260
+msgid "File status"
+msgstr "Aktenstatus"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:262
+msgid "All file statuses"
+msgstr "Alle Aktenstatus"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:264
+msgid "Not open"
+msgstr "Nicht offen"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:273
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:589
+msgid "Clear filters"
+msgstr "Filter zurücksetzen"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:283
+msgid "Showing %1$s accounts · newest first"
+msgstr "%1$s Konten · neueste zuerst"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:290
+msgid "AML and KYC accounts"
+msgstr "AML- und KYC-Konten"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:298
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:458
+msgid "Account lifecycle"
+msgstr "Lebenszyklus der Akte"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:304
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:467
+msgid "Latest note"
+msgstr "Neueste Notiz"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:550
+msgid "Copied"
+msgstr "Kopiert"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:550
+msgid "Copy"
+msgstr "Kopieren"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:576
+msgid "No matching accounts"
+msgstr "Keine passenden Konten"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:576
+msgid "No accounts yet"
+msgstr "Noch keine Konten"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:580
+msgid "No accounts match the selected filters."
+msgstr "Keine Konten entsprechen den ausgewählten Filtern."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:581
+msgid "The exchange has not recorded any AML or KYC accounts yet."
+msgstr "Der Exchange hat noch keine AML- oder KYC-Konten erfasst."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:647
+msgid "This officer session is not authorized to list accounts."
+msgstr "Diese Sachbearbeitersitzung ist nicht berechtigt, Konten aufzulisten."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:649
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:674
+msgid "The exchange does not recognize this officer session."
+msgstr "Der Exchange erkennt diese Sachbearbeitersitzung nicht."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:651
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:676
+msgid "This officer session is currently disabled."
+msgstr "Diese Sachbearbeitersitzung ist derzeit deaktiviert."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:668
+msgid "There are no matching accounts to export."
+msgstr "Es gibt keine passenden Konten für den Export."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:670
+msgid "The exchange does not support the selected export format."
+msgstr "Der Exchange unterstützt das ausgewählte Exportformat nicht."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:672
+msgid "This officer session is not authorized to export accounts."
+msgstr ""
+"Diese Sachbearbeitersitzung ist nicht berechtigt, Konten zu exportieren."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:575
-msgid "Address should have less than 90 characters."
-msgstr "Die Adresse sollte weniger als 90 Zeichen haben."
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:52
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:546
+msgid "Dashboard"
+msgstr "Dashboard"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:577
-msgid "Address should have more than 6 characters."
-msgstr "Die Adresse sollte mehr als 6 Zeichen haben."
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:55
+msgid ""
+"Review cases requiring attention, investigate accounts, and monitor AML "
+"reporting indicators."
+msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:579
-msgid "Decoding issue."
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:77
+msgid "Review case queue"
msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:581
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:80
#, fuzzy
-msgid "Invalid data"
-msgstr "Ungültiger Host"
-
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:591
-msgid "Unsupported country."
-msgstr "Nicht unterstütztes Land."
+#| msgid "Accounts under investigation."
+msgid "Review accounts currently under investigation."
+msgstr "Konten in Untersuchung."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:593
-msgid "IBANs have fewer than 34 characters."
-msgstr "IBANs haben weniger als 34 Zeichen."
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:94
+#, fuzzy
+#| msgid "Show transfers"
+msgid "Inspect transfers"
+msgstr "Überweisungen anzeigen"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:595
-msgid "IBANs have more than 4 characters."
-msgstr "IBANs haben mehr als 4 Zeichen."
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:97
+msgid "Find credit, debit, and KYC authorization activity."
+msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:597
-msgid "IBAN length is invalid for this country."
-msgstr "Die IBAN-Länge ist für dieses Land ungültig."
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:128
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:165
+msgid "Statistics"
+msgstr "Statistiken"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:597
-msgid "It should only contain numbers and letters."
-msgstr "Es sollte nur Zahlen und Buchstaben enthalten."
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:132
+msgid "No reporting profile for this dialect"
+msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:599
-msgid "The checksum is wrong."
-msgstr "Die Prüfsumme ist falsch."
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:137
+msgid ""
+"The testing dialect does not define dashboard statistics. Select TOPS in "
+"development settings to inspect the TOPS reporting profile."
+msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:617
-msgid "The string should start with payto://"
-msgstr "Die Zeichenfolge sollte mit payto:// beginnen"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:154
+msgid "Failed to load TOPS statistics."
+msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:619
-msgid "After the target type it should follow a '/' with more information."
-msgstr "Nach dem Zieltyp sollte ein '/' mit weiteren Informationen folgen."
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:192
+#, fuzzy
+#| msgid "Attributes unavailable"
+msgid "Some statistics are unavailable."
+msgstr "Attribute nicht verfügbar"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:621
-msgid ""
-"The target type is not supported, only x-taler-bank, taler-reserve or iban"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:195
+msgid "The available values are shown below. Missing values are not zero."
msgstr ""
-"Der Zieltyp wird nicht unterstützt, nur x-taler-bank, taler-reserve oder iban"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:626
-msgid "IBAN is missing"
-msgstr "IBAN fehlt"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:275
+msgid "Accounts open"
+msgstr "Eröffnete Konten"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:628
-msgid "Bitcoin address is missing"
-msgstr "Bitcoin-Adresse fehlt"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:278
+msgid "New files last year"
+msgstr "Neue Akten im letzten Jahr"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:630
-msgid "Bank host and account is missing"
-msgstr "Bank-Host und Konto fehlen"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:281
+msgid "Closed files last year"
+msgstr "Geschlossene Akten im letzten Jahr"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:632
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:634
-msgid "Exchange host and account is missing"
-msgstr "Exchange-Host und Konto fehlen"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:284
+msgid "MROS substantiated"
+msgstr "MROS begründet"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:636
-msgid "Ethereum address is missing"
-msgstr "Ethereum-Adresse fehlt"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:287
+msgid "MROS simple"
+msgstr "MROS einfach"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:638
-msgid "Cyclos address is missing"
-msgstr "Cyclos-Adresse fehlt"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:290
+msgid "High risk files"
+msgstr "Hochrisiko-Akten"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:640
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:293
+msgid "PEP files"
+msgstr "PEP-Akten"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:333
+msgid "Number of accounts that are opened"
+msgstr "Anzahl der eröffneten Konten"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:336
+msgid "Number of new GwG files in the last year"
+msgstr "Anzahl neuer GwG-Akten im letzten Jahr"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:339
+msgid "Number of GwG files closed in the last year"
+msgstr "Anzahl der im letzten Jahr geschlossenen GwG-Akten"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:342
+msgid "Number of MROS reports based on Art 9 Abs. 1 GwG (per year)"
+msgstr "Anzahl der MROS-Meldungen gemäß Art. 9 Abs. 1 GwG (pro Jahr)"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:345
+msgid "Number of MROS reports based on Art 305ter Abs. 2 StGB (per year)"
+msgstr "Anzahl der MROS-Meldungen gemäß Art. 305ter Abs. 2 StGB (pro Jahr)"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:348
+msgid "Number of GwG files of high-risk customers"
+msgstr "Anzahl der GwG-Akten von Hochrisikokunden"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:351
+msgid "Number of GwG files managed with “increased risk” due to PEP status"
+msgstr "Anzahl der GwG-Akten mit „erhöhtem Risiko“ aufgrund des PEP-Status"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:354
#, fuzzy
-msgid "Void address is missing"
-msgstr "Bitcoin-Adresse fehlt"
+msgid "Number of customers with open proceeding."
+msgstr "Anzahl der eröffneten Konten"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:648
-msgid "Invalid IBAN: %1$s"
-msgstr "Ungültige IBAN: %1$s"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:400
+msgid "previous"
+msgstr "vorherig"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:655
-msgid "Invalid BTC: %1$s"
-msgstr "Ungültige BTC-Adresse: %1$s"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:443
+msgid "Decreased by"
+msgstr "Verringert um"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:660
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:683
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:696
-msgid "Invalid reserve: %1$s"
-msgstr "Ungültige Reserve: %1$s"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:447
+msgid "Increased by"
+msgstr "Erhöht um"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:671
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:681
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:694
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:715
-msgid "Invalid host"
-msgstr "Ungültiger Host"
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:114
+msgid ""
+"The built-in event selection differs from the events derived from the "
+"proposed account state."
+msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:707
-msgid "Invalid address"
-msgstr "Ungültige Adresse"
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:119
+msgid ""
+"Built-in events are derived from changes to the proposed account properties. "
+"They are stored for reporting and statistics; they do not notify the "
+"customer."
+msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:745
-msgid "Payto URI"
-msgstr "Payto-URI"
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:138
+#, fuzzy
+#| msgid "Reset to default"
+msgid "Reset to derived events"
+msgstr "Auf Standard zurücksetzen"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:746
-msgid "As defined by RFC 8905"
-msgstr "Wie in RFC 8905 definiert"
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:169
+msgid "Calculated"
+msgstr "Berechnet"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:747
-msgid "payto://"
-msgstr "payto://"
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:170
+msgid ""
+"Events derived from proposed property changes and submitted information."
+msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:762
-msgid "International Bank Account Number"
-msgstr "Internationale Bankkontonummer"
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:184
+msgid "Other built-in events"
+msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:763
-msgid "DE1231231231"
-msgstr "DE1231231231"
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:185
+#, fuzzy
+#| msgid "Events that can be triggered manually"
+msgid "Additional events that may be recorded manually."
+msgstr "Ereignisse, die manuell ausgelöst werden können"
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:198
+#, fuzzy
+#| msgid "Next event"
+msgid "Custom events"
+msgstr "Nächstes Ereignis"
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:199
+msgid "Operator-defined event names that are not part of the selected dialect."
+msgstr ""
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:213
+#, fuzzy
+#| msgid "Describe the decision."
+msgid "Events recorded with this decision"
+msgstr "Die Entscheidung beschreiben."
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:214
+#, fuzzy
+#| msgid ""
+#| "The events will be triggered only after the decision has been confirmed."
+msgid "Events are added only after the decision is successfully submitted."
+msgstr ""
+"Die Ereignisse werden erst ausgelöst, nachdem die Entscheidung bestätigt "
+"wurde."
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:209
+#, fuzzy
+#| msgid "System information"
+msgid "Add customer information"
+msgstr "Systeminformation"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:212
+msgid ""
+"The completed form is attached to this AML decision as reviewed account "
+"information. It does not create a customer-facing measure."
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:223
+#, fuzzy
+#| msgid "Collected information"
+msgid "Selected form"
+msgstr "Erfasste Informationen"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:233
+#, fuzzy
+#| msgid "Complete the form"
+msgid "Choose another form"
+msgstr "Formular ausfüllen"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:242
+msgid "Expiration"
+msgstr "Ablauf"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:243
+msgid "Expiration date of the information filled in this form."
+msgstr "Ablaufdatum der in diesem Formular eingegebenen Informationen."
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:254
+#, fuzzy
+#| msgid "Context"
+msgid "Form context"
+msgstr "Kontext"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:261
+#, fuzzy
+#| msgid "Context"
+msgid "Advanced form context"
+msgstr "Kontext"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:264
+msgid ""
+"Only change this operator-defined JSON when the form documentation requires "
+"additional context."
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:270
+#, fuzzy
+#| msgid "Context"
+msgid "Context as JSON"
+msgstr "Kontext"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:291
+#, fuzzy
+msgid "Invalid JSON"
+msgstr "Ungültiger Host"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:296
+msgid "Invalid expiration"
+msgstr "Ungültiges Ablaufdatum"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:297
+msgid "Attributes require an expiration date in the future or set to Never."
+msgstr ""
+"Attribute benötigen ein in der Zukunft liegendes Ablaufdatum oder müssen auf "
+"„Nie“ gesetzt werden."
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:355
+msgid "Include new information"
+msgstr "Neue Informationen einbeziehen"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:356
+msgid ""
+"This step is optional. Select a form to attach newly reviewed AML/KYC "
+"information, or continue without one."
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:361
+msgid "AML/KYC form"
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:362
+msgid "Search AML/KYC forms"
+msgstr "AML/KYC-Formulare durchsuchen"
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:101
+#, fuzzy
+#| msgid "Accounts under investigation."
+msgid "The account will be included in the AML investigation queue."
+msgstr "Konten in Untersuchung."
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:106
+#, fuzzy
+#| msgid "Accounts under investigation."
+msgid "The account will not be included in the AML investigation queue."
+msgstr "Konten in Untersuchung."
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:114
+#, fuzzy
+#| msgid "Investigation"
+msgid "Current investigation status"
+msgstr "Untersuchung"
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:128
+#, fuzzy
+#| msgid "No previous decisions"
+msgid "No previous decision"
+msgstr "Keine früheren Entscheidungen"
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:140
+#, fuzzy
+#| msgid "Investigation"
+msgid "Investigation status after this decision"
+msgstr "Untersuchung"
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:145
+#, fuzzy
+#| msgid "Measures the customer must complete under the current policy."
+msgid ""
+"Choose whether the account should remain in the AML investigation queue "
+"after this decision is submitted."
+msgstr ""
+"Maßnahmen, die der Kunde gemäß der aktuellen Richtlinie abschließen muss."
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:201
+msgid ""
+"Full name used in the payto URI when creating this previously unknown "
+"account."
+msgstr ""
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:208
+#, fuzzy
+#| msgid "Decision date"
+msgid "Decision rationale"
+msgstr "Entscheidungsdatum"
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:209
+msgid ""
+"Record the facts and reasoning needed to understand this decision in a later "
+"audit or review."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:264
+#, fuzzy
+#| msgid "Custom measures"
+msgid "Create custom measure"
+msgstr "Benutzerdefinierte Maßnahmen"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:266
+#, fuzzy
+#| msgid "Add custom measure"
+msgid "Edit custom measure"
+msgstr "Benutzerdefinierte Maßnahme hinzufügen"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:270
+msgid ""
+"Combine a customer check with an AML program, or use SKIP to run a program "
+"immediately. Context values must satisfy the selected check and program "
+"requirements."
+msgstr ""
+
+#. screenid: 122
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:289
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:478
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:366
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:115
+msgid "Add custom measure"
+msgstr "Benutzerdefinierte Maßnahme hinzufügen"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:299
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:488
+msgid "Save changes"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:306
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:495
+#, fuzzy
+#| msgid "Add custom measure"
+msgid "Remove custom measure"
+msgstr "Benutzerdefinierte Maßnahme hinzufügen"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:547
+#, fuzzy
+#| msgid "Configure verification type: %1$s"
+msgid "Configure %1$s verification"
+msgstr "Verifizierungstyp konfigurieren: %1$s"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:558
+msgid "Use advanced measure editor"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:587
+#, fuzzy
+#| msgid "Name of the verification measure"
+msgid "Use guided verification editor"
+msgstr "Name der Verifizierungsmaßnahme"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:632
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1111
+msgid "There is already a measure with that name"
+msgstr "Es gibt bereits eine Maßnahme mit diesem Namen"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:646
+msgid ""
+"Runs immediately for SKIP measures, or after a successful check. It may be "
+"omitted for a check that only presents or collects information."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:650
+msgid "Missing check or program"
+msgstr "Prüfung oder Programm fehlt"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:660
+msgid ""
+"The customer-facing check to perform before the program. Leave empty to use "
+"SKIP and run the program immediately."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:683
+msgid ""
+"Configuration values required by the selected check or program. Property "
+"names and value types must match the exchange configuration."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:690
+msgid "Field name"
+msgstr "Feldname"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:695
+msgid "Type"
+msgstr "Typ"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:699
+msgid "string"
+msgstr "string"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:703
+msgid "number"
+msgstr "number"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:707
+msgid "boolean"
+msgstr "boolean"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:711
+msgid "json"
+msgstr "json"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:738
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:792
+#, fuzzy
+#| msgid "Form not available"
+msgid "Program \"%1$s\" is not available"
+msgstr "Formular nicht verfügbar"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:742
+msgid "There are unsatisfied inputs: %1$s"
+msgstr "Es gibt nicht erfüllte Eingaben: %1$s"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:750
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:772
+msgid "Check \"%1$s\" is not available"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:756
+msgid "There are missing inputs: %1$s"
+msgstr "Es fehlen Eingaben: %1$s"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:779
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:799
+msgid "There are missing requirements: %1$s"
+msgstr "Es fehlen Anforderungen: %1$s"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:855
+msgid "Can't be empty"
+msgstr "Darf nicht leer sein"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:859
+msgid "Not a number"
+msgstr "Keine Zahl"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:861
+msgid "It should be finite"
+msgstr "Es sollte endlich sein"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:866
+msgid "It should be either \"true\" or \"false\""
+msgstr "Es sollte entweder \"true\" oder \"false\" sein"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:871
+msgid "Couldn't parse as json string: %1$s"
+msgstr "Konnte nicht als JSON-String geparst werden: %1$s"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:899
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:946
+msgid "Description"
+msgstr "Beschreibung"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:915
+msgid "Inputs"
+msgstr "Eingaben"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:954
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:534
+#, fuzzy
+#| msgid "Output"
+msgid "Outputs"
+msgstr "Ausgabe"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:962
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:401
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:533
+#, fuzzy
+#| msgid "Required"
+msgid "Required context"
+msgstr "Erforderlich"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:970
+msgid "Fallback"
+msgstr "Fallback"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:993
+#, fuzzy
+#| msgid "Context"
+msgid "Context values"
+msgstr "Kontext"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1045
+msgid "Selected pipeline"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1048
+msgid "Review how the exchange will execute this measure."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1105
+msgid "Name of the verification measure"
+msgstr "Name der Verifizierungsmaßnahme"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1118
+msgid "Read only"
+msgstr "Nur lesen"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1119
+msgid "Prevent the customer from changing the address"
+msgstr "Verhindert, dass der Kunde die Adresse ändert"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:154
+msgid "Customer actions after submission"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:157
+msgid ""
+"Immediate measures start as soon as this decision is accepted. A measure may "
+"show information, collect customer data, or run an AML program. Leave the "
+"selection empty when no immediate customer action is required."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:302
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:301
+msgid "Too many SKIP measures"
+msgstr "Zu viele SKIP-Maßnahmen"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:303
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:302
+msgid "At most one immediate measure may use the SKIP check."
+msgstr "Höchstens eine sofortige Maßnahme darf die SKIP-Prüfung verwenden."
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:332
+#, fuzzy
+#| msgid "Configure verification measure: \"%1$s\""
+msgid "Configure verification measure “%1$s”"
+msgstr "Verifizierungsmaßnahme konfigurieren: \"%1$s\""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:372
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:522
+msgid "Custom measures"
+msgstr "Benutzerdefinierte Maßnahmen"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:375
+msgid "Measures defined only for this proposed decision."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:399
+msgid "Edit"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:407
+#, fuzzy
+#| msgid "All measures"
+msgid "Available exchange measures"
+msgstr "Alle Maßnahmen"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:410
+msgid "Reusable templates configured by the exchange operator"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:432
+msgid "Use as template"
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:512
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:288
+#, fuzzy
+#| msgid "Instant measures"
+msgid "Immediate measures"
+msgstr "Sofortmaßnahmen"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:513
+msgid ""
+"Selected measures begin immediately after the decision is accepted by the "
+"exchange."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:518
+#, fuzzy
+#| msgid "Require all measures"
+msgid "Require every selected measure"
+msgstr "Alle Maßnahmen voraussetzen"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:519
+#, fuzzy
+#| msgid ""
+#| "Run all selected measures together instead of accepting any one of them."
+msgid ""
+"When enabled, all selected measures must be completed. Otherwise, completing "
+"any one of them is sufficient."
+msgstr ""
+"Alle ausgewählten Maßnahmen gemeinsam ausführen, anstatt eine beliebige "
+"davon zu akzeptieren."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:190
+#, fuzzy
+msgid "Failed to make the decision."
+msgstr "Die Entscheidung beschreiben."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:193
+#, fuzzy
+msgid "Invalid credentials."
+msgstr "Ungültiges Konto"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:195
+msgid "Session not found. Contact the administrator."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:197
+msgid ""
+"The exchange rejected the decision because the officer session is disabled "
+"or the account has a newer decision. Reload the account before trying again."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:251
+msgid ""
+"This decision records that an MROS report was filed. Confirm that the report "
+"has actually been submitted before continuing."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:264
+#, fuzzy
+#| msgid "No manual review"
+msgid "Go back and review"
+msgstr "Keine manuelle Prüfung"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:271
+msgid "Confirm decision"
+msgstr "Entscheidung bestätigen"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:283
+msgid "Unknown measure"
+msgstr "Unbekannte Maßnahme"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:284
+msgid ""
+"A rule or immediate action references a measure that is not available. "
+"Review the rules and measures before submitting."
+msgstr ""
+"Eine Regel oder sofortige Aktion verweist auf eine nicht verfügbare "
+"Maßnahme. Prüfen Sie die Regeln und Maßnahmen vor dem Absenden."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:291
+#, fuzzy
+#| msgid "Add custom measure"
+msgid "Invalid custom measure"
+msgstr "Benutzerdefinierte Maßnahme hinzufügen"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:292
+msgid ""
+"A custom measure references an unavailable check or program, lacks required "
+"context, or cannot provide the selected program inputs. Review the immediate "
+"measures before submitting."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:310
+msgid "Missing deadline"
+msgstr "Frist fehlt"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:311
+msgid "Set when the proposed rules expire and what should happen afterward."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:319
+msgid "Invalid rule expiration"
+msgstr "Ungültiger Regelablauf"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:320
+msgid "Rule expiration must be in the future or set to Never."
+msgstr ""
+"Der Regelablauf muss in der Zukunft liegen oder auf „Nie“ gesetzt sein."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:327
+msgid "Missing rules"
+msgstr "Regeln fehlen"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:328
+msgid ""
+"A decision must contain the complete rule set that will apply to the account."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:337
+msgid ""
+"Review the proposed rules. Hard blocks must be explicit, and Balance and "
+"Refund rules must use an instant timeframe."
+msgstr ""
+"Prüfen Sie die vorgeschlagenen Regeln. Harte Sperren müssen ausdrücklich "
+"angegeben werden, und Regeln für Saldo und Rückerstattung müssen einen "
+"sofortigen Zeitraum verwenden."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:376
+msgid "Immediate measures not reviewed"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:378
+#, fuzzy
+#| msgid "Measures the customer must complete under the current policy."
+msgid "Review whether the customer must complete any immediate measures."
+msgstr ""
+"Maßnahmen, die der Kunde gemäß der aktuellen Richtlinie abschließen muss."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:384
+#, fuzzy
+#| msgid "Triggered immediately without customer interaction."
+msgid "No immediate customer action"
+msgstr "Wird sofort ohne Kundeninteraktion ausgelöst."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:385
+msgid "No measure will start when this decision is submitted."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:396
+#, fuzzy
+#| msgid "Account properties"
+msgid "Account properties not reviewed"
+msgstr "Kontoeigenschaften"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:398
+msgid "Review the account properties before submitting the decision."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:409
+msgid "Reporting events not reviewed"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:411
+msgid "Review which statistical events will be recorded with the decision."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:420
+msgid "Case disposition incomplete"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:421
+msgid "You must complete the justification section."
+msgstr "Sie müssen den Abschnitt Begründung ausfüllen."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:430
+msgid "Invalid attributes"
+msgstr "Ungültige Attribute"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:431
+msgid ""
+"Correct the selected form or continue without attaching new customer "
+"information."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:443
+#, fuzzy
+#| msgid "Check account details"
+msgid "Decision details"
+msgstr "Kontodetails überprüfen"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:447
+msgid "Justification"
+msgstr "Begründung"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:450
+#, fuzzy
+#| msgid "Not opened"
+msgid "Not provided"
+msgstr "Nicht eröffnet"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:454
+#, fuzzy
+#| msgid "Accounts under investigation."
+msgid "The account remains under investigation."
+msgstr "Konten in Untersuchung."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:458
+#, fuzzy
+#| msgid "Accounts under investigation."
+msgid "The account will not remain under investigation."
+msgstr "Konten in Untersuchung."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:487
+msgid "No account properties"
+msgstr "Keine Kontoeigenschaften"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:493
+msgid "Events"
+msgstr "Ereignisse"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:496
+#, fuzzy
+#| msgid "Next event"
+msgid "No events"
+msgstr "Nächstes Ereignis"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:501
+#, fuzzy
+#| msgid "Invalid attributes"
+msgid "Submitted attributes"
+msgstr "Ungültige Attribute"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:509
+#, fuzzy
+#| msgid "Expiration date"
+msgid "expiration set"
+msgstr "Ablaufdatum"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:515
+#, fuzzy
+#| msgid "Invalid attributes"
+msgid "No new attributes"
+msgstr "Ungültige Attribute"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:537
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:550
+#, fuzzy
+#| msgid "Officer decision"
+msgid "Discard decision"
+msgstr "Entscheidung des Sachbearbeiters"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:544
+#, fuzzy
+#| msgid "Send decision"
+msgid "Submit AML decision"
+msgstr "Entscheidung senden"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:549
+#, fuzzy
+#| msgid "Discard this key"
+msgid "Discard this decision?"
+msgstr "Diesen Schlüssel verwerfen"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:554
+msgid ""
+"All entries made in this decision wizard will be lost. No change will be "
+"submitted to the exchange."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:571
+#, fuzzy
+#| msgid "Review status"
+msgid "Review this step"
+msgstr "Prüfstatus"
+
+#. screenid: 113
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:172
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:250
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:507
+#, fuzzy
+#| msgid "Back to accounts"
+msgid "Back to account"
+msgstr "Zurück zu den Konten"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:177
+#, fuzzy
+#| msgid "New decision"
+msgid "New AML decision"
+msgstr "Neue Entscheidung"
+
+#. screenid: 113
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:201
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:297
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:790
+msgid "Payto URI"
+msgstr "Payto-URI"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:218
+#, fuzzy
+#| msgctxt "threshold"
+#| msgid "%1$s every %2$s"
+msgid "Step %1$s of %2$s"
+msgstr "%1$s alle %2$s"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:236
+msgid "Decision steps"
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:245
+#, fuzzy
+#| msgid "Previous event"
+msgid "Previous step"
+msgstr "Vorheriges Ereignis"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:254
+#, fuzzy
+#| msgid "Next event"
+msgid "Next step"
+msgstr "Nächstes Ereignis"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:273
+#, fuzzy
+#| msgid "System information"
+msgid "Customer information"
+msgstr "Systeminformation"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:274
+#, fuzzy
+#| msgid ""
+#| "You can review AML information, but this officer key cannot submit "
+#| "decisions."
+msgid "Optionally add reviewed AML/KYC information to this decision."
+msgstr ""
+"Sie können AML-Informationen prüfen, aber dieser Sachbearbeiterschlüssel "
+"kann keine Entscheidungen einreichen."
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:279
+msgid "Review the account state derived from the available information."
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:283
+#, fuzzy
+#| msgid "Missing events"
+msgid "Reporting events"
+msgstr "Ereignisse fehlen"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:284
+msgid "Review the statistical events recorded with this decision."
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:289
+#, fuzzy
+#| msgid "Measures the customer must complete under the current policy."
+msgid ""
+"Choose actions the customer must complete after the decision is submitted."
+msgstr ""
+"Maßnahmen, die der Kunde gemäß der aktuellen Richtlinie abschließen muss."
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:293
+#, fuzzy
+#| msgctxt "operation type"
+#| msgid "Transaction"
+msgid "Transaction rules"
+msgstr "Transaktion"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:294
+msgid "Set operation thresholds, escalation measures, and expiration behavior."
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:298
+msgid "Case disposition"
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:299
+#, fuzzy
+#| msgid "Accounts under investigation."
+msgid "Record the rationale and whether the case remains under investigation."
+msgstr "Konten in Untersuchung."
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:305
+#, fuzzy
+#| msgid "Review and submit."
+msgid "Review and submit"
+msgstr "Überprüfen und absenden."
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:306
+msgid "Check the complete decision before signing and submitting it."
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:326
+#, fuzzy
+#| msgid "Decision date"
+msgid "Decision progress"
+msgstr "Entscheidungsdatum"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:407
+#, fuzzy
+#| msgid "Failed to load account decisions."
+msgid "Loading account decision"
+msgstr "Kontoentscheidungen konnten nicht geladen werden."
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:418
+#, fuzzy
+#| msgid "Decision for account:"
+msgid "Decision for account"
+msgstr "Entscheidung für Konto:"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:425
+#, fuzzy
+#| msgid "Decision for account:"
+msgid "Decision for wallet account"
+msgstr "Entscheidung für Konto:"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:431
+#, fuzzy
+#| msgid "Decision for bank account:"
+msgid "Decision for bank account"
+msgstr "Entscheidung für Bankkonto:"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:107
+msgid "Enter a valid HTTP or HTTPS URL."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:114
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:176
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:218
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:259
+msgid "Development settings"
+msgstr "Entwicklungseinstellungen"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:117
+msgid ""
+"These browser-local settings are intended for development and "
+"troubleshooting."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:132
+#, fuzzy
+#| msgid "Exchange hostname"
+msgid "Exchange connection"
+msgstr "Exchange-Hostname"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:135
+msgid ""
+"Changing the exchange reloads the application. The override is stored only "
+"in this browser."
+msgstr ""
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:147
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:97
+msgid "Exchange base URL"
+msgstr "Exchange-Basis-URL"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:166
+msgid "Leave empty to use the configured URL: %1$s"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:170
+msgid "Leave empty to derive the exchange URL from this page."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:184
+msgid "Currently connected to"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:196
+msgid "Apply and reload"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:207
+msgid "Use configured URL"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:214
+msgid "Preferences"
+msgstr "Einstellungen"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:221
+msgid "AML SPA dialect"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:236
+#, fuzzy
+#| msgid "Welcome to the exchange configuration"
+msgid "Use exchange configuration"
+msgstr "Willkommen bei der Exchange-Konfiguration"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:240
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:44
+msgid "Testing"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:244
+msgid ""
+"Override how this web interface presents dialect-specific AML rules and "
+"properties. The override is stored only in this browser."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:262
+#, fuzzy
+msgid "Show debug information"
+msgstr "Debug-Informationen ansehen"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:45
+msgid "Fallback dialect for development and testing."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:52
+msgid "TOPS"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:53
+msgid "Taler Operations deployment for Swiss AML processes."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:56
+msgid "File note"
+msgstr "Aktennotiz"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:57
+#, fuzzy
+#| msgid "Current note on the GwG file"
+msgid "Current note on the GwG file."
+msgstr "Aktuelle Notiz zur GwG-Akte"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:58
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:64
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:112
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:124
+msgid "Text"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:62
+msgid "Customer label"
+msgstr "Kundenbezeichnung"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:68
+msgid "Account open"
+msgstr "Konto eröffnet"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:69
+#, fuzzy
+#| msgid "Is the account active for deposit and payments?"
+msgid "Whether the account is active for deposits and payments."
+msgstr "Ist das Konto für Einzahlungen und Zahlungen aktiv?"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:70
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:76
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:82
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:88
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:94
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:100
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:106
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:142
+#, fuzzy
+#| msgid "boolean"
+msgid "Boolean"
+msgstr "boolean"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:74
+msgid "Domestic PEP"
+msgstr "Inländische PEP"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:75
+msgid "Whether the customer is a domestic politically exposed person."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:80
+msgid "Foreign PEP"
+msgstr "Ausländische PEP"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:81
+msgid "Whether the customer is a foreign politically exposed person."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:86
+msgid "International-organization PEP"
+msgstr "PEP einer internationalen Organisation"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:87
+msgid ""
+"Whether the customer is a politically exposed person associated with an "
+"international organization."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:92
+msgid "High-risk customer"
+msgstr "Hochrisikokunde"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:93
+#, fuzzy
+#| msgid "Measures the customer must complete under the current policy."
+msgid "Whether the customer is classified as high risk."
+msgstr ""
+"Maßnahmen, die der Kunde gemäß der aktuellen Richtlinie abschließen muss."
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:98
+msgid "High-risk country"
+msgstr "Hochrisikoland"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:99
+msgid "Whether the customer is associated with a high-risk country."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:104
+msgid "Account idle"
+msgstr "Konto inaktiv"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:105
+msgid "Whether the account has been marked as idle."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:110
+#, fuzzy
+#| msgid "Investigation trigger"
+msgid "Investigation trigger"
+msgstr "Auslöser der Untersuchung"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:111
+#, fuzzy
+#| msgid "Informal reason why the AML investigation was triggered"
+msgid "Informal reason why the AML investigation was triggered."
+msgstr "Informeller Grund für die Auslösung der AML-Untersuchung"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:116
+#, fuzzy
+#| msgid "Investigation"
+msgid "Investigation state"
+msgstr "Untersuchung"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:117
+#, fuzzy
+#| msgid "The MROS reporting state for the account."
+msgid "Special-clarification and MROS reporting state for the account."
+msgstr "Der MROS-Meldestatus für das Konto."
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:118
+#, fuzzy
+#| msgid "Operation"
+msgid "Enumeration"
+msgstr "Vorgang"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:122
+#, fuzzy
+#| msgid "Sanctions-list best match"
+msgid "Sanction-list best match"
+msgstr "Beste Übereinstimmung auf der Sanktionsliste"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:123
+#, fuzzy
+#| msgid "Identifies the sanction list entry that the account matched against"
+msgid ""
+"Sanction-list entry that best matched the account, regardless of match "
+"quality."
+msgstr ""
+"Identifiziert den Sanktionslisteneintrag, mit dem das Konto übereinstimmte"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:128
+#, fuzzy
+#| msgid "Sanctions-list rating"
+msgid "Sanction-list rating"
+msgstr "Bewertung der Sanktionslistenübereinstimmung"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:129
+msgid "Score from 0 (no match) to 1,000,000,000 (best match)."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:130
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:136
+#, fuzzy
+#| msgid "Internal"
+msgid "Integer"
+msgstr "Intern"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:134
+#, fuzzy
+#| msgid "Sanctions-list confidence"
+msgid "Sanction-list confidence"
+msgstr "Konfidenz der Sanktionslistenübereinstimmung"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:135
+msgid ""
+"Score from 0 (no supporting data) to 1,000,000,000 (highest confidence)."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:140
+#, fuzzy
+#| msgid "Suppress sanctions-list match"
+msgid "Suppress sanction-list match"
+msgstr "Sanktionslistenübereinstimmung unterdrücken"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:141
+msgid ""
+"Whether this account's sanction-list hit is treated as a false positive."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:148
+#, fuzzy
+#| msgid "Account open"
+msgid "Account opened"
+msgstr "Konto eröffnet"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:149
+msgid "Recorded when an account changes to open."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:153
+#, fuzzy
+#| msgid "Account case"
+msgid "Account closed"
+msgstr "Kontofall"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:154
+msgid "Recorded when an account changes from open to closed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:158
+#, fuzzy
+#| msgid "High-risk customer"
+msgid "High-risk customer classification added"
+msgstr "Hochrisikokunde"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:159
+msgid ""
+"Recorded when an open account becomes classified as a high-risk customer."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:163
+#, fuzzy
+#| msgid "High-risk customer"
+msgid "High-risk customer classification removed"
+msgstr "Hochrisikokunde"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:164
+msgid "Recorded when the high-risk customer classification is removed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:168
+#, fuzzy
+#| msgid "High-risk country"
+msgid "High-risk country classification added"
+msgstr "Hochrisikoland"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:169
+msgid ""
+"Recorded when an open account becomes associated with a high-risk country."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:173
+msgid "High-risk country classification removed"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:174
+msgid "Recorded when the high-risk country classification is removed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:178
+msgid "PEP classification added"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:179
+msgid "Recorded when an open account becomes associated with any PEP category."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:183
+#, fuzzy
+#| msgid "No justification was recorded."
+msgid "PEP classification removed"
+msgstr "Es wurde keine Begründung erfasst."
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:184
+msgid ""
+"Recorded when the account is no longer associated with any PEP category."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:188
+msgid "Foreign PEP classification added"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:189
+msgid "Recorded when an open account becomes associated with a foreign PEP."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:193
+msgid "Foreign PEP classification removed"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:194
+msgid "Recorded when the foreign PEP classification is removed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:198
+msgid "Domestic PEP classification added"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:199
+msgid "Recorded when an open account becomes associated with a domestic PEP."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:203
+msgid "Domestic PEP classification removed"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:204
+msgid "Recorded when the domestic PEP classification is removed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:208
+#, fuzzy
+#| msgid "International-organization PEP"
+msgid "International-organization PEP classification added"
+msgstr "PEP einer internationalen Organisation"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:209
+#, fuzzy
+#| msgid "Does account belong to an international-organization PEP?"
+msgid ""
+"Recorded when an open account becomes associated with an international-"
+"organization PEP."
+msgstr "Gehört das Konto zu einer PEP einer internationalen Organisation?"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:213
+#, fuzzy
+#| msgid "International-organization PEP"
+msgid "International-organization PEP classification removed"
+msgstr "PEP einer internationalen Organisation"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:214
+msgid ""
+"Recorded when the international-organization PEP classification is removed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:218
+msgid "Simple suspicion reported to MROS"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:219
+msgid "Recorded when a report is filed under Article 305ter paragraph 2 StGB."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:223
+#, fuzzy
+#| msgid "Reported substantiated suspicion"
+msgid "Substantiated suspicion reported to MROS"
+msgstr "Begründeter Verdacht gemeldet"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:224
+msgid "Recorded when a report is filed under Article 9 GwG."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:228
+#, fuzzy
+#| msgid "Investigation trigger"
+msgid "Investigation concluded"
+msgstr "Auslöser der Untersuchung"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:229
+msgid "Recorded when a pending special clarification is concluded."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:233
+#, fuzzy
+#| msgid "Investigation trigger"
+msgid "Investigation conclusion reversed"
+msgstr "Auslöser der Untersuchung"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:234
+msgid ""
+"Recorded when a previously concluded investigation returns to a non-"
+"concluded state."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:50
+msgid "Browser override"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:52
+#, fuzzy
+#| msgid "Welcome to the exchange configuration"
+msgid "Exchange configuration"
+msgstr "Willkommen bei der Exchange-Konfiguration"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:53
+#, fuzzy
+#| msgid "Default rules"
+msgid "Default fallback"
+msgstr "Standardregeln"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:59
+#, fuzzy
+#| msgid "Welcome to the exchange configuration"
+msgid "Exchange and AML configuration"
+msgstr "Willkommen bei der Exchange-Konfiguration"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:62
+msgid ""
+"Exchange identity, the active AML dialect, and the checks and programs "
+"available to AML decisions."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:71
+msgid "Public information reported by this exchange."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:75
+msgid "Base URL"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:76
+msgid "Protocol"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:77
+msgid "Protocol version"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:78
+#, fuzzy
+#| msgid "Operation"
+msgid "Implementation"
+msgstr "Vorgang"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:80
+#, fuzzy
+#| msgid "Not opened"
+msgid "Not reported"
+msgstr "Nicht eröffnet"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:82
+msgid "Currency"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:88
+msgid "AML dialect"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:95
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:119
+#, fuzzy
+#| msgid "Effective decision"
+msgid "Effective dialect"
+msgstr "Wirksame Entscheidung"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:111
+#, fuzzy
+#| msgid "Configure measure"
+msgid "Configured dialect"
+msgstr "Maßnahme konfigurieren"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:114
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:504
+#, fuzzy
+#| msgid "Not opened"
+msgid "Not specified"
+msgstr "Nicht eröffnet"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:129
+msgid "Canonical properties defined by the effective dialect."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:130
+#, fuzzy
+#| msgid "No account properties"
+msgid "This dialect does not define account properties."
+msgstr "Keine Kontoeigenschaften"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:136
+#, fuzzy
+#| msgid "Reset to default"
+msgid "Derived events"
+msgstr "Auf Standard zurücksetzen"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:137
+#, fuzzy
+#| msgid "No account properties"
+msgid "Canonical events derived from account property changes."
+msgstr "Keine Kontoeigenschaften"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:138
+msgid "This dialect does not define derived events."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:144
+#, fuzzy
+#| msgid "All measures"
+msgid "AML measures"
+msgstr "Alle Maßnahmen"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:145
+msgid ""
+"Checks, programs, root measures, and default rules reported by the exchange."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:213
+#, fuzzy
+#| msgctxt "threshold"
+#| msgid "%1$s every %2$s"
+msgid "%1$s entry"
+msgstr "%1$s alle %2$s"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:214
+msgid "%1$s entries"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:277
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:289
+#, fuzzy
+msgid "Failed to load the exchange AML measures."
+msgstr "Aktuell aktive Maßnahmen"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:300
+#, fuzzy
+#| msgid "The measures endpoint was not found."
+msgid "The measures endpoint is not available."
+msgstr "Der Endpunkt für Maßnahmen wurde nicht gefunden."
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:306
+#, fuzzy
+#| msgid "The account state changed. Reload it and try again."
+msgid "The exchange configuration changed. Reload it and try again."
+msgstr ""
+"Der Kontostatus hat sich geändert. Laden Sie das Konto neu und versuchen Sie "
+"es erneut."
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:332
+#, fuzzy
+#| msgid "Required measures"
+msgid "Retry loading measures"
+msgstr "Erforderliche Maßnahmen"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:351
+#, fuzzy
+#| msgid "Reset measure"
+msgid "Root measures"
+msgstr "Maßnahme zurücksetzen"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:366
+msgid "No root measures are configured."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:371
+#, fuzzy
+#| msgid "Check"
+msgid "KYC checks"
+msgstr "Überprüfen"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:386
+msgid "No KYC checks are configured."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:391
+#, fuzzy
+#| msgid "Program"
+msgid "AML programs"
+msgstr "Programm"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:405
+#, fuzzy
+#| msgid "Requirements"
+msgid "Required inputs"
+msgstr "Anforderungen"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:413
+msgid "No AML programs are configured."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:428
+msgid "No default AML rules are configured."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:480
+#, fuzzy
+#| msgid "Check"
+msgid "KYC check"
+msgstr "Überprüfen"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:484
+msgid "Built-in check that proceeds without collecting customer data."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:491
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:497
+#, fuzzy
+#| msgid "Program"
+msgid "AML program"
+msgstr "Programm"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:536
+#, fuzzy
+#| msgid "All measures"
+msgid "Fallback measure"
+msgstr "Alle Maßnahmen"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:602
+#, fuzzy
+#| msgid "Unavailable"
+msgid "Unavailable reference"
+msgstr "Nicht verfügbar"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:48
+msgid "Session and access"
+msgstr "Sitzung und Zugriff"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:51
+msgid ""
+"Review this officer's exchange access and manage the unlocked key in this "
+"browser."
+msgstr ""
+"Überprüfen Sie den Exchange-Zugriff dieses Sachbearbeiters und verwalten Sie "
+"den entsperrten Schlüssel in diesem Browser."
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:66
+msgid "Officer access"
+msgstr "Sachbearbeiterzugriff"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:71
+msgid "Officer name"
+msgstr "Name des Sachbearbeiters"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:77
+msgid "Permissions"
+msgstr "Berechtigungen"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:88
+msgid "Read-only"
+msgstr "Nur lesen"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:90
+msgid "Read and write"
+msgstr "Lesen und Schreiben"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:118
+msgid "Session security"
+msgstr "Sitzungssicherheit"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:121
+msgid "Lock the session when you leave this device unattended."
+msgstr "Sperren Sie die Sitzung, wenn Sie dieses Gerät unbeaufsichtigt lassen."
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:133
+msgid "Lock now"
+msgstr "Jetzt sperren"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:148
+msgid "Unlocked"
+msgstr "Entsperrt"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:154
+msgid "Locks automatically"
+msgstr "Automatische Sperre"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:165
+msgid "Exact time"
+msgstr "Genauer Zeitpunkt"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:185
+msgid "Copy public key"
+msgstr "Öffentlichen Schlüssel kopieren"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:200
+msgid "Remove key from this browser"
+msgstr "Schlüssel aus diesem Browser entfernen"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:203
+msgid ""
+"Removing this key deletes the officer key from this browser. It does not "
+"revoke or change the officer's access at the exchange. Ask the exchange "
+"operator to revoke access if needed."
+msgstr ""
+"Durch das Entfernen dieses Schlüssels wird der Sachbearbeiterschlüssel aus "
+"diesem Browser gelöscht. Der Zugriff des Sachbearbeiters beim Exchange wird "
+"dadurch weder widerrufen noch geändert. Bitten Sie den Exchange-Betreiber "
+"bei Bedarf, den Zugriff zu widerrufen."
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:214
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:222
+msgid "Remove key"
+msgstr "Schlüssel entfernen"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:221
+msgid "Remove officer key?"
+msgstr "Sachbearbeiterschlüssel entfernen?"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:231
+msgid ""
+"This deletes the officer key from this browser. You will need to create and "
+"enroll a new key to use the AML WebUI here again."
+msgstr ""
+"Hierdurch wird der Sachbearbeiterschlüssel aus diesem Browser gelöscht. Sie "
+"müssen einen neuen Schlüssel erstellen und registrieren lassen, um die AML-"
+"Weboberfläche hier erneut zu verwenden."
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:237
+msgid ""
+"This does not revoke the officer at the exchange. Ask the exchange operator "
+"to revoke its access if the key may be compromised."
+msgstr ""
+"Der Sachbearbeiter wird dadurch beim Exchange nicht widerrufen. Bitten Sie "
+"den Exchange-Betreiber, seinen Zugriff zu widerrufen, wenn der Schlüssel "
+"möglicherweise kompromittiert wurde."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:86
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:559
+msgid "Find account"
+msgstr "Konto suchen"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:89
+msgid "Look up an account by its payto information or normalized payto hash."
+msgstr ""
+"Suchen Sie ein Konto anhand seiner Payto-Informationen oder seines "
+"normalisierten Payto-Hashs."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:100
+msgid "Find by payto"
+msgstr "Nach Payto suchen"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:146
+msgid "Find by normalized payto hash"
+msgstr "Nach normalisiertem Payto-Hash suchen"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:169
+msgid "Enter a valid 52-character normalized payto hash."
+msgstr "Geben Sie einen gültigen normalisierten Payto-Hash mit 52 Zeichen ein."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:179
+msgid "Open account"
+msgstr "Konto öffnen"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:214
+msgid "Failed to load account decisions."
+msgstr "Kontoentscheidungen konnten nicht geladen werden."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:223
+msgid "Failed to load the account history."
+msgstr "Der Kontoverlauf konnte nicht geladen werden."
+
+#. screenid: 111
+#. screenid: 110
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:228
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:82
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:268
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:66
+msgid ""
+"This session signature is invalid, contact administrator or create a new one."
+msgstr ""
+"Die Signatur dieser Sitzung ist ungültig. Wenden Sie sich an den "
+"Administrator oder erstellen Sie eine neue Sitzung."
+
+#. screenid: 111
+#. screenid: 110
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:235
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:89
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:275
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:73
+msgid ""
+"The designated AML session is not known, contact administrator or create a "
+"new one."
+msgstr ""
+"Die angegebene AML-Sitzung ist nicht bekannt. Wenden Sie sich an den "
+"Administrator oder erstellen Sie eine neue Sitzung."
+
+#. screenid: 111
+#. screenid: 110
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:242
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:96
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:282
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:80
+msgid ""
+"The designated AML session is not enabled, contact administrator or create a "
+"new one."
+msgstr ""
+"Die angegebene AML-Sitzung ist nicht aktiviert. Wenden Sie sich an den "
+"Administrator oder erstellen Sie eine neue Sitzung."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:268
+#, fuzzy
+#| msgid "Account not found"
+msgid "Account found"
+msgstr "Konto nicht gefunden"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:271
+msgid ""
+"This account has an AML decision history. Open its case to review current "
+"rules, measures, attributes, and past decisions."
+msgstr ""
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:283
+#, fuzzy
+#| msgid "Open account"
+msgid "Open account case"
+msgstr "Konto öffnen"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:309
+msgid "Active"
+msgstr ""
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:311
+#, fuzzy
+#| msgid "Effective decision"
+msgid "No active decision"
+msgstr "Wirksame Entscheidung"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:317
+#, fuzzy
+#| msgid "File status"
+msgid "Case status"
+msgstr "Aktenstatus"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:321
+#, fuzzy
+#| msgid "Investigation trigger"
+msgid "Investigation required"
+msgstr "Auslöser der Untersuchung"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:323
+#, fuzzy
+#| msgid "Investigation state"
+msgid "No investigation requested"
+msgstr "Untersuchungsstatus"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:333
+msgid "Account not found"
+msgstr "Konto nicht gefunden"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:335
+msgid "There is no history known for this account yet."
+msgstr "Für dieses Konto ist noch kein Verlauf bekannt."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:350
+#, fuzzy
+#| msgid "You can make a decision for this account anyway."
+msgid "Start a decision for this account"
+msgstr "Sie können trotzdem eine Entscheidung für dieses Konto treffen."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:403
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:445
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:493
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:533
+msgid "Search"
+msgstr "Suchen"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:575
+msgid "Taler Bank"
+msgstr "Taler-Bank"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:579
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:364
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:433
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:441
+msgid "Wallet"
+msgstr "Wallet"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:583
+msgid "Generic Payto:// URI"
+msgstr "Allgemeine Payto://-URI"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:586
+msgid "Account type"
+msgstr "Kontotyp"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:596
+msgid "Should be 52 characters."
+msgstr "Sollte 52 Zeichen haben."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:598
+msgid "Failed to parse: %1$s"
+msgstr "Konnte nicht geparst werden: %1$s"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:610
+msgid "Address contains invalid characters."
+msgstr "Die Adresse enthält ungültige Zeichen."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:612
+msgid "Can't mix uppercased and lowercased characters."
+msgstr "Groß- und Kleinbuchstaben dürfen nicht gemischt werden."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:614
+msgid "The addr checksum doesn't match."
+msgstr "Die Adress-Prüfsumme stimmt nicht überein."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:616
+msgid "Missing separator or address type."
+msgstr "Trennzeichen oder Adresstyp fehlt."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:618
+msgid "Address should have less than 90 characters."
+msgstr "Die Adresse sollte weniger als 90 Zeichen haben."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:620
+msgid "Address should have more than 6 characters."
+msgstr "Die Adresse sollte mehr als 6 Zeichen haben."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:622
+msgid "Decoding issue."
+msgstr "Dekodierungsfehler."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:624
+msgid "Invalid data"
+msgstr "Ungültige Daten"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:634
+msgid "Unsupported country."
+msgstr "Nicht unterstütztes Land."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:636
+msgid "IBANs have fewer than 34 characters."
+msgstr "IBANs haben weniger als 34 Zeichen."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:638
+msgid "IBANs have more than 4 characters."
+msgstr "IBANs haben mehr als 4 Zeichen."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:640
+msgid "IBAN length is invalid for this country."
+msgstr "Die IBAN-Länge ist für dieses Land ungültig."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:642
+msgid "It should only contain numbers and letters."
+msgstr "Es sollte nur Zahlen und Buchstaben enthalten."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:644
+msgid "The checksum is wrong."
+msgstr "Die Prüfsumme ist falsch."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:662
+msgid "The string should start with payto://"
+msgstr "Die Zeichenfolge sollte mit payto:// beginnen"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:664
+msgid "After the target type it should follow a '/' with more information."
+msgstr "Nach dem Zieltyp sollte ein '/' mit weiteren Informationen folgen."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:666
+msgid ""
+"The target type is not supported, only x-taler-bank, taler-reserve or iban"
+msgstr ""
+"Der Zieltyp wird nicht unterstützt, nur x-taler-bank, taler-reserve oder iban"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:671
+msgid "IBAN is missing"
+msgstr "IBAN fehlt"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:673
+msgid "Bitcoin address is missing"
+msgstr "Bitcoin-Adresse fehlt"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:675
+msgid "Bank host and account is missing"
+msgstr "Bank-Host und Konto fehlen"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:677
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:679
+msgid "Exchange host and account is missing"
+msgstr "Exchange-Host und Konto fehlen"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:681
+msgid "Ethereum address is missing"
+msgstr "Ethereum-Adresse fehlt"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:683
+msgid "Cyclos address is missing"
+msgstr "Cyclos-Adresse fehlt"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:685
+msgid "Void address is missing"
+msgstr "Die Void-Adresse fehlt"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:693
+msgid "Invalid IBAN: %1$s"
+msgstr "Ungültige IBAN: %1$s"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:700
+msgid "Invalid BTC: %1$s"
+msgstr "Ungültige BTC-Adresse: %1$s"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:705
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:728
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:741
+msgid "Invalid reserve: %1$s"
+msgstr "Ungültige Reserve: %1$s"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:716
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:726
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:739
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:760
+msgid "Invalid host"
+msgstr "Ungültiger Host"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:718
+msgid "Invalid account"
+msgstr "Ungültiges Konto"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:752
+msgid "Invalid address"
+msgstr "Ungültige Adresse"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:791
+msgid "As defined by RFC 8905"
+msgstr "Wie in RFC 8905 definiert"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:792
+msgid "payto://"
+msgstr "payto://"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:807
+msgid "International Bank Account Number"
+msgstr "Internationale Bankkontonummer"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:808
+msgid "DE1231231231"
+msgstr "DE1231231231"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:820
+msgid "Host"
+msgstr "Host"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:821
+msgid "Exchange hostname"
+msgstr "Exchange-Hostname"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:822
+msgid "exchange.taler.net"
+msgstr "exchange.taler.net"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:827
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:874
+msgid "Remove last '/'"
+msgstr "Letztes '/' entfernen"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:829
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:846
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:426
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:472
+msgid "Invalid value"
+msgstr "Ungültiger Wert"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:837
+msgid "ID"
+msgstr "ID"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:838
+msgid "Wallet reserve public key"
+msgstr "Öffentlicher Reserveschlüssel der Wallet"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:839
+msgid "abcdef1235"
+msgstr "abcdef1235"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:844
+msgid "Should be 52 characters"
+msgstr "Sollte 52 Zeichen haben"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:860
+msgid "Bank account identification"
+msgstr "Bankkontokennung"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:861
+msgid "DE123123123"
+msgstr "DE123123123"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:867
+msgid "Hostname"
+msgstr "Hostname"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:868
+msgid "Without the scheme, may include subpath: bank.com, bank.com/path/"
+msgstr "Ohne Schema, kann Unterpfad enthalten: bank.com, bank.com/path/"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:869
+msgid "bank.demo.taler.net"
+msgstr "bank.demo.taler.net"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:876
+msgid "Invalid hostname"
+msgstr "Ungültiger Hostname"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:68
+msgid "Failed to load account information."
+msgstr "Kontoinformationen konnten nicht geladen werden."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:77
+msgid "Failed to load the account information."
+msgstr ""
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:115
+msgid "Collection event not found"
+msgstr "Erfassungsereignis nicht gefunden"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:117
+msgid "There is no collection event with ID %1$s for this account."
+msgstr "Für dieses Konto gibt es kein Erfassungsereignis mit der ID %1$s."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:129
+msgid "Attributes unavailable"
+msgstr "Attribute nicht verfügbar"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:131
+msgid "The collection event does not contain readable attributes."
+msgstr "Das Erfassungsereignis enthält keine lesbaren Attribute."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:148
+msgid "Form identifier missing"
+msgstr "Formular-ID fehlt"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:150
+msgid "The collected information does not identify the form used to create it."
+msgstr ""
+"Die erfassten Informationen geben nicht an, mit welchem Formular sie "
+"erstellt wurden."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:165
+msgid "Form not available"
+msgstr "Formular nicht verfügbar"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:167
+msgid "Form %1$s is not configured in this AML Web UI."
+msgstr "Das Formular %1$s ist in dieser AML-Weboberfläche nicht konfiguriert."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:255
+#, fuzzy
+#| msgid "Collected information"
+msgid "Collected AML/KYC information"
+msgstr "Erfasste Informationen"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:262
+#, fuzzy
+#| msgid "Forms"
+msgid "Form"
+msgstr "Formulare"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:267
+#, fuzzy
+#| msgid "Collected information"
+msgid "Collected"
+msgstr "Erfasste Informationen"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:270
+msgid "Source"
+msgstr ""
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:274
+#, fuzzy
+#| msgid "Custom properties"
+msgid "Customer process"
+msgstr "Benutzerdefinierte Eigenschaften"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:277
+#, fuzzy
+#| msgid "Events"
+msgid "Event ID"
+msgstr "Ereignisse"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:284
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:292
+msgid "Different form version"
+msgstr "Andere Formularversion"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:285
+msgid ""
+"The collected information does not identify the form version used. The "
+"latest configured version is shown and field labels may differ from those "
+"used at collection time."
+msgstr ""
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:293
+#, fuzzy
+#| msgid "Form %1$s is not configured in this AML Web UI."
+msgid ""
+"Form version %1$s is not configured in this AML Web UI. Version %2$s is "
+"shown and field labels may differ."
+msgstr "Das Formular %1$s ist in dieser AML-Weboberfläche nicht konfiguriert."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:301
+#, fuzzy
+#| msgid "Collected information"
+msgid "Collected information events"
+msgstr "Erfasste Informationen"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:305
+#, fuzzy
+#| msgid "Next event"
+msgid "Older event"
+msgstr "Nächstes Ereignis"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:316
+#, fuzzy
+#| msgid "Next event"
+msgid "Newer event"
+msgstr "Nächstes Ereignis"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:329
+#, fuzzy
+#| msgid "Invalid attributes"
+msgid "Submitted values"
+msgstr "Ungültige Attribute"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:369
+#, fuzzy
+#| msgid "Officer name"
+msgid "Officer view"
+msgstr "Name des Sachbearbeiters"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:371
+#, fuzzy
+#| msgid "Customer-visible"
+msgid "Customer view"
+msgstr "Für Kunden sichtbar"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:372
+msgid "JSON view"
+msgstr ""
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:403
+#, fuzzy
+#| msgid "System information"
+msgid "Submitted information view"
+msgstr "Systeminformation"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:109
+msgid "Incoming"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:113
+msgid "Outgoing"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:117
+msgid "KYC authorization"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:127
+msgid "Wallet credits (P2P)"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:140
+#, fuzzy
+#| msgid "Transfers history"
+msgid "Transfer category"
+msgstr "Überweisungsverlauf"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:147
+msgid "Minimum amount"
+msgstr "Mindestbetrag"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:148
+msgid "All amounts below the given threshold will be filtered."
+msgstr ""
+"Alle Beträge unterhalb des angegebenen Schwellenwerts werden ausgefiltert."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:182
+#, fuzzy
+#| msgid "Exchange hostname"
+msgid "Exchange transfer activity"
+msgstr "Exchange-Hostname"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:188
+#, fuzzy
+#| msgid "Transfers history"
+msgid "Wallet credit activity"
+msgstr "Überweisungsverlauf"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:190
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:198
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:241
+#, fuzzy
+#| msgid "Transfers history"
+msgid "Transfer activity"
+msgstr "Überweisungsverlauf"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:196
+#, fuzzy
+#| msgid "Transfers history for account"
+msgid "Transfer activity for account"
+msgstr "Überweisungsverlauf für Konto"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:204
+msgid ""
+"Inspect successful P2P credits received by this wallet. Requests that were "
+"not paid are not shown."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:209
+msgid ""
+"Inspect effective bank transfers observed by the exchange. Credit transfers "
+"are incoming, debit transfers are outgoing, and bounced or drain transfers "
+"are not included."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:215
+msgid ""
+"Inspect effective transfers observed by the exchange. Incoming, outgoing, "
+"and KYC authorization entries are bank transfers. Wallet credits are "
+"successful P2P transfers into wallets."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:233
+#, fuzzy
+#| msgid "Transfers history"
+msgid "Transfer filters"
+msgstr "Überweisungsverlauf"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:254
+#, fuzzy
+msgid "Failed to load transfer list."
+msgstr "Konnte nicht geparst werden: %1$s"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:263
+msgid "Failed to load the transfer list."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:299
+msgid "Select transaction type"
+msgstr "Transaktionstyp auswählen"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:300
+msgid "Please select a transaction type to show transactions."
+msgstr ""
+"Bitte wählen Sie einen Transaktionstyp aus, um Transaktionen anzuzeigen."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:314
+#, fuzzy
+#| msgid "No transfers yet."
+msgid "No wallet credits yet."
+msgstr "Noch keine Überweisungen."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:315
+msgid "No transfers yet."
+msgstr "Noch keine Überweisungen."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:319
+#, fuzzy
+#| msgid "There are no transfers for this account."
+msgid "There are no P2P credits for this wallet."
+msgstr "Für dieses Konto gibt es keine Überweisungen."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:323
+#, fuzzy
+#| msgid ""
+#| "There are no transfers reported to the exchange with the current "
+#| "threshold."
+msgid ""
+"There are no wallet credits reported to the exchange with the current "
+"threshold."
+msgstr ""
+"Es wurden dem Exchange bei dem aktuellen Schwellenwert keine Überweisungen "
+"gemeldet."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:328
+msgid "There are no transfers for this account."
+msgstr "Für dieses Konto gibt es keine Überweisungen."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:332
+msgid ""
+"There are no transfers reported to the exchange with the current threshold."
+msgstr ""
+"Es wurden dem Exchange bei dem aktuellen Schwellenwert keine Überweisungen "
+"gemeldet."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:343
+msgid "Unknown date"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:355
+msgid "Time"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:359
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:406
+msgid "Amount"
+msgstr "Betrag"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:393
+msgid "Unknown time"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:410
+#, fuzzy
+#| msgid "Credit"
+msgid "credited"
+msgstr "Guthaben"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:412
+msgid "sent"
+msgstr "gesendet"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:413
+msgid "received"
+msgstr "erhalten"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:443
+msgid "to"
+msgstr "an"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:444
+msgid "from"
+msgstr "von"
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:165
+msgid "This exchange is not compatible with the AML WebUI."
+msgstr "Dieser Exchange ist nicht mit der AML-WebUI kompatibel."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:167
+msgid ""
+"Officer identity and permissions require exchange protocol v40 or newer."
+msgstr ""
+"Identität und Berechtigungen des Sachbearbeiters erfordern Exchange-"
+"Protokoll v40 oder neuer."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:191
+msgid "Verifying that this public key is enrolled by the exchange."
+msgstr ""
+"Es wird geprüft, ob dieser öffentliche Schlüssel beim Exchange registriert "
+"ist."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:278
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:331
+msgid "Read-only officer access"
+msgstr "Lesezugriff für Sachbearbeiter"
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:279
+msgid ""
+"You can review AML information, but this officer key cannot submit decisions."
+msgstr ""
+"Sie können AML-Informationen prüfen, aber dieser Sachbearbeiterschlüssel "
+"kann keine Entscheidungen einreichen."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:332
+msgid "This officer key cannot create or submit AML decisions."
+msgstr ""
+"Dieser Sachbearbeiterschlüssel kann keine AML-Entscheidungen erstellen oder "
+"einreichen."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:340
+msgid "Return to account"
+msgstr "Zum Konto zurückkehren"
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:466
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:475
+msgid "Failed to load the active AML decision."
+msgstr "Die aktive AML-Entscheidung konnte nicht geladen werden."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:484
+msgid "The account was not found."
+msgstr "Das Konto wurde nicht gefunden."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:488
+msgid "The account state changed. Reload it and try again."
+msgstr ""
+"Der Kontostatus hat sich geändert. Laden Sie das Konto neu und versuchen Sie "
+"es erneut."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:511
+msgid ""
+"The payto URI does not belong to this account. Return to the account search "
+"and start the decision again."
+msgstr ""
+"Die Payto-URI gehört nicht zu diesem Konto. Kehren Sie zur Kontosuche zurück "
+"und beginnen Sie die Entscheidung erneut."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:571
+#, fuzzy
+#| msgid "AML navigation"
+msgid "AML configuration"
+msgstr "AML-Navigation"
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:577
+msgid "Session"
+msgstr "Sitzung"
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:585
+msgid "AML navigation"
+msgstr "AML-Navigation"
+
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:49
+#, fuzzy
+msgid "Failed to load server measures."
+msgstr "Server-Maßnahmen"
+
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:61
+#, fuzzy
+msgid "Failed to load the measures"
+msgstr "Aktuell aktive Maßnahmen"
+
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:102
+msgid "Measures"
+msgstr "Maßnahmen"
+
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:105
+#, fuzzy
+msgid "A list of all the predefined measures you can use."
+msgstr ""
+"Eine Liste aller vordefinierten Maßnahmen, die verwendet werden können."
+
+#~ msgid "AML officer justification"
+#~ msgstr "Begründung des AML-Sachbearbeiters"
+
+#~ msgid "Effective policy"
+#~ msgstr "Wirksame Richtlinie"
+
+#~ msgid "Account assessment"
+#~ msgstr "Kontobewertung"
+
+#~ msgid "Properties recorded by AML officers for this account."
+#~ msgstr "Von AML-Sachbearbeitern für dieses Konto erfasste Eigenschaften."
+
+#~ msgid "Account assessment could not be loaded"
+#~ msgstr "Die Kontobewertung konnte nicht geladen werden"
+
+#~ msgid "No assessment properties have been recorded for this account."
+#~ msgstr "Für dieses Konto wurden keine Bewertungseigenschaften erfasst."
+
+#~ msgid "Currently applied rules"
+#~ msgstr "Aktuell angewendete Regeln"
+
+#~ msgid ""
+#~ "This account has no account-specific decision. The exchange default rules "
+#~ "currently apply."
+#~ msgstr ""
+#~ "Für dieses Konto gibt es keine kontospezifische Entscheidung. Derzeit "
+#~ "gelten die Standardregeln der Börse."
+
+#, fuzzy
+#~ msgid "Keep case under investigation"
+#~ msgstr "Nicht in Untersuchung"
+
+#~ msgid "Account views"
+#~ msgstr "Kontoansichten"
+
+#~ msgid "Date"
+#~ msgstr "Datum"
+
+#~ msgid "Show transfers"
+#~ msgstr "Überweisungen anzeigen"
+
+#, fuzzy
+#~ msgid "View decision history"
+#~ msgstr "Entscheidungsverlauf"
+
+#~ msgid "Save PDF"
+#~ msgstr "PDF speichern"
+
+#~ msgid "Manual review required"
+#~ msgstr "Manuelle Prüfung erforderlich"
+
+#~ msgid "At a glance"
+#~ msgstr "Auf einen Blick"
+
+#~ msgid "Requirements present"
+#~ msgstr "Anforderungen vorhanden"
+
+#~ msgid "Current assessment and policy"
+#~ msgstr "Aktuelle Bewertung und Richtlinie"
+
+#~ msgid "The current account properties and effective AML rules."
+#~ msgstr "Die aktuellen Kontoeigenschaften und wirksamen AML-Regeln."
+
+#, fuzzy
+#~ msgid "Property"
+#~ msgstr "Eigenschaften"
+
+#~ msgid "The officer session signature is invalid."
+#~ msgstr "Die Signatur der Sitzung des AML-Sachbearbeiters ist ungültig."
+
+#~ msgid "The requested AML account was not found."
+#~ msgstr "Das angeforderte AML-Konto wurde nicht gefunden."
+
+#~ msgid "The officer session is disabled or the account state changed."
+#~ msgstr ""
+#~ "Die Sitzung des AML-Sachbearbeiters ist deaktiviert oder der Kontostatus "
+#~ "hat sich geändert."
+
+#, fuzzy
+#~ msgid "Account audit trail"
+#~ msgstr "Kontofilter"
+
+#~ msgid "(all)"
+#~ msgstr "(alle)"
+
+#~ msgid "Info"
+#~ msgstr "Info"
+
+#~ msgid "Will show information to the user."
+#~ msgstr "Zeigt dem Benutzer Informationen an."
+
+#~ msgid ""
+#~ "The account isn't a wallet and there are wallet operation's limits which "
+#~ "may trigger actions that are not required: %1$s"
+#~ msgstr ""
+#~ "Das Konto ist keine Wallet, und es bestehen Limits für Wallet-Vorgänge, "
+#~ "die möglicherweise nicht erforderliche Aktionen auslösen: %1$s"
+
+#~ msgid ""
+#~ "The account is a wallet and there are wallet operation's limits which are "
+#~ "not limited: %1$s"
+#~ msgstr ""
+#~ "Das Konto ist eine Wallet, und es bestehen Limits für Wallet-Vorgänge, "
+#~ "die nicht begrenzt sind: %1$s"
+
+#~ msgid "New rules"
+#~ msgstr "Neue Regeln"
+
+#~ msgid "Set rules to default"
+#~ msgstr "Regeln auf Standard setzen"
+
+#~ msgid "Behavior on rule expiration"
+#~ msgstr "Verhalten bei Ablauf der Regel"
+
+#~ msgid ""
+#~ "Events based on properties and new attributes that should be triggered"
+#~ msgstr ""
+#~ "Ereignisse, die auf Grundlage von Eigenschaften und neuen Attributen "
+#~ "ausgelöst werden sollen"
+
+#~ msgid "Others"
+#~ msgstr "Sonstige"
+
+#~ msgid "Custom list"
+#~ msgstr "Benutzerdefinierte Liste"
+
+#~ msgid "Events without built-in support."
+#~ msgstr "Ereignisse ohne integrierte Unterstützung."
+
+#~ msgid "These measures will ask the customer for information."
+#~ msgstr ""
+#~ "Diese Maßnahmen fordern den Kunden zur Angabe von Informationen auf."
+
+#~ msgid ""
+#~ "Select a form to submit new information about the customer or continue to "
+#~ "the next step"
+#~ msgstr ""
+#~ "Wählen Sie ein Formular aus, um neue Informationen über den Kunden zu "
+#~ "übermitteln, oder fahren Sie mit dem nächsten Schritt fort"
+
+#~ msgid "Form:"
+#~ msgstr "Formular:"
+
+#~ msgid "Keep investigation?"
+#~ msgstr "Untersuchung beibehalten?"
+
+#~ msgid "Full name of the account holder"
+#~ msgstr "Vollständiger Name des Kontoinhabers"
+
+#~ msgid "Update"
+#~ msgstr "Aktualisieren"
+
+#~ msgid "Remove"
+#~ msgstr "Entfernen"
+
+#~ msgid "Show complete form"
+#~ msgstr "Vollständiges Formular anzeigen"
+
+#~ msgid "Show as verification"
+#~ msgstr "Als Verifizierung anzeigen"
+
+#~ msgid "Only required when no check is specified"
+#~ msgstr "Nur erforderlich, wenn keine Prüfung angegeben ist"
+
+#~ msgid "Without a check the program will run automatically"
+#~ msgstr "Ohne Prüfung wird das Programm automatisch ausgeführt"
+
+#~ msgid "It should be a number"
+#~ msgstr "Es sollte eine Zahl sein"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:775
-msgid "Host"
-msgstr "Host"
+#~ msgid "It should be a safe integer"
+#~ msgstr "Es sollte eine sichere Ganzzahl sein"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:776
-msgid "Exchange hostname"
-msgstr "Exchange-Hostname"
+#~ msgid "Server measures"
+#~ msgstr "Server-Maßnahmen"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:777
-msgid "exchange.taler.net"
-msgstr "exchange.taler.net"
+#~ msgid "New measures"
+#~ msgstr "Neue Maßnahmen"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:782
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:829
-msgid "Remove last '/'"
-msgstr "Letztes '/' entfernen"
+#~ msgid ""
+#~ "Measures that are available/executed directly after the decision is "
+#~ "confirmed."
+#~ msgstr ""
+#~ "Maßnahmen, die direkt nach Bestätigung der Entscheidung verfügbar sind/"
+#~ "ausgeführt werden."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:784
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:801
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:332
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:376
-msgid "Invalid value"
-msgstr "Ungültiger Wert"
+#, fuzzy
+#~ msgid ""
+#~ "The session is disabled or a more recent decision was already submitted."
+#~ msgstr ""
+#~ "Sachbearbeiter deaktiviert oder es wurde bereits eine neuere Entscheidung "
+#~ "übermittelt."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:792
-msgid "ID"
-msgstr "ID"
+#, fuzzy
+#~ msgid ""
+#~ "This decision declares that the MROS report has concluded. Please make "
+#~ "sure that this is the case"
+#~ msgstr ""
+#~ "Diese Entscheidung erklärt, dass die MROS-Meldung abgeschlossen ist. "
+#~ "Bitte stellen Sie sicher, dass dies zutrifft"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:793
-msgid "Wallet reserve public key"
-msgstr "Öffentlicher Reserveschlüssel der Wallet"
+#~ msgid "I want to check first!"
+#~ msgstr "Ich möchte zuerst prüfen!"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:794
-msgid "abcdef1235"
-msgstr "abcdef1235"
+#~ msgid ""
+#~ "Deadline should specify when this rules ends and what is the next "
+#~ "measures to apply after expiration."
+#~ msgstr ""
+#~ "Die Frist sollte angeben, wann diese Regel endet und welche Maßnahmen "
+#~ "nach Ablauf anzuwenden sind."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:799
-msgid "Should be 52 characters"
-msgstr "Sollte 52 Zeichen haben"
+#~ msgid "Can't make a decision without rules."
+#~ msgstr "Ohne Regeln kann keine Entscheidung getroffen werden."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:814
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:268
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:338
-msgid "Account"
-msgstr "Konto"
+#~ msgid "Missing active measure"
+#~ msgstr "Aktive Maßnahme fehlt"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:815
-msgid "Bank account identification"
-msgstr "Bankkontokennung"
+#~ msgid "You should specify in the measure section."
+#~ msgstr "Sie sollten dies im Abschnitt Maßnahmen angeben."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:816
-msgid "DE123123123"
-msgstr "DE123123123"
+#~ msgid "You should specify in the properties section."
+#~ msgstr "Sie sollten dies im Abschnitt Eigenschaften angeben."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:822
-msgid "Hostname"
-msgstr "Hostname"
+#~ msgid "You should specify in the events section."
+#~ msgstr "Sie sollten dies im Abschnitt Ereignisse angeben."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:823
-msgid "Without the scheme, may include subpath: bank.com, bank.com/path/"
-msgstr "Ohne Schema, kann Unterpfad enthalten: bank.com, bank.com/path/"
+#~ msgid "Missing justification"
+#~ msgstr "Begründung fehlt"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:824
-msgid "bank.demo.taler.net"
-msgstr "bank.demo.taler.net"
+#~ msgid ""
+#~ "You should check form errors or submit a decision without attributes."
+#~ msgstr ""
+#~ "Sie sollten Formularfehler prüfen oder eine Entscheidung ohne Attribute "
+#~ "übermitteln."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:831
-msgid "Invalid hostname"
-msgstr "Ungültiger Hostname"
+#~ msgid "Clear"
+#~ msgstr "Leeren"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:71
-msgid "Failed to load the account information."
-msgstr ""
+#~ msgid "Attributes"
+#~ msgstr "Attribute"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:198
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:204
-msgid "Different form version"
-msgstr "Andere Formularversion"
+#~ msgid "Add more information about the customer"
+#~ msgstr "Weitere Informationen über den Kunden hinzufügen"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:199
-msgid "The collected information don't have the form version used."
-msgstr ""
-"Die erfassten Informationen enthalten die verwendete Formularversion nicht."
+#~ msgid "Rules"
+#~ msgstr "Regeln"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:205
-msgid ""
-"The collected information used the form version \"%1$s \" but is not "
-"available."
-msgstr ""
-"Die erfassten Informationen verwendeten die Formularversion \"%1$s \", die "
-"jedoch nicht verfügbar ist."
+#~ msgid "Set the limit of the operations"
+#~ msgstr "Das Limit der Vorgänge festlegen"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:217
-msgid "Case details"
-msgstr "Falldetails"
+#~ msgid "Trigger notifications."
+#~ msgstr "Benachrichtigungen auslösen."
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:231
-msgid "Next event"
-msgstr "Nächstes Ereignis"
+#~ msgid "Ask the customer to take action."
+#~ msgstr "Den Kunden zum Handeln auffordern."
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:245
-msgid "Previous event"
-msgstr "Vorheriges Ereignis"
+#~ msgid "Flag the current account state."
+#~ msgstr "Den aktuellen Kontostatus markieren."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:66
-msgid "Direction"
-msgstr "Richtung"
+#~ msgid "loading..."
+#~ msgstr "wird geladen..."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:69
-msgid "Credit"
-msgstr "Guthaben"
+#~ msgid "Decision for wallet:"
+#~ msgstr "Entscheidung für Wallet:"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:73
-msgid "Debit"
-msgstr "Soll"
+#~ msgid "Check account details"
+#~ msgstr "Kontodetails überprüfen"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:77
-msgid "KYC Auth"
-msgstr "KYC-Authentifizierung"
+#~ msgid "Account most recent decisions"
+#~ msgstr "Jüngste Entscheidungen zum Konto"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:85
-msgid "Minimum amount"
-msgstr "Mindestbetrag"
+#~ msgid "When"
+#~ msgstr "Wann"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:86
-msgid "All amounts below the given threshold will be filtered."
-msgstr ""
-"Alle Beträge unterhalb des angegebenen Schwellenwerts werden ausgefiltert."
+#~ msgid "LATEST"
+#~ msgstr "NEUESTE"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:114
-#, fuzzy
-msgid "Failed to load transfer list."
-msgstr "Konnte nicht geparst werden: %1$s"
+#~ msgid "ACTIVE"
+#~ msgstr "AKTIV"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:123
-msgid "Failed to load the transfer list."
-msgstr ""
+#~ msgid "Requires investigation"
+#~ msgstr "Erfordert eine Untersuchung"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:160
-msgid "Select transaction type"
-msgstr "Transaktionstyp auswählen"
+#~ msgid "The collected information don't have the form version used."
+#~ msgstr ""
+#~ "Die erfassten Informationen enthalten die verwendete Formularversion "
+#~ "nicht."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:161
-msgid "Please select a transaction type to show transactions."
-msgstr ""
-"Bitte wählen Sie einen Transaktionstyp aus, um Transaktionen anzuzeigen."
+#~ msgid ""
+#~ "The collected information used the form version \"%1$s \" but is not "
+#~ "available."
+#~ msgstr ""
+#~ "Die erfassten Informationen verwendeten die Formularversion \"%1$s \", "
+#~ "die jedoch nicht verfügbar ist."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:176
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:234
-msgid "Transfers history for account"
-msgstr "Überweisungsverlauf für Konto"
+#~ msgid "Case details"
+#~ msgstr "Falldetails"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:188
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:246
-msgid "Transfers history"
-msgstr "Überweisungsverlauf"
+#~ msgid "Previous event"
+#~ msgstr "Vorheriges Ereignis"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:195
-msgid "No transfers yet."
-msgstr "Noch keine Überweisungen."
+#~ msgid "Direction"
+#~ msgstr "Richtung"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:197
-msgid "There are no transfers for this account."
-msgstr "Für dieses Konto gibt es keine Überweisungen."
+#~ msgid "Debit"
+#~ msgstr "Soll"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:201
-msgid ""
-"There are no transfers reported to the exchange with the current threshold."
-msgstr ""
-"Es wurden dem Exchange bei dem aktuellen Schwellenwert keine Überweisungen "
-"gemeldet."
+#~ msgid "KYC Auth"
+#~ msgstr "KYC-Authentifizierung"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:260
-msgid "Date"
-msgstr "Datum"
+#~ msgid "Previous AML decisions that are no longer active."
+#~ msgstr "Frühere AML-Entscheidungen, die nicht mehr aktiv sind."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:264
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:310
-msgid "Amount"
-msgstr "Betrag"
+#~ msgid "The account has no KYC information."
+#~ msgstr "Das Konto enthält keine KYC-Informationen."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:314
-msgid "sent"
-msgstr "gesendet"
+#~ msgid "Download KYC report"
+#~ msgstr "KYC-Bericht herunterladen"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:315
-msgid "received"
-msgstr "erhalten"
+#~ msgid "KYC report ready"
+#~ msgstr "KYC-Bericht ist bereit"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:348
-msgid "to"
-msgstr "an"
+#~ msgid "Use testing dialect"
+#~ msgstr "Test-Dialekt verwenden"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:349
-msgid "from"
-msgstr "von"
+#~ msgid "Since"
+#~ msgstr "Seit"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:92
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:101
-msgid "Welcome to the exchange configuration"
-msgstr "Willkommen bei der Exchange-Konfiguration"
+#~ msgid "Already completed."
+#~ msgstr "Bereits abgeschlossen."
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:372
-msgid "Transfers"
-msgstr "Überweisungen"
+#~ msgid "Case history for selected account"
+#~ msgstr "Fallverlauf für ausgewähltes Konto"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:379
-msgid "Profile"
-msgstr "Profil"
+#~ msgid "ID:"
+#~ msgstr "ID:"
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:49
-#, fuzzy
-msgid "Failed to load server measures."
-msgstr "Server-Maßnahmen"
+#~ msgid "Payto:"
+#~ msgstr "Payto:"
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:61
-#, fuzzy
-msgid "Failed to load the measures"
-msgstr "Aktuell aktive Maßnahmen"
+#~ msgid "Export as PDF"
+#~ msgstr "Als PDF exportieren"
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:105
-#, fuzzy
-msgid "A list of all the predefined measures you can use."
-msgstr ""
-"Eine Liste aller vordefinierten Maßnahmen, die verwendet werden können."
+#~ msgid "Click here to save the file in your computer."
+#~ msgstr "Klicken Sie hier, um die Datei auf Ihrem Computer zu speichern."
-#. screenid: 122
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:165
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:174
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:214
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:222
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:90
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:99
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:62
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:71
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:191
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:200
-msgid "Failed to load available measures."
-msgstr "Die verfügbaren Maßnahmen konnten nicht geladen werden."
+#~ msgid "Every attribute collection event (via form upload or KYC provider)."
+#~ msgstr ""
+#~ "Jedes Ereignis der Attributerfassung (über Formular-Upload oder KYC-"
+#~ "Anbieter)."
-#. screenid: 122
-#. screenid: 102
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:179
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:104
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:76
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:205
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:403
-msgid "The officer session is invalid."
-msgstr "Die Sitzung des AML-Sachbearbeiters ist ungültig."
+#~ msgid ""
+#~ "There is no decision for this account yet. The account is limited by the "
+#~ "default rules."
+#~ msgstr ""
+#~ "Für dieses Konto liegt noch keine Entscheidung vor. Das Konto unterliegt "
+#~ "den Standardregeln."
-#. screenid: 122
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:183
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:80
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:209
-msgid "The measures endpoint was not found."
-msgstr "Der Endpunkt für Maßnahmen wurde nicht gefunden."
+#~ msgid "No AML history found"
+#~ msgstr "Kein AML-Verlauf gefunden"
-#. screenid: 122
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:189
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:114
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:86
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:215
-msgid "The officer session is disabled."
-msgstr "Die Sitzung des AML-Sachbearbeiters ist deaktiviert."
+#~ msgid "Current active measures"
+#~ msgstr "Aktuell aktive Maßnahmen"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:182
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:190
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:389
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:398
-msgid "Failed to load the active AML decision."
-msgstr "Die aktive AML-Entscheidung konnte nicht geladen werden."
+#, fuzzy
+#~ msgid "There are no accounts in the resultset."
+#~ msgstr "Für dieses Konto gibt es noch keine Regeln."
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:488
-msgid "The officer session signature is invalid."
-msgstr "Die Signatur der Sitzung des AML-Sachbearbeiters ist ungültig."
+#, fuzzy
+#~ msgid "Failed to load the accounts"
+#~ msgstr "Fallverlauf für ausgewähltes Konto"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:491
-msgid "The requested AML account or session was not found."
-msgstr "Das angeforderte AML-Konto oder die Sitzung wurde nicht gefunden."
+#~ msgid "High risk accounts. Only with custom rules."
+#~ msgstr "Hochrisikokonten. Nur mit benutzerdefinierten Regeln."
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:495
-msgid "The officer session is disabled or the account state changed."
-msgstr ""
-"Die Sitzung des AML-Sachbearbeiters ist deaktiviert oder der Kontostatus hat "
-"sich geändert."
+#~ msgid "Account with custom rules."
+#~ msgstr "Konto mit benutzerdefinierten Regeln."
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:192
-msgid "Invalid expiration"
-msgstr "Ungültiges Ablaufdatum"
+#~ msgid "High risk accounts under investigation. Only with custom rules."
+#~ msgstr ""
+#~ "Hochrisikokonten in Untersuchung. Nur mit benutzerdefinierten Regeln."
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:193
-msgid "Attributes require an expiration date in the future."
-msgstr "Attribute benötigen ein in der Zukunft liegendes Ablaufdatum."
+#~ msgid "Accounts under investigation. Only with custom rules."
+#~ msgstr "Konten in Untersuchung. Nur mit benutzerdefinierten Regeln."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:288
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:273
-msgid "Too many SKIP measures"
-msgstr "Zu viele SKIP-Maßnahmen"
+#~ msgid "High risk accounts under investigation."
+#~ msgstr "Hochrisikokonten in Untersuchung."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:289
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:274
-msgid "At most one immediate measure may use the SKIP check."
-msgstr "Höchstens eine sofortige Maßnahme darf die SKIP-Prüfung verwenden."
+#~ msgid "Accounts under investigation."
+#~ msgstr "Konten in Untersuchung."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:491
-msgid "Require all measures"
-msgstr "Alle Maßnahmen voraussetzen"
+#~ msgid "High risk accounts without investigation. Only with custom rules."
+#~ msgstr ""
+#~ "Hochrisikokonten ohne Untersuchung. Nur mit benutzerdefinierten Regeln."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:492
-msgid ""
-"Run all selected measures together instead of accepting any one of them."
-msgstr ""
-"Alle ausgewählten Maßnahmen gemeinsam ausführen, anstatt eine beliebige "
-"davon zu akzeptieren."
+#~ msgid "Accounts without investigation. Only with custom rules."
+#~ msgstr "Konten ohne Untersuchung. Nur mit benutzerdefinierten Regeln."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:172
-msgid "Invalid custom properties"
-msgstr "Ungültige benutzerdefinierte Eigenschaften"
+#~ msgid "High risk accounts without investigation."
+#~ msgstr "Hochrisikokonten ohne Untersuchung."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:173
-msgid ""
-"Custom property names and values must be non-empty and names must be unique "
-"and different from built-in properties."
-msgstr ""
-"Namen und Werte benutzerdefinierter Eigenschaften dürfen nicht leer sein; "
-"die Namen müssen eindeutig sein und sich von integrierten Eigenschaften "
-"unterscheiden."
+#~ msgid "Accounts without investigation."
+#~ msgstr "Konten ohne Untersuchung."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:265
-msgid "Unknown measure"
-msgstr "Unbekannte Maßnahme"
+#~ msgid "No results"
+#~ msgstr "Keine Ergebnisse"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:266
-msgid ""
-"A rule or immediate action references a measure that is not available. "
-"Review the rules and measures before submitting."
-msgstr ""
-"Eine Regel oder sofortige Aktion verweist auf eine nicht verfügbare "
-"Maßnahme. Prüfen Sie die Regeln und Maßnahmen vor dem Absenden."
+#~ msgid "#"
+#~ msgstr "#"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:274
-msgid "Requires investigation"
-msgstr "Erfordert eine Untersuchung"
+#~ msgid "Account Identification"
+#~ msgstr "Kontokennung"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:106
-msgid "Collection event not found"
-msgstr "Erfassungsereignis nicht gefunden"
+#~ msgid "From %1$s %2$s To %3$s"
+#~ msgstr "Von %1$s %2$s Bis %3$s"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:107
-msgid "There is no collection event with ID %1$s for this account."
-msgstr "Für dieses Konto gibt es kein Erfassungsereignis mit der ID %1$s."
+#~ msgid "With custom rules"
+#~ msgstr "Mit benutzerdefinierten Regeln"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:116
-msgid "Attributes unavailable"
-msgstr "Attribute nicht verfügbar"
+#~ msgid "Search by ID"
+#~ msgstr "Nach ID suchen"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:117
-msgid "The collection event does not contain readable attributes."
-msgstr "Das Erfassungsereignis enthält keine lesbaren Attribute."
+#~ msgid "Under investigation: "
+#~ msgstr "In Untersuchung: "
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:131
-msgid "Form identifier missing"
-msgstr "Formular-ID fehlt"
+#~ msgid "High risk:"
+#~ msgstr "Hochrisiko:"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:132
-msgid "The collected information does not identify the form used to create it."
-msgstr ""
-"Die erfassten Informationen geben nicht an, mit welchem Formular sie "
-"erstellt wurden."
+#~ msgid "Case queue"
+#~ msgstr "Fallwarteschlange"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:144
-msgid "Form not available"
-msgstr "Formular nicht verfügbar"
+#~ msgid "Access"
+#~ msgstr "Zugriff"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:145
-msgid "Form %1$s is not configured in this AML Web UI."
-msgstr "Das Formular %1$s ist in dieser AML-Weboberfläche nicht konfiguriert."
+#~ msgid "Unlocked until"
+#~ msgstr "Entsperrt bis"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:407
-msgid "The account was not found."
-msgstr "Das Konto wurde nicht gefunden."
+#~ msgid "Confirm forgetting this session"
+#~ msgstr "Vergessen dieser Sitzung bestätigen"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:411
-msgid "The account state changed. Reload it and try again."
-msgstr ""
-"Der Kontostatus hat sich geändert. Laden Sie das Konto neu und versuchen Sie "
-"es erneut."
+#, fuzzy
+#~ msgid "Request session activation"
+#~ msgstr "Kontoaktivierung anfordern"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:436
-msgid ""
-"The payto URI does not belong to this account. Return to the account search "
-"and start the decision again."
-msgstr ""
-"Die Payto-URI gehört nicht zu diesem Konto. Kehren Sie zur Kontosuche zurück "
-"und beginnen Sie die Entscheidung erneut."
+#~ msgid "Prev"
+#~ msgstr "Zurück"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:448
-msgid ""
-"This account has no active decision and its payto URI is unknown. Start the "
-"decision from the account search so the account type can be determined "
-"safely."
-msgstr ""
-"Für dieses Konto gibt es keine aktive Entscheidung und seine Payto-URI ist "
-"unbekannt. Starten Sie die Entscheidung über die Kontosuche, damit der "
-"Kontotyp sicher bestimmt werden kann."
+#~ msgid "Next"
+#~ msgstr "Weiter"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:458
-msgid "Return to account"
-msgstr "Zum Konto zurückkehren"
+#~ msgid ""
+#~ "This account has no active decision and its payto URI is unknown. Start "
+#~ "the decision from the account search so the account type can be "
+#~ "determined safely."
+#~ msgstr ""
+#~ "Für dieses Konto gibt es keine aktive Entscheidung und seine Payto-URI "
+#~ "ist unbekannt. Starten Sie die Entscheidung über die Kontosuche, damit "
+#~ "der Kontotyp sicher bestimmt werden kann."
#, c-format
#~ msgid "Internal error, please report."
@@ -2410,10 +5285,6 @@ msgstr "Zum Konto zurückkehren"
#~ "falsch."
#, c-format
-#~ msgid "Lock account"
-#~ msgstr "Konto sperren"
-
-#, c-format
#~ msgid "Operation denied"
#~ msgstr "Vorgang verweigert"
diff --git a/packages/taler-exchange-aml-webui/src/i18n/en.po b/packages/taler-exchange-aml-webui/src/i18n/en.po
@@ -24,2289 +24,5083 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. screenid: 118
-#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:103
-msgid "Use testing dialect"
-msgstr ""
-
-#. screenid: 118
-#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:105
+#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:114
msgid "Allow Insecure password"
-msgstr ""
+msgstr "Allow Insecure password"
#. screenid: 118
-#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:107
+#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:116
msgid "Keep session after reload"
-msgstr ""
+msgstr "Keep session after reload"
#. screenid: 118
-#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:109
+#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:118
msgid "Don't compress request"
-msgstr ""
+msgstr "Don't compress request"
#. screenid: 101
-#: packages/taler-exchange-aml-webui/src/ExchangeAmlFrame.tsx:75
-msgid "Preferences"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/ExchangeAmlFrame.tsx:85
+msgid "Lock session"
+msgstr "Lock session"
#. screenid: 101
-#: packages/taler-exchange-aml-webui/src/ExchangeAmlFrame.tsx:120
-msgid "Show debug information"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/ExchangeAmlFrame.tsx:90
+msgid "Lock"
+msgstr "Lock"
#. screenid: 125
#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:46
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:45
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:94
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:47
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:47
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:115
msgid "Password"
-msgstr ""
+msgstr "Password"
#. screenid: 125
#. screenid: 122
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:50
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:71
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:555
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:996
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:749
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:780
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:797
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:827
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:841
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:51
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:72
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:629
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1108
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:794
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:825
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:842
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:872
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:886
msgid "Required"
-msgstr ""
+msgstr "Required"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:54
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:55
msgid "should have at least 12 characters"
-msgstr ""
+msgstr "should have at least 12 characters"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:56
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:57
msgid "should have lowercase and uppercase characters"
-msgstr ""
+msgstr "should have lowercase and uppercase characters"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:58
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:59
msgid "should have numbers"
-msgstr ""
+msgstr "should have numbers"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:60
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:61
msgid "should have at least one character which is not a number or letter"
-msgstr ""
+msgstr "should have at least one character which is not a number or letter"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:67
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:68
msgid "Repeat password"
-msgstr ""
+msgstr "Repeat password"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:73
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:74
msgid "doesn't match"
-msgstr ""
+msgstr "doesn't match"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:105
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:112
msgid "Create session"
-msgstr ""
+msgstr "Create session"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:117
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:139
msgid "Create"
-msgstr ""
-
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:66
-msgid "Failed to unlock the session."
-msgstr ""
+msgstr "Create"
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:69
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:243
-msgid "Authorization denied for this session. Contact the administrator."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountBadges.tsx:28
+msgid "Wallet account"
+msgstr "Wallet account"
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:80
-msgid "Session locked"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountBadges.tsx:28
+msgid "Bank account"
+msgstr "Bank account"
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:83
-msgid ""
-"Your session is normally locked anytime you reload. To unlock type your "
-"password again."
-msgstr ""
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/components/AccountBadges.tsx:40
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:93
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:245
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:296
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:100
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:130
+msgid "Under investigation"
+msgstr "Under investigation"
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:108
-msgid "Unlock"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountBadges.tsx:89
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:101
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:254
+msgid "High risk"
+msgstr "High risk"
-#. screenid: 119
-#. screenid: 112
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:116
-#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:81
-msgid "Forget session"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:51
+msgid "Payment target type"
msgstr ""
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:55
-msgid "There are no rules for operations"
-msgstr ""
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:81
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:199
+msgid "Account holder"
+msgstr "Account holder"
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:58
-msgid "This means that no operation has any limit."
-msgstr ""
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:107
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:110
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:571
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:806
+msgid "IBAN"
+msgstr "IBAN"
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:69
-msgid "Add custom rule"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:109
+msgid "BIC"
+msgstr "BIC"
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:94
-msgid "Operation"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:114
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:119
+msgid "Bank"
+msgstr "Bank"
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:100
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:625
-msgid "Threshold"
-msgstr ""
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:115
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:120
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:154
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:160
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:295
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:859
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:364
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:435
+msgid "Account"
+msgstr "Account"
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:106
-msgid "Escalation"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:116
+msgid "Taler bank"
+msgstr "Taler bank"
-#. screenid: 121
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:120
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:243
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:800
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:844
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:902
-msgid "%1$s"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:121
+msgid "Cyclos"
+msgstr "Cyclos"
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:195
-msgctxt "threshold"
-msgid "%1$s every %2$s"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:124
+msgid "Bitcoin address"
+msgstr "Bitcoin address"
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:213
-msgid "(all)"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:129
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:144
+msgid "Reserve public key"
+msgstr "Reserve public key"
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:59
-#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:69
-msgid "Since"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:133
+msgid "Bitcoin"
+msgstr "Bitcoin"
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:70
-msgid "Expired"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:136
+msgid "Ethereum address"
+msgstr "Ethereum address"
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:72
-msgid "Expires"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:139
+msgid "Ethereum"
+msgstr "Ethereum"
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:82
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:724
-msgid "Successor measure"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:142
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:70
+msgid "Exchange"
+msgstr "Exchange"
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:140
-msgid "AML officer justification"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:149
+msgid "Taler reserve"
+msgstr "Taler reserve"
-#: packages/taler-exchange-aml-webui/src/components/ShowDefaultRules.tsx:11
-msgid "Default rules"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:150
+msgid "Taler reserve (HTTP)"
+msgstr "Taler reserve (HTTP)"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:42
-msgid "Forms"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:157
+msgid "Test account"
+msgstr "Test account"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:45
-msgid "Measures used to gather information about the customer."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:180
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:225
+msgid "Account details unavailable"
+msgstr "Account details unavailable"
-#. screenid: 123
-#. screenid: 108
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:69
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:162
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:248
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:153
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:552
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:992
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:192
-msgid "Name"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:54
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:96
+msgid "Not opened"
+msgstr "Not opened"
-#. screenid: 123
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:76
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:169
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:584
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:837
-msgid "Check"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:59
+msgid "Opened:"
+msgstr "Opened:"
-#. screenid: 123
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:82
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:255
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:564
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:791
-msgid "Program"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:68
+msgid "Closed:"
+msgstr "Closed:"
-#. screenid: 123
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:88
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:175
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:267
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:607
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:805
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:893
-msgid "Context"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:94
+msgid "Closed"
+msgstr "Closed"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:102
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:189
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:281
-msgid "Modify"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:95
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:263
+msgid "Open"
+msgstr "Open"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:135
-msgid "Info"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:125
+msgid "No note"
+msgstr "No note"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:138
-msgid "Will show information to the user."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:136
+msgid "Show full note"
+msgstr "Show full note"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:221
-msgid "Instant measures"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:146
+msgid "System information"
+msgstr "System information"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:224
-msgid "Triggered immediately without customer interaction."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:149
+msgid "Transactions remain below the threshold that opens an AML file."
+msgstr "Transactions remain below the threshold that opens an AML file."
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:261
-msgid "Input requirement"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:122
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:202
+msgid "Account case"
+msgstr "Account case"
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:78
-msgid "Already completed."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:149
+msgid "Failed to download AML file."
+msgstr "Failed to download AML file."
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:80
-msgid "Waiting to be completed."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:152
+msgid "No AML file is available for this account."
+msgstr "No AML file is available for this account."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:183
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:365
-msgid "Current active rules"
-msgstr ""
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:154
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:72
+msgid "Authorization denied for this session. Contact the administrator."
+msgstr "Authorization denied for this session. Contact the administrator."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:188
-msgid "There are no rules for this account yet."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:156
+msgid "The account or session was not found."
+msgstr "The account or session was not found."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:238
-msgid "New rule form"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:158
+msgid "The session is disabled. Contact the administrator."
+msgstr "The session is disabled. Contact the administrator."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:250
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:230
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:412
-msgid "Add"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:160
+msgid "The exchange does not support PDF reports."
+msgstr "The exchange does not support PDF reports."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:258
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:221
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:403
-msgid "Cancel"
-msgstr ""
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:175
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:354
+msgid "Read-only officers cannot create AML decisions."
+msgstr "Read-only officers cannot create AML decisions."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:356
-msgid "Basic plan"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:177
+msgid "A payto URI is required to create a new decision."
+msgstr "A payto URI is required to create a new decision."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:367
-msgid "Premium"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:194
+msgid "Back to accounts"
+msgstr "Back to accounts"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:378
-msgid "E-commerce"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:224
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:505
+msgid "File no. %1$s"
+msgstr "File no. %1$s"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:389
-msgid "Point of Sale"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:253
+msgid "New decision"
+msgstr "New decision"
+
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:265
+msgid "Download AML file (PDF)"
+msgstr "Download AML file (PDF)"
+
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:278
+msgid "AML file download started."
+msgstr "AML file download started."
+
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:284
+#, fuzzy
+#| msgid "Account open"
+msgid "Account notes"
+msgstr "Account open"
+
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:293
+#, fuzzy
+#| msgid "Account assessment could not be loaded"
+msgid "Current account status and notes could not be loaded."
+msgstr "Account assessment could not be loaded"
+
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:302
+msgid "Try again"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:316
+msgid "Account identifiers"
+msgstr "Account identifiers"
+
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:325
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:509
+msgid "Technical identifiers"
+msgstr "Technical identifiers"
+
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:329
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:513
+msgid "Full payto URI"
+msgstr "Full payto URI"
+
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:331
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:144
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:155
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:173
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:190
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:390
+msgid "Unavailable"
+msgstr "Unavailable"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:408
-msgid "Check rules"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:332
+msgid "Copy payto URI"
+msgstr "Copy payto URI"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:428
-msgid ""
-"The account is a wallet and there are bank account operation's limits which "
-"may trigger actions that are not required: %1$s"
-msgstr ""
+#. screenid: 113
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:335
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:517
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:188
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:157
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:289
+msgid "Normalized payto hash"
+msgstr "Normalized payto hash"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:437
-msgid ""
-"The account isn't a wallet and there are wallet operation's limits which may "
-"trigger actions that are not required: %1$s"
-msgstr ""
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:337
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:194
+msgid "Copy normalized payto hash"
+msgstr "Copy normalized payto hash"
+
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:341
+#, fuzzy
+#| msgid "number"
+msgid "File number"
+msgstr "number"
+
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:343
+#, fuzzy
+#| msgid "Not a number"
+msgid "Copy file number"
+msgstr "Not a number"
+
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:351
+msgid "Account case views"
+msgstr "Account case views"
+
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:355
+msgid "Overview"
+msgstr "Overview"
+
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:360
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:565
+msgid "Transfers"
+msgstr "Transfers"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:446
-msgid ""
-"The account is a wallet and there are wallet operation's limits which are "
-"not limited: %1$s"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:365
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:67
+msgid "Decision history"
+msgstr "Decision history"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:454
-msgid ""
-"The AML account is a bank account, but not all account-related operations "
-"are limited ( %1$s)."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ConfirmationModal.tsx:73
+msgid "Close"
+msgstr "Close"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:482
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:269
-msgid "New rules"
-msgstr ""
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/ConfirmationModal.tsx:91
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:207
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:534
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:280
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:469
+msgid "Cancel"
+msgstr "Cancel"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:503
-msgid "Reset rules to current state"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:36
+msgid "AML officer enrollment request"
+msgstr "AML officer enrollment request"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:511
-msgid "Set rules to default"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:37
+msgid ""
+"Please enroll this AML officer public key:\n"
+"\n"
+"%1$s"
msgstr ""
+"Please enroll this AML officer public key:\n"
+"\n"
+"%1$s"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:519
-msgid "Freeze account"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:59
+msgid "Officer key awaiting enrollment"
+msgstr "Officer key awaiting enrollment"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:535
-msgid "Behavior on rule expiration"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:62
+msgid ""
+"This browser has created an AML officer key, but the exchange has not "
+"granted it access. Ask the exchange operator or administrator to enroll the "
+"public key below."
+msgstr ""
+"This browser has created an AML officer key, but the exchange has not "
+"granted it access. Ask the exchange operator or administrator to enroll the "
+"public key below."
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:70
+msgid "AML officer public key"
+msgstr "AML officer public key"
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:76
+msgid "Copy AML officer public key"
+msgstr "Copy AML officer public key"
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:82
+msgid "After the operator confirms enrollment, retry the access check."
+msgstr "After the operator confirms enrollment, retry the access check."
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:92
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:69
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:212
+msgid "Retry access check"
+msgstr "Retry access check"
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:101
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:188
+msgid "Checking officer access"
+msgstr "Checking officer access"
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:104
+msgid "Last checked at %1$s"
+msgstr "Last checked at %1$s"
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:114
+msgid "Request enrollment"
+msgstr "Request enrollment"
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:121
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:128
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:77
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:85
+msgid "Discard this key"
+msgstr "Discard this key"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:546
-msgid "Reset measure"
-msgstr ""
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:127
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:84
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:250
+msgid "Confirmation required"
+msgstr "Confirmation required"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:558
-msgid "Reset expiration"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:135
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:92
+msgid ""
+"Discarding this key removes the officer session from this browser. You will "
+"need to create a new key to use the AML WebUI again."
msgstr ""
+"Discarding this key removes the officer session from this browser. You will "
+"need to create a new key to use the AML WebUI again."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:583
-msgctxt "operation type"
-msgid "Withdraw"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:41
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:205
+msgid "Failed to check AML officer access."
+msgstr "Failed to check AML officer access."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:585
-msgctxt "operation type"
-msgid "Deposit"
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:45
+msgid ""
+"This officer key cannot authenticate with the exchange. Retry the check or "
+"discard the key and create a new session."
msgstr ""
+"This officer key cannot authenticate with the exchange. Retry the check or "
+"discard the key and create a new session."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:587
-msgctxt "operation type"
-msgid "Merge"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:50
+msgid "The exchange rejected the officer access check."
+msgstr "The exchange rejected the officer access check."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:589
-msgctxt "operation type"
-msgid "Aggregate"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:57
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:211
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:522
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:101
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:612
+msgid "Technical details"
+msgstr "Technical details"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:591
-msgctxt "operation type"
-msgid "Balance"
-msgstr ""
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:69
+msgid "Failed to unlock the session."
+msgstr "Failed to unlock the session."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:593
-msgctxt "operation type"
-msgid "Refund"
-msgstr ""
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:95
+msgid "Session locked"
+msgstr "Session locked"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:595
-msgctxt "operation type"
-msgid "Close"
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:98
+msgid ""
+"Your session is normally locked anytime you reload. To unlock type your "
+"password again."
msgstr ""
+"Your session is normally locked anytime you reload. To unlock type your "
+"password again."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:597
-msgctxt "operation type"
-msgid "Transaction"
-msgstr ""
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:136
+msgid "Unlock"
+msgstr "Unlock"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:612
-msgid "Operation type"
-msgstr ""
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:144
+msgid "Forget session"
+msgstr "Forget session"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:633
-msgid "Timeframe"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:162
+#, fuzzy
+#| msgid "No account properties"
+msgid "Review derived account properties"
+msgstr "No account properties"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:639
-msgid "Exposed"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:165
+msgid ""
+"Values may be derived from the selected AML/KYC form. Confirm them against "
+"the case record and change only values that require an officer override."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:640
-msgid "Is this limit communicated to the customer?"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:187
+#, fuzzy
+#| msgid "Reset to default"
+msgid "Reset to derived values"
+msgstr "Reset to default"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:652
-msgid "Escalation measure"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:192
+msgid "Invalid custom properties"
+msgstr "Invalid custom properties"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:653
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:193
msgid ""
-"Measures that the customer will need to satisfy to apply for a new threshold."
+"Custom property names and values must be non-empty and names must be unique "
+"and different from built-in properties."
msgstr ""
+"Custom property names and values must be non-empty and names must be unique "
+"and different from built-in properties."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:658
-msgid "All measures"
-msgstr ""
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:216
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:466
+msgid "Properties"
+msgstr "Properties"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:659
-msgid "Hint the customer that all measures should be completed"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:217
+msgid "Built-in property names are preserved when the decision is submitted."
msgstr ""
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:672
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:157
-msgid "Expiration"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:223
+msgid "Custom properties"
+msgstr "Custom properties"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:673
-msgid "Predefined shortcuts"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:224
+msgid "Add more properties that are not listed above."
+msgstr "Add more properties that are not listed above."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:677
-msgid "In a week"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:229
+msgid "New properties"
+msgstr "New properties"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:685
-msgid "In a month"
-msgstr ""
+#. screenid: 123
+#. screenid: 108
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:234
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:73
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:171
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:261
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:204
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:626
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1104
+msgid "Name"
+msgstr "Name"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:693
-msgid "In a year"
-msgstr ""
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:240
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:720
+msgid "Value"
+msgstr "Value"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:701
-msgid "Never"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:262
+msgid "Current note on the GwG file"
+msgstr "Current note on the GwG file"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:712
-msgid "Expiration date"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:267
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:63
+msgid "Customer name or internal alias."
+msgstr "Customer name or internal alias."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:713
-msgid "Until when are the new rules active."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:272
+msgid "Is the account active for deposit and payments?"
+msgstr "Is the account active for deposit and payments?"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:725
-msgid "Measure taken automatically upon expiration of the current decision."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:277
+msgid "Is the account idle?"
+msgstr "Is the account idle?"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:107
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:62
-msgid "Failed to load account information."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:278
+msgid "No operation for a period of time"
+msgstr "No operation for a period of time"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:125
-msgid "Failed to load decision history."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:283
+msgid "Does account belong to a domestic PEP?"
+msgstr "Does account belong to a domestic PEP?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:143
-msgid "Failed to load current legitimizations."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:288
+msgid "Does account belong to a foreign PEP?"
+msgstr "Does account belong to a foreign PEP?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:188
-msgid "New decision"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:293
+msgid "Does account belong to an international-organization PEP?"
+msgstr "Does account belong to an international-organization PEP?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:196
-msgid "Show transfers"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:298
+msgid "Does account belong to a high risk customer?"
+msgstr "Does account belong to a high risk customer?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:236
-msgid "Failed to download report."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:303
+msgid "Does account belong to a person from a high risk country?"
+msgstr "Does account belong to a person from a high risk country?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:241
-msgid "The account has no KYC info."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:308
+msgid "The MROS reporting state for the account."
+msgstr "The MROS reporting state for the account."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:245
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:183
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:195
-msgid "Session not found. Contact the administrator."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:313
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:307
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:175
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:199
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:497
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:630
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:653
+msgid "None"
+msgstr "None"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:247
-msgid "The session is disabled. Contact the administrator."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:317
+msgid "Pending investigation"
+msgstr "Pending investigation"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:249
-msgid "The server doesn't support PDF download. Contact the administrator."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:321
+msgid "Investigated without suspicion"
+msgstr "Investigated without suspicion"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:260
-msgid "Case history for selected account"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:325
+msgid "Reported simple suspicion"
+msgstr "Reported simple suspicion"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:265
-msgid "ID:"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:329
+msgid "Reported substantiated suspicion"
+msgstr "Reported substantiated suspicion"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:271
-msgid "Payto:"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:336
+msgid "Informal reason why the AML investigation was triggered"
+msgstr "Informal reason why the AML investigation was triggered"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:282
-msgid "Export as PDF"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:341
+msgid "Identifies the sanction list entry that the account matched against"
+msgstr "Identifies the sanction list entry that the account matched against"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:298
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:279
-msgid "Export completed"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:343
+msgid "Best match, does not mean it was a good match."
+msgstr "Best match, does not mean it was a good match."
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:301
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:282
-msgid "Click here to save the file in your computer."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:347
+msgid "Score for how good the sanction list match was"
+msgstr "Score for how good the sanction list match was"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:310
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:411
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:208
-msgid "Under investigation"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:349
+msgid "Integer score from 0 (no match) to 1,000,000,000 (best match)."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:311
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:353
+msgid "Score for how much supporting data we had for the sanction list match"
+msgstr "Score for how much supporting data we had for the sanction list match"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:355
msgid ""
-"This account requires a manual review and is waiting for a decision to be "
-"made."
+"Integer score from 0 (no supporting data) to 1,000,000,000 (highest "
+"confidence)."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:322
-msgid "Collected information"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:359
+msgid ""
+"Suppress flagging this account when it creates a hit on a sanctions list, "
+"this is a false-positive"
msgstr ""
+"Suppress flagging this account when it creates a hit on a sanctions list, "
+"this is a false-positive"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:325
-msgid "Every attribute collection event (via form upload or KYC provider)."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/DecisionProperties.tsx:46
+#, fuzzy
+#| msgid "No account properties"
+msgid "No account properties were recorded."
+msgstr "No account properties"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:333
-msgid "No collected attributes for this account."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/DecisionProperties.tsx:91
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:317
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:509
+msgid "Yes"
+msgstr "Yes"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:347
-msgid "Current account properties"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/DecisionProperties.tsx:91
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:317
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:509
+msgid "No"
+msgstr "No"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:354
-msgid "No active decision found"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:59
+msgid "There are no rules for operations"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:355
-msgid ""
-"There is no decision for this account yet. The account is limited by the "
-"default rules."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:62
+msgid "This means that no operation has any limit."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:384
-msgid "Previous AML decisions"
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:90
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:312
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:500
+msgid "Operation"
+msgstr "Operation"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:403
-msgid "No AML history found"
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:96
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:695
+msgid "Threshold"
+msgstr "Threshold"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:409
-msgid "Current active measures"
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:102
+msgid "Escalation"
+msgstr "Escalation"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:537
-msgid "Now"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:108
+msgid "Visibility"
msgstr ""
-#. screenid: 112
-#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:43
-msgid "Session public key"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:114
+msgid "Priority"
msgstr ""
-#. screenid: 112
-#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:59
-msgid "Request session activation"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:121
+msgid "Actions"
msgstr ""
-#. screenid: 112
-#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:70
-msgid "Lock session"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:142
+msgctxt "threshold"
+msgid "%1$s every %2$s"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:73
-msgid "Failed to load accounts"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:161
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:725
+msgid "Block operation"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:83
-msgid "Failed to load the accounts"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:163
+msgid "All required:"
msgstr ""
-#. screenid: 111
-#. screenid: 110
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:88
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:168
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:76
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:128
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:66
-msgid ""
-"This session signature is invalid, contact administrator or create a new one."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:165
+msgid "Any one:"
msgstr ""
-#. screenid: 111
-#. screenid: 110
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:95
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:175
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:83
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:135
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:73
-msgid ""
-"The designated AML session is not known, contact administrator or create a "
-"new one."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:182
+msgid "Customer-visible"
msgstr ""
-#. screenid: 111
-#. screenid: 110
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:102
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:182
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:90
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:142
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:80
-msgid ""
-"The designated AML session is not enabled, contact administrator or create a "
-"new one."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:184
+msgid "Internal"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:122
-msgid "High risk accounts. Only with custom rules."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:197
+msgid "Move %1$s rule up"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:123
-msgid "Account with custom rules."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:206
+msgid "Move %1$s rule down"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:125
-msgid "High risk accounts"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:217
+msgid "Edit %1$s rule"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:126
-msgid "All known accounts."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:240
+msgid "Remove %1$s rule"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:130
-msgid "High risk accounts under investigation. Only with custom rules."
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:282
+msgctxt "operation type"
+msgid "Withdraw"
+msgstr "Withdraw"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:131
-msgid "Accounts under investigation. Only with custom rules."
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:284
+msgctxt "operation type"
+msgid "Deposit"
+msgstr "Deposit"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:133
-msgid "High risk accounts under investigation."
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:286
+msgctxt "operation type"
+msgid "Merge"
+msgstr "Merge"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:134
-msgid "Accounts under investigation."
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:288
+msgctxt "operation type"
+msgid "Aggregate"
+msgstr "Aggregate"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:137
-msgid "High risk accounts without investigation. Only with custom rules."
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:290
+msgctxt "operation type"
+msgid "Balance"
+msgstr "Balance"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:138
-msgid "Accounts without investigation. Only with custom rules."
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:292
+msgctxt "operation type"
+msgid "Refund"
+msgstr "Refund"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:140
-msgid "High risk accounts without investigation."
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:294
+msgctxt "operation type"
+msgid "Close"
+msgstr "Close"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:141
-msgid "Accounts without investigation."
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:296
+msgctxt "operation type"
+msgid "Transaction"
+msgstr "Transaction"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:174
-msgid "Failed to download"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:83
+#, fuzzy
+#| msgid "Decision date"
+msgid "Decision provenance"
+msgstr "Decision date"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:177
-msgid "There are no accounts in the resultset."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:85
+#, fuzzy
+#| msgid "Decision date"
+msgid "Decision made by"
+msgstr "Decision date"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:179
-msgid "The format requested is not acceptable from the service provider."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:88
+#, fuzzy
+#| msgid "AML officer public key"
+msgid "AML officer (name unavailable)"
+msgstr "AML officer public key"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:181
-msgid "Authorization denied for this session."
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:89
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:369
+msgid "Automated outcome"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:185
-msgid "The session is disabled. Contact the administrator"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:91
+msgid "Resulting case disposition"
msgstr ""
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:240
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:368
-msgid "Accounts"
-msgstr ""
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:94
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:246
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:105
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:132
+msgid "Not under investigation"
+msgstr "Not under investigation"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:247
-msgid "Export as file"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:99
+#, fuzzy
+#| msgid "Justification"
+msgid "Justification:"
+msgstr "Justification"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:318
-msgid "No results"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:101
+msgid "No justification was recorded."
+msgstr "No justification was recorded."
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:329
-msgid "#"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:112
+#, fuzzy
+#| msgid "System information"
+msgid "View submitted customer information"
+msgstr "System information"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:335
-msgid "Account Identification"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:120
+#, fuzzy
+#| msgid "Instant measures"
+msgid "Immediate measures requested"
+msgstr "Instant measures"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:341
-msgid "Open time"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:123
+msgid "This decision did not request an immediate measure."
msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:347
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:243
-msgid "Status"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:131
+#, fuzzy
+#| msgid "All listed measures must be completed."
+msgid "All listed measures were requested (AND)."
+msgstr "All listed measures must be completed."
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:365
-msgid "From %1$s %2$s To %3$s"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:132
+#, fuzzy
+#| msgid "Any one listed measure may be completed."
+msgid "Any listed measure may satisfy the request (OR)."
+msgstr "Any one listed measure may be completed."
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:371
-msgid "Since %1$s"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:151
+msgid "Operation rules"
+msgstr "Operation rules"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:374
-msgid "Not opened"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:156
+msgid "No operation-specific rules were stored."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:419
-msgid "High risk"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:163
+#, fuzzy
+#| msgid "Select transaction type"
+msgid "Policy transition"
+msgstr "Select transaction type"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:427
-msgid "With custom rules"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:165
+msgid "Policy expires"
msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:642
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:673
-msgid "Invalid account"
-msgstr ""
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:173
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:796
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:362
+msgid "Successor measure"
+msgstr "Successor measure"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:657
-msgid "Search by ID"
-msgstr ""
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:174
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:479
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:163
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:365
+msgid "Exchange defaults"
+msgstr "Exchange defaults"
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:179
+#, fuzzy
+#| msgid "Custom measures"
+msgid "Custom measure definitions"
+msgstr "Custom measures"
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:182
+#, fuzzy
+#| msgid "No active measure has been selected."
+msgid "No custom measures were stored."
+msgstr "No active measure has been selected."
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:687
-msgid "Under investigation: "
-msgstr ""
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:202
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:278
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:128
+msgid "Account properties"
+msgstr "Account properties"
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:214
+#, fuzzy
+#| msgid "Decision steps"
+msgid "Decision row"
+msgstr "Decision steps"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:696
-msgid "High risk:"
-msgstr ""
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:217
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:174
+msgid "Officer public key"
+msgstr "Officer public key"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:705
-msgid "Custom rules:"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:219
+msgid "Not applicable"
msgstr ""
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:47
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:366
-msgid "Dashboard"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:277
+#, fuzzy
+#| msgid "System information"
+msgid "Stored custom definition"
+msgstr "System information"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:88
-msgid "Failed to load TOPS statistics."
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:284
+msgid ""
+"Current measure metadata is still loading; the stored machine name is shown."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:99
-msgid "Statistics"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:286
+msgid ""
+"The current measure configuration could not be loaded; the stored machine "
+"name is shown."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:187
-msgid "Accounts open"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:287
+msgid ""
+"No stored or currently configured definition is available for this reference."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:190
-msgid "New files last year"
-msgstr ""
+#. screenid: 123
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:291
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:80
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:178
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:659
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:938
+msgid "Check"
+msgstr "Check"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:193
-msgid "Closed files last year"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:295
+msgid "Built-in check that requires no customer interaction."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:196
-msgid "MROS substantiated"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:296
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:304
+#, fuzzy
+#| msgid "Attributes unavailable"
+msgid "Description unavailable"
+msgstr "Attributes unavailable"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:199
-msgid "MROS simple"
-msgstr ""
+#. screenid: 123
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:299
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:86
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:268
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:639
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:891
+msgid "Program"
+msgstr "Program"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:202
-msgid "High risk files"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:316
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:508
+msgid "Voluntary"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:205
-msgid "PEP files"
-msgstr ""
+#. screenid: 123
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:320
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:92
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:184
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:280
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:682
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:907
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:644
+msgid "Context"
+msgstr "Context"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:267
-msgid "Number of accounts that are opened"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:349
+msgid "Decision date"
+msgstr "Decision date"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:270
-msgid "Number of new GwG files in the last year"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:357
+msgid "Expired"
+msgstr "Expired"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:273
-msgid "Number of GwG files closed in the last year"
-msgstr ""
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:357
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:419
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:354
+msgid "Expires"
+msgstr "Expires"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:276
-msgid "Number of MROS reports based on Art 9 Abs. 1 GwG (per year)"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:362
+#, fuzzy
+#| msgid "Decision steps"
+msgid "Decision status"
+msgstr "Decision steps"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:279
-msgid "Number of MROS reports based on Art 305ter Abs. 2 StGB (per year)"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:363
+#, fuzzy
+#| msgid "Send decision"
+msgid "Current"
+msgstr "Send decision"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:282
-msgid "Number of GwG files of high-risk customers"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:363
+msgid "Historical"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:285
-msgid "Number of GwG files managed with “increased risk” due to PEP status"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:365
+msgid "Made by"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:288
-msgid "Number of customers with open proceeding."
-msgstr ""
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:368
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:272
+#, fuzzy
+#| msgid "AML officer public key"
+msgid "AML officer"
+msgstr "AML officer public key"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:343
-msgid "previous"
-msgstr ""
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:44
+msgid "Forms"
+msgstr "Forms"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:386
-msgid "Decreased by"
-msgstr ""
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:47
+msgid "Measures used to gather information about the customer."
+msgstr "Measures used to gather information about the customer."
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:390
-msgid "Increased by"
-msgstr ""
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:62
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:160
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:250
+msgid "Select"
+msgstr "Select"
-#. screenid: 108
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:115
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:217
-msgid "Events"
-msgstr ""
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:107
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:199
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:295
+msgid "Modify"
+msgstr "Modify"
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:116
-msgid ""
-"The events will be triggered only after the decision has been confirmed."
-msgstr ""
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:141
+#, fuzzy
+#| msgid "System information"
+msgid "Information"
+msgstr "System information"
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:121
-msgid "Calculated"
-msgstr ""
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:144
+#, fuzzy
+#| msgid "KYC information filed by the customer or an AML officer."
+msgid "Shows information to the customer without running an AML program."
+msgstr "KYC information filed by the customer or an AML officer."
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:122
-msgid "Events based on properties and new attributes that should be triggered"
-msgstr ""
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:232
+msgid "Instant measures"
+msgstr "Instant measures"
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:134
-msgid "Others"
-msgstr ""
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:235
+msgid "Triggered immediately without customer interaction."
+msgstr "Triggered immediately without customer interaction."
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:135
-msgid "Events that can be triggered manually"
-msgstr ""
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:274
+msgid "Input requirement"
+msgstr "Input requirement"
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:147
-msgid "Custom list"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:56
+msgid "Started"
+msgstr "Started"
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:148
-msgid "Events without built-in support."
-msgstr ""
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:64
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:301
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:140
+msgid "Status"
+msgstr "Status"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:132
-msgid "Complete the form"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:76
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:447
+msgid "Forbidden"
+msgstr "Forbidden"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:135
-msgid "These measures will ask the customer for information."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:78
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:443
+msgid "Completed"
+msgstr "Completed"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:153
-msgid "change form"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:79
+msgid "Waiting for customer"
+msgstr "Waiting for customer"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:158
-msgid "Expiration date of the information filled in this form."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:92
+msgid "The operation is categorically forbidden by this requirement."
+msgstr "The operation is categorically forbidden by this requirement."
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:217
-msgid "Include new information"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:100
+msgid "All listed measures must be completed."
+msgstr "All listed measures must be completed."
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:218
-msgid ""
-"Select a form to submit new information about the customer or continue to "
-"the next step"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:104
+msgid "Any one listed measure may be completed."
+msgstr "Any one listed measure may be completed."
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:223
-msgid "Form:"
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:24
+msgid "Expiration shortcuts"
msgstr ""
-#. screenid: 106
-#. screenid: 113
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:81
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:227
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:237
-msgid "Justification"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:29
+msgid "In a week"
+msgstr "In a week"
-#. screenid: 106
-#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:86
-msgid "Keep investigation?"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:30
+msgid "In a month"
+msgstr "In a month"
-#. screenid: 106
-#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:91
-msgid "Account holder"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:31
+msgid "In a year"
+msgstr "In a year"
-#. screenid: 106
-#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:93
-msgid "Full name of the account holder"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:50
+msgid "Never"
+msgstr "Never"
#. screenid: 122
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:90
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:394
-msgid "loading..."
-msgstr ""
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:115
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:98
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:63
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:72
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:209
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:218
+msgid "Failed to load available measures."
+msgstr "Failed to load available measures."
#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:239
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:421
-msgid "Update"
-msgstr ""
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:120
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:112
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:77
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:223
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:294
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:480
+msgid "The officer session is invalid."
+msgstr "The officer session is invalid."
#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:246
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:428
-msgid "Remove"
-msgstr ""
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:124
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:116
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:81
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:227
+msgid "The measures endpoint was not found."
+msgstr "The measures endpoint was not found."
#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:473
-msgid "Configure verification type: %1$s"
-msgstr ""
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:130
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:122
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:87
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:233
+msgid "The officer session is disabled."
+msgstr "The officer session is disabled."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:484
-msgid "Show complete form"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:195
+msgid "Edit proposed rule"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:505
-msgid "Configure measure"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:197
+msgid "Add proposed rule"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:515
-msgid "Show as verification"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:216
+msgid "Save rule"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:557
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:998
-msgid "There is already a measure with that name"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:218
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:372
+msgid "Add rule"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:571
-msgid "Only required when no check is specified"
-msgstr ""
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:356
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:348
+#, fuzzy
+#| msgid "Properties"
+msgid "Proposed rules"
+msgstr "Properties"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:575
-msgid "Missing check or program"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:359
+msgid ""
+"This complete rule set replaces the currently applied rules and exchange "
+"defaults until it expires. Higher rows take precedence."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:585
-msgid "Without a check the program will run automatically"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:390
+msgid "Rules for another account type"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:614
-msgid "Field name"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:393
+msgid "These operations do not apply to this account type: %1$s."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:619
-msgid "Type"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:400
+msgid "Operations without limits"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:623
-msgid "string"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:401
+msgid "No proposed rule limits these operations: %1$s."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:627
-msgid "number"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:408
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:336
+msgid "Invalid proposed rules"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:631
-msgid "boolean"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:409
+msgid ""
+"Edit the highlighted rule set before continuing. Hard blocks cannot be "
+"combined with measures, and Balance and Refund rules must use an instant "
+"timeframe."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:635
-msgid "json"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:432
+msgid "Remove proposed rule?"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:644
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:197
-msgid "Value"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:434
+msgid ""
+"This is the final rule. Removing it leaves every applicable operation "
+"unlimited."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:663
-msgid "There are unsatisfied inputs: %1$s"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:439
+msgid "The rule will be removed from the proposed set."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:674
-msgid "There are missing inputs: %1$s"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:449
+msgid "Keep rule"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:694
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:711
-msgid "There are missing requirements: %1$s"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:459
+msgid "Remove rule"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:751
-msgid "Can't be empty"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:467
+msgid "Replace proposed rules"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:755
-msgid "It should be a number"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:470
+msgid "Preview a complete replacement before applying it."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:757
-msgid "Not a number"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:476
+msgid "Currently applied"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:759
-msgid "It should be finite"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:486
+msgid "E-commerce"
+msgstr "E-commerce"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:761
-msgid "It should be a safe integer"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:489
+msgid "Point of Sale"
+msgstr "Point of Sale"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:766
-msgid "It should be either \"true\" or \"false\""
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:496
+msgid "Basic plan"
+msgstr "Basic plan"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:771
-msgid "Couldn't parse as json string: %1$s"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:501
+msgid "Premium"
+msgstr "Premium"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:797
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:940
-msgid "Description"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:510
+msgid "Freeze account"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:813
-msgid "Inputs"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:518
+msgid "Replacement preview"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:849
-msgid "Output"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:521
+msgid "Confirm account freeze"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:859
-msgid "Requires"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:522
+msgid "Every applicable operation will receive a zero hard limit."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:867
-msgid "Fallback"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:548
+msgid "Apply replacement"
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:993
-msgid "Name of the verification measure"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:556
+#, fuzzy
+#| msgid "Reset expiration"
+msgid "Rule expiration"
+msgstr "Reset expiration"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1005
-msgid "Read only"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:559
+msgid "Choose how long the proposed rules apply and what happens afterwards."
msgstr ""
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1006
-msgid "Prevent the customer from changing the address"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:578
+msgid "The proposed rules never expire, so no successor action will run."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:256
-msgid "Configure verification measure: \"%1$s\""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:598
+msgid "Restore currently applied expiration"
msgstr ""
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:294
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:115
-msgid "Add custom measure"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:682
+msgid "Operation type"
+msgstr "Operation type"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:300
-msgid "Custom measures"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:704
+msgid "Timeframe"
+msgstr "Timeframe"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:329
-msgid "Server measures"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:705
+msgid ""
+"Use Y, M, D, h, m or s after each number. Forever accumulates over the "
+"account's full history."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:426
-msgid "New measures"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:709
+msgid "Instant timeframe"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:427
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:710
msgid ""
-"Measures that are available/executed directly after the decision is "
-"confirmed."
-msgstr ""
-
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:154
-msgid "Reset to default"
+"Balance and Refund limits apply to one balance or transaction, so their "
+"timeframe is fixed to zero."
msgstr ""
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:175
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:234
-msgid "Properties"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:716
+msgid "Exposed"
+msgstr "Exposed"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:181
-msgid "Custom properties"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:717
+msgid "Is this limit communicated to the customer?"
+msgstr "Is this limit communicated to the customer?"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:182
-msgid "Add more properties that are not listed above."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:723
+msgid "When the threshold is crossed"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:187
-msgid "New properties"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:726
+msgid "Require measures"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:218
-msgid "Current note on the GwG file"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:740
+msgid "Required measures"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:223
-msgid "Customer name or internal alias."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:741
+msgid ""
+"Measures that the customer will need to satisfy to apply for a new threshold."
msgstr ""
+"Measures that the customer will need to satisfy to apply for a new threshold."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:228
-msgid "Is the account active for deposit and payments?"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:747
+msgid "All measures"
+msgstr "All measures"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:233
-msgid "Is the account idle?"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:748
+msgid "Hint the customer that all measures should be completed"
+msgstr "Hint the customer that all measures should be completed"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:234
-msgid "No operation for a period of time"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:767
+msgid "Expiration date"
+msgstr "Expiration date"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:239
-msgid "Does account belong to a domestic PEP?"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:768
+msgid "Until when are the new rules active."
+msgstr "Until when are the new rules active."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:244
-msgid "Does account belong to a foreign PEP?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:773
+msgid "Choose a future expiration date or Never."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:249
-msgid "Does account belong to an international-organization PEP?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:779
+msgid "After expiration"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:254
-msgid "Does account belong to a high risk customer?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:781
+msgid "Return to exchange defaults"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:259
-msgid "Does account belong to a person from a high risk country?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:782
+msgid "Trigger a successor measure"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:264
-msgid "The MROS reporting state for the account."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:797
+msgid "Measure taken automatically upon expiration of the current decision."
+msgstr "Measure taken automatically upon expiration of the current decision."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:269
-msgid "None"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:805
+msgid "This successor measure is no longer available."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:273
-msgid "Pending investigation"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:133
+msgid "Case summary"
+msgstr "Case summary"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:277
-msgid "Investigated without suspicion"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:134
+msgid "Current review state and the latest account activity."
+msgstr "Current review state and the latest account activity."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:281
-msgid "Reported simple suspicion"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:138
+msgid "Review status"
+msgstr "Review status"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:285
-msgid "Reported substantiated suspicion"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:142
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:153
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:171
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:188
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:492
+msgid "Loading…"
+msgstr "Loading…"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:292
-msgid "Informal reason why the AML investigation was triggered"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:146
+msgid "Manual review required — waiting for an AML decision."
+msgstr "Manual review required — waiting for an AML decision."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:297
-msgid "Identifies the sanction list entry that the account matched against"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:147
+msgid "No manual review"
+msgstr "No manual review"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:299
-msgid "Best match, does not mean it was a good match."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:150
+msgid "Effective decision"
+msgstr "Effective decision"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:303
-msgid "Score for how good the sanction list match was"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:168
+msgid "Requirements"
+msgstr "Requirements"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:308
-msgid "Score for how much supporting data we had for the sanction list match"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:185
+msgid "Latest collected information"
+msgstr "Latest collected information"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:313
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:208
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:305
+#, fuzzy
+#| msgid "Send decision"
+msgid "Current decision"
+msgstr "Send decision"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:209
+#, fuzzy
+#| msgid ""
+#| "The AML decision and operation rules currently applied to this account."
+msgid "The complete AML decision currently applied to this account."
+msgstr ""
+"The AML decision and operation rules currently applied to this account."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:216
+msgid "Effective policy could not be loaded"
+msgstr "Effective policy could not be loaded"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:234
+msgid "Exchange defaults apply"
+msgstr "Exchange defaults apply"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:235
+msgid "No AML officer decision is active for this account."
+msgstr "No AML officer decision is active for this account."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:238
+msgid "Account type unavailable"
+msgstr "Account type unavailable"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:239
msgid ""
-"Suppress flagging this account when it creates a hit on a sanctions list, "
-"this is a false-positive"
+"Open this case from the account directory or payto search to see the "
+"applicable default rules."
msgstr ""
+"Open this case from the account directory or payto search to see the "
+"applicable default rules."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:190
-msgid "Failed to make the decision."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:248
+msgid "Default rules could not be loaded"
+msgstr "Default rules could not be loaded"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:193
-msgid "Invalid credentials."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:255
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:419
+#: packages/taler-exchange-aml-webui/src/components/ShowDefaultRules.tsx:11
+msgid "Default rules"
+msgstr "Default rules"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:197
-msgid ""
-"The session is disabled or a more recent decision was already submitted."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:266
+msgid "Collected information"
+msgstr "Collected information"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:208
-msgid "Confirmation required"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:267
+msgid "KYC information filed by the customer or an AML officer."
+msgstr "KYC information filed by the customer or an AML officer."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:209
-msgid ""
-"This decision declares that the MROS report has concluded. Please make sure "
-"that this is the case"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:273
+msgid "Collected information could not be loaded"
+msgstr "Collected information could not be loaded"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:279
+msgid "No collected information"
+msgstr "No collected information"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:280
+msgid "No KYC information has been collected for this account."
+msgstr "No KYC information has been collected for this account."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:302
+msgid "Active requirements"
+msgstr "Active requirements"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:303
+msgid "Measures the customer must complete under the current policy."
+msgstr "Measures the customer must complete under the current policy."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:309
+msgid "Active requirements could not be loaded"
+msgstr "Active requirements could not be loaded"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:315
+msgid "No active requirements"
+msgstr "No active requirements"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:316
+msgid "The customer has no active legitimization measures to complete."
+msgstr "The customer has no active legitimization measures to complete."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:413
+msgid "Officer decision"
+msgstr "Officer decision"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:416
+msgid "Does not expire"
+msgstr "Does not expire"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:439
+msgid "Waiting"
+msgstr "Waiting"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:451
+msgid "More on later pages"
+msgstr "More on later pages"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:510
+msgid "Try loading this section again."
+msgstr "Try loading this section again."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:518
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:97
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:633
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:205
+msgid "Retry"
+msgstr "Retry"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:566
+msgid "Unconfigured form"
+msgstr "Unconfigured form"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:567
+msgid "Form not identified"
+msgstr "Form not identified"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:576
+msgid "Filed by an AML officer"
+msgstr "Filed by an AML officer"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:577
+msgid "Provided by the customer"
+msgstr "Provided by the customer"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:581
+msgid "Attribute data is unavailable."
+msgstr "Attribute data is unavailable."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:595
+msgid "View details"
+msgstr "View details"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:70
+msgid ""
+"Review superseded AML decisions for this account, from newest to oldest."
+msgstr ""
+"Review superseded AML decisions for this account, from newest to oldest."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:79
+msgid "Loading decision history…"
+msgstr "Loading decision history…"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:84
+msgid "Decision history could not be loaded"
+msgstr "Decision history could not be loaded"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:87
+msgid "Try loading the decision history again."
+msgstr "Try loading the decision history again."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:111
+msgid "No previous decisions"
+msgstr "No previous decisions"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:114
+msgid "No superseded AML decisions have been recorded for this account."
+msgstr "No superseded AML decisions have been recorded for this account."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:125
+msgid "Previous decisions"
+msgstr "Previous decisions"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:153
+msgid "The export could not be prepared. Try again."
+msgstr "The export could not be prepared. Try again."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:164
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:173
+msgid "Failed to load accounts"
+msgstr "Failed to load accounts"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:193
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:552
+msgid "Accounts"
+msgstr "Accounts"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:196
+msgid "Review accounts known to the exchange for AML and KYC handling."
+msgstr "Review accounts known to the exchange for AML and KYC handling."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:203
+msgid "Export filtered accounts"
+msgstr "Export filtered accounts"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:211
+msgid "Download CSV"
+msgstr "Download CSV"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:218
+msgid "Download Excel"
+msgstr "Download Excel"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:226
+msgid "Preparing export…"
+msgstr "Preparing export…"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:230
+msgid "Export failed"
+msgstr "Export failed"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:236
+msgid "Account filters"
+msgstr "Account filters"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:242
+msgid "Investigation"
+msgstr "Investigation"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:244
+msgid "All accounts"
+msgstr "All accounts"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:251
+msgid "Risk"
+msgstr "Risk"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:253
+msgid "All risk levels"
+msgstr "All risk levels"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:255
+msgid "Not high risk"
+msgstr "Not high risk"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:260
+msgid "File status"
+msgstr "File status"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:262
+msgid "All file statuses"
+msgstr "All file statuses"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:264
+msgid "Not open"
+msgstr "Not open"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:273
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:589
+msgid "Clear filters"
+msgstr "Clear filters"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:283
+msgid "Showing %1$s accounts · newest first"
+msgstr "Showing %1$s accounts · newest first"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:290
+msgid "AML and KYC accounts"
+msgstr "AML and KYC accounts"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:298
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:458
+msgid "Account lifecycle"
+msgstr "Account lifecycle"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:304
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:467
+msgid "Latest note"
+msgstr "Latest note"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:550
+msgid "Copied"
+msgstr "Copied"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:550
+msgid "Copy"
+msgstr "Copy"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:576
+msgid "No matching accounts"
+msgstr "No matching accounts"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:576
+msgid "No accounts yet"
+msgstr "No accounts yet"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:580
+msgid "No accounts match the selected filters."
+msgstr "No accounts match the selected filters."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:581
+msgid "The exchange has not recorded any AML or KYC accounts yet."
+msgstr "The exchange has not recorded any AML or KYC accounts yet."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:647
+msgid "This officer session is not authorized to list accounts."
+msgstr "This officer session is not authorized to list accounts."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:649
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:674
+msgid "The exchange does not recognize this officer session."
+msgstr "The exchange does not recognize this officer session."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:651
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:676
+msgid "This officer session is currently disabled."
+msgstr "This officer session is currently disabled."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:668
+msgid "There are no matching accounts to export."
+msgstr "There are no matching accounts to export."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:670
+msgid "The exchange does not support the selected export format."
+msgstr "The exchange does not support the selected export format."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:672
+msgid "This officer session is not authorized to export accounts."
+msgstr "This officer session is not authorized to export accounts."
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:52
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:546
+msgid "Dashboard"
+msgstr "Dashboard"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:55
+msgid ""
+"Review cases requiring attention, investigate accounts, and monitor AML "
+"reporting indicators."
+msgstr ""
+"Review cases requiring attention, investigate accounts, and monitor AML "
+"reporting indicators."
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:77
+msgid "Review case queue"
+msgstr "Review case queue"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:80
+#, fuzzy
+#| msgid "The account was not found."
+msgid "Review accounts currently under investigation."
+msgstr "The account was not found."
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:94
+#, fuzzy
+#| msgid "Transfers"
+msgid "Inspect transfers"
+msgstr "Transfers"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:97
+msgid "Find credit, debit, and KYC authorization activity."
+msgstr "Find credit, debit, and KYC authorization activity."
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:128
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:165
+msgid "Statistics"
+msgstr "Statistics"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:132
+msgid "No reporting profile for this dialect"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:137
+msgid ""
+"The testing dialect does not define dashboard statistics. Select TOPS in "
+"development settings to inspect the TOPS reporting profile."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:154
+msgid "Failed to load TOPS statistics."
+msgstr "Failed to load TOPS statistics."
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:192
+msgid "Some statistics are unavailable."
+msgstr "Some statistics are unavailable."
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:195
+msgid "The available values are shown below. Missing values are not zero."
+msgstr "The available values are shown below. Missing values are not zero."
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:275
+msgid "Accounts open"
+msgstr "Accounts open"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:278
+msgid "New files last year"
+msgstr "New files last year"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:281
+msgid "Closed files last year"
+msgstr "Closed files last year"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:284
+msgid "MROS substantiated"
+msgstr "MROS substantiated"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:287
+msgid "MROS simple"
+msgstr "MROS simple"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:290
+msgid "High risk files"
+msgstr "High risk files"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:293
+msgid "PEP files"
+msgstr "PEP files"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:333
+msgid "Number of accounts that are opened"
+msgstr "Number of accounts that are opened"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:336
+msgid "Number of new GwG files in the last year"
+msgstr "Number of new GwG files in the last year"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:339
+msgid "Number of GwG files closed in the last year"
+msgstr "Number of GwG files closed in the last year"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:342
+msgid "Number of MROS reports based on Art 9 Abs. 1 GwG (per year)"
+msgstr "Number of MROS reports based on Art 9 Abs. 1 GwG (per year)"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:345
+msgid "Number of MROS reports based on Art 305ter Abs. 2 StGB (per year)"
+msgstr "Number of MROS reports based on Art 305ter Abs. 2 StGB (per year)"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:348
+msgid "Number of GwG files of high-risk customers"
+msgstr "Number of GwG files of high-risk customers"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:351
+msgid "Number of GwG files managed with “increased risk” due to PEP status"
+msgstr "Number of GwG files managed with “increased risk” due to PEP status"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:354
+msgid "Number of customers with open proceeding."
+msgstr "Number of customers with open proceeding."
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:400
+msgid "previous"
+msgstr "previous"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:443
+msgid "Decreased by"
+msgstr "Decreased by"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:447
+msgid "Increased by"
+msgstr "Increased by"
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:114
+#, fuzzy
+#| msgid "Events are derived from the proposed account state."
+msgid ""
+"The built-in event selection differs from the events derived from the "
+"proposed account state."
+msgstr "Events are derived from the proposed account state."
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:119
+msgid ""
+"Built-in events are derived from changes to the proposed account properties. "
+"They are stored for reporting and statistics; they do not notify the "
+"customer."
msgstr ""
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:138
+#, fuzzy
+#| msgid "Reset to default"
+msgid "Reset to derived events"
+msgstr "Reset to default"
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:169
+msgid "Calculated"
+msgstr "Calculated"
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:170
+#, fuzzy
+#| msgid "Events are derived from the proposed account state."
+msgid ""
+"Events derived from proposed property changes and submitted information."
+msgstr "Events are derived from the proposed account state."
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:184
+msgid "Other built-in events"
+msgstr ""
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:185
+#, fuzzy
+#| msgid "Events that can be triggered manually"
+msgid "Additional events that may be recorded manually."
+msgstr "Events that can be triggered manually"
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:198
+#, fuzzy
+#| msgid "No events"
+msgid "Custom events"
+msgstr "No events"
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:199
+msgid "Operator-defined event names that are not part of the selected dialect."
+msgstr ""
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:213
+#, fuzzy
+#| msgid "Describe the decision."
+msgid "Events recorded with this decision"
+msgstr "Describe the decision."
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:214
+#, fuzzy
+#| msgid ""
+#| "The events will be triggered only after the decision has been confirmed."
+msgid "Events are added only after the decision is successfully submitted."
+msgstr ""
+"The events will be triggered only after the decision has been confirmed."
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:209
+#, fuzzy
+#| msgid "System information"
+msgid "Add customer information"
+msgstr "System information"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:212
+msgid ""
+"The completed form is attached to this AML decision as reviewed account "
+"information. It does not create a customer-facing measure."
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:223
+#, fuzzy
+#| msgid "Collected information"
+msgid "Selected form"
+msgstr "Collected information"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:233
+#, fuzzy
+#| msgid "Complete the form"
+msgid "Choose another form"
+msgstr "Complete the form"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:242
+msgid "Expiration"
+msgstr "Expiration"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:243
+msgid "Expiration date of the information filled in this form."
+msgstr "Expiration date of the information filled in this form."
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:254
+msgid "Form context"
+msgstr "Form context"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:261
+#, fuzzy
+#| msgid "Form context"
+msgid "Advanced form context"
+msgstr "Form context"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:264
+msgid ""
+"Only change this operator-defined JSON when the form documentation requires "
+"additional context."
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:270
+msgid "Context as JSON"
+msgstr "Context as JSON"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:291
+msgid "Invalid JSON"
+msgstr "Invalid JSON"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:296
+msgid "Invalid expiration"
+msgstr "Invalid expiration"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:297
+msgid "Attributes require an expiration date in the future or set to Never."
+msgstr "Attributes require an expiration date in the future or set to Never."
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:355
+msgid "Include new information"
+msgstr "Include new information"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:356
+msgid ""
+"This step is optional. Select a form to attach newly reviewed AML/KYC "
+"information, or continue without one."
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:361
+msgid "AML/KYC form"
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:362
+msgid "Search AML/KYC forms"
+msgstr "Search AML/KYC forms"
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:101
+#, fuzzy
+#| msgid "The account will not remain under investigation."
+msgid "The account will be included in the AML investigation queue."
+msgstr "The account will not remain under investigation."
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:106
+#, fuzzy
+#| msgid "The account will not remain under investigation."
+msgid "The account will not be included in the AML investigation queue."
+msgstr "The account will not remain under investigation."
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:114
+#, fuzzy
+#| msgid "Investigation"
+msgid "Current investigation status"
+msgstr "Investigation"
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:128
+#, fuzzy
+#| msgid "No previous decisions"
+msgid "No previous decision"
+msgstr "No previous decisions"
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:140
+#, fuzzy
+#| msgid "Investigation"
+msgid "Investigation status after this decision"
+msgstr "Investigation"
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:145
+#, fuzzy
+#| msgid "Measures the customer must complete under the current policy."
+msgid ""
+"Choose whether the account should remain in the AML investigation queue "
+"after this decision is submitted."
+msgstr "Measures the customer must complete under the current policy."
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:201
+msgid ""
+"Full name used in the payto URI when creating this previously unknown "
+"account."
+msgstr ""
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:208
+#, fuzzy
+#| msgid "Decision date"
+msgid "Decision rationale"
+msgstr "Decision date"
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:209
+msgid ""
+"Record the facts and reasoning needed to understand this decision in a later "
+"audit or review."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:264
+#, fuzzy
+#| msgid "Custom measures"
+msgid "Create custom measure"
+msgstr "Custom measures"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:266
+#, fuzzy
+#| msgid "Add custom measure"
+msgid "Edit custom measure"
+msgstr "Add custom measure"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:270
+msgid ""
+"Combine a customer check with an AML program, or use SKIP to run a program "
+"immediately. Context values must satisfy the selected check and program "
+"requirements."
+msgstr ""
+
+#. screenid: 122
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:289
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:478
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:366
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:115
+msgid "Add custom measure"
+msgstr "Add custom measure"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:299
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:488
+msgid "Save changes"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:306
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:495
+#, fuzzy
+#| msgid "Add custom measure"
+msgid "Remove custom measure"
+msgstr "Add custom measure"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:547
+#, fuzzy
+#| msgid "Configure verification type: %1$s"
+msgid "Configure %1$s verification"
+msgstr "Configure verification type: %1$s"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:558
+msgid "Use advanced measure editor"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:587
+#, fuzzy
+#| msgid "Name of the verification measure"
+msgid "Use guided verification editor"
+msgstr "Name of the verification measure"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:632
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1111
+msgid "There is already a measure with that name"
+msgstr "There is already a measure with that name"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:646
+msgid ""
+"Runs immediately for SKIP measures, or after a successful check. It may be "
+"omitted for a check that only presents or collects information."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:650
+msgid "Missing check or program"
+msgstr "Missing check or program"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:660
+msgid ""
+"The customer-facing check to perform before the program. Leave empty to use "
+"SKIP and run the program immediately."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:683
+msgid ""
+"Configuration values required by the selected check or program. Property "
+"names and value types must match the exchange configuration."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:690
+msgid "Field name"
+msgstr "Field name"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:695
+msgid "Type"
+msgstr "Type"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:699
+msgid "string"
+msgstr "string"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:703
+msgid "number"
+msgstr "number"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:707
+msgid "boolean"
+msgstr "boolean"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:711
+msgid "json"
+msgstr "json"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:738
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:792
+#, fuzzy
+#| msgid "Form not available"
+msgid "Program \"%1$s\" is not available"
+msgstr "Form not available"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:742
+msgid "There are unsatisfied inputs: %1$s"
+msgstr "There are unsatisfied inputs: %1$s"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:750
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:772
+msgid "Check \"%1$s\" is not available"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:756
+msgid "There are missing inputs: %1$s"
+msgstr "There are missing inputs: %1$s"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:779
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:799
+msgid "There are missing requirements: %1$s"
+msgstr "There are missing requirements: %1$s"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:855
+msgid "Can't be empty"
+msgstr "Can't be empty"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:859
+msgid "Not a number"
+msgstr "Not a number"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:861
+msgid "It should be finite"
+msgstr "It should be finite"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:866
+msgid "It should be either \"true\" or \"false\""
+msgstr "It should be either \"true\" or \"false\""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:871
+msgid "Couldn't parse as json string: %1$s"
+msgstr "Couldn't parse as json string: %1$s"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:899
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:946
+msgid "Description"
+msgstr "Description"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:915
+msgid "Inputs"
+msgstr "Inputs"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:954
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:534
+#, fuzzy
+#| msgid "Output"
+msgid "Outputs"
+msgstr "Output"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:962
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:401
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:533
+#, fuzzy
+#| msgid "Required"
+msgid "Required context"
+msgstr "Required"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:970
+msgid "Fallback"
+msgstr "Fallback"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:993
+#, fuzzy
+#| msgid "Context as JSON"
+msgid "Context values"
+msgstr "Context as JSON"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1045
+msgid "Selected pipeline"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1048
+msgid "Review how the exchange will execute this measure."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1105
+msgid "Name of the verification measure"
+msgstr "Name of the verification measure"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1118
+msgid "Read only"
+msgstr "Read only"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1119
+msgid "Prevent the customer from changing the address"
+msgstr "Prevent the customer from changing the address"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:154
+msgid "Customer actions after submission"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:157
+msgid ""
+"Immediate measures start as soon as this decision is accepted. A measure may "
+"show information, collect customer data, or run an AML program. Leave the "
+"selection empty when no immediate customer action is required."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:302
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:301
+msgid "Too many SKIP measures"
+msgstr "Too many SKIP measures"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:303
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:302
+msgid "At most one immediate measure may use the SKIP check."
+msgstr "At most one immediate measure may use the SKIP check."
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:332
+#, fuzzy
+#| msgid "Configure verification measure: \"%1$s\""
+msgid "Configure verification measure “%1$s”"
+msgstr "Configure verification measure: \"%1$s\""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:372
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:522
+msgid "Custom measures"
+msgstr "Custom measures"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:375
+#, fuzzy
+#| msgid "Events are derived from the proposed account state."
+msgid "Measures defined only for this proposed decision."
+msgstr "Events are derived from the proposed account state."
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:399
+msgid "Edit"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:407
+#, fuzzy
+#| msgid "All measures"
+msgid "Available exchange measures"
+msgstr "All measures"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:410
+msgid "Reusable templates configured by the exchange operator"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:432
+msgid "Use as template"
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:512
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:288
+#, fuzzy
+#| msgid "Instant measures"
+msgid "Immediate measures"
+msgstr "Instant measures"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:513
+msgid ""
+"Selected measures begin immediately after the decision is accepted by the "
+"exchange."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:518
+#, fuzzy
+#| msgid "Require all measures"
+msgid "Require every selected measure"
+msgstr "Require all measures"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:519
+#, fuzzy
+#| msgid ""
+#| "Run all selected measures together instead of accepting any one of them."
+msgid ""
+"When enabled, all selected measures must be completed. Otherwise, completing "
+"any one of them is sufficient."
+msgstr ""
+"Run all selected measures together instead of accepting any one of them."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:190
+msgid "Failed to make the decision."
+msgstr "Failed to make the decision."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:193
+msgid "Invalid credentials."
+msgstr "Invalid credentials."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:195
+msgid "Session not found. Contact the administrator."
+msgstr "Session not found. Contact the administrator."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:197
+msgid ""
+"The exchange rejected the decision because the officer session is disabled "
+"or the account has a newer decision. Reload the account before trying again."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:251
+msgid ""
+"This decision records that an MROS report was filed. Confirm that the report "
+"has actually been submitted before continuing."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:264
+#, fuzzy
+#| msgid "No manual review"
+msgid "Go back and review"
+msgstr "No manual review"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:271
+msgid "Confirm decision"
+msgstr "Confirm decision"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:283
+msgid "Unknown measure"
+msgstr "Unknown measure"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:284
+msgid ""
+"A rule or immediate action references a measure that is not available. "
+"Review the rules and measures before submitting."
+msgstr ""
+"A rule or immediate action references a measure that is not available. "
+"Review the rules and measures before submitting."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:291
+#, fuzzy
+#| msgid "Add custom measure"
+msgid "Invalid custom measure"
+msgstr "Add custom measure"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:292
+msgid ""
+"A custom measure references an unavailable check or program, lacks required "
+"context, or cannot provide the selected program inputs. Review the immediate "
+"measures before submitting."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:310
+msgid "Missing deadline"
+msgstr "Missing deadline"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:311
+msgid "Set when the proposed rules expire and what should happen afterward."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:319
+msgid "Invalid rule expiration"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:320
+msgid "Rule expiration must be in the future or set to Never."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:327
+msgid "Missing rules"
+msgstr "Missing rules"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:328
+msgid ""
+"A decision must contain the complete rule set that will apply to the account."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:337
+msgid ""
+"Review the proposed rules. Hard blocks must be explicit, and Balance and "
+"Refund rules must use an instant timeframe."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:376
+msgid "Immediate measures not reviewed"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:378
+#, fuzzy
+#| msgid "Measures the customer must complete under the current policy."
+msgid "Review whether the customer must complete any immediate measures."
+msgstr "Measures the customer must complete under the current policy."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:384
+#, fuzzy
+#| msgid "Triggered immediately without customer interaction."
+msgid "No immediate customer action"
+msgstr "Triggered immediately without customer interaction."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:385
+msgid "No measure will start when this decision is submitted."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:396
+#, fuzzy
+#| msgid "Account properties"
+msgid "Account properties not reviewed"
+msgstr "Account properties"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:398
+msgid "Review the account properties before submitting the decision."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:409
+msgid "Reporting events not reviewed"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:411
+msgid "Review which statistical events will be recorded with the decision."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:420
+msgid "Case disposition incomplete"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:421
+msgid "You must complete the justification section."
+msgstr "You must complete the justification section."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:430
+msgid "Invalid attributes"
+msgstr "Invalid attributes"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:431
+msgid ""
+"Correct the selected form or continue without attaching new customer "
+"information."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:443
+msgid "Decision details"
+msgstr "Decision details"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:447
+msgid "Justification"
+msgstr "Justification"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:450
+msgid "Not provided"
+msgstr "Not provided"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:454
+#, fuzzy
+#| msgid "The account was not found."
+msgid "The account remains under investigation."
+msgstr "The account was not found."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:458
+msgid "The account will not remain under investigation."
+msgstr "The account will not remain under investigation."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:487
+msgid "No account properties"
+msgstr "No account properties"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:493
+msgid "Events"
+msgstr "Events"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:496
+msgid "No events"
+msgstr "No events"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:501
+msgid "Submitted attributes"
+msgstr "Submitted attributes"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:509
+msgid "expiration set"
+msgstr "expiration set"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:515
+msgid "No new attributes"
+msgstr "No new attributes"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:537
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:550
+#, fuzzy
+#| msgid "Officer decision"
+msgid "Discard decision"
+msgstr "Officer decision"
+
#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:222
-msgid "I want to check first!"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:544
+#, fuzzy
+#| msgid "Send decision"
+msgid "Submit AML decision"
+msgstr "Send decision"
#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:229
-msgid "Confirm decision"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:549
+#, fuzzy
+#| msgid "Discard this key"
+msgid "Discard this decision?"
+msgstr "Discard this key"
#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:245
-msgid "Missing deadline"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:554
+msgid ""
+"All entries made in this decision wizard will be lost. No change will be "
+"submitted to the exchange."
msgstr ""
#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:248
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:571
+#, fuzzy
+#| msgid "Review status"
+msgid "Review this step"
+msgstr "Review status"
+
+#. screenid: 113
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:172
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:250
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:507
+#, fuzzy
+#| msgid "Back to accounts"
+msgid "Back to account"
+msgstr "Back to accounts"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:177
+#, fuzzy
+#| msgid "New decision"
+msgid "New AML decision"
+msgstr "New decision"
+
+#. screenid: 113
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:201
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:297
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:790
+msgid "Payto URI"
+msgstr "Payto URI"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:218
+#, fuzzy
+#| msgctxt "threshold"
+#| msgid "%1$s every %2$s"
+msgid "Step %1$s of %2$s"
+msgstr "%1$s every %2$s"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:236
+msgid "Decision steps"
+msgstr "Decision steps"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:245
+msgid "Previous step"
+msgstr "Previous step"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:254
+msgid "Next step"
+msgstr "Next step"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:273
+#, fuzzy
+#| msgid "System information"
+msgid "Customer information"
+msgstr "System information"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:274
+#, fuzzy
+#| msgid ""
+#| "You can review AML information, but this officer key cannot submit "
+#| "decisions."
+msgid "Optionally add reviewed AML/KYC information to this decision."
+msgstr ""
+"You can review AML information, but this officer key cannot submit decisions."
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:279
+msgid "Review the account state derived from the available information."
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:283
+#, fuzzy
+#| msgid "Missing events"
+msgid "Reporting events"
+msgstr "Missing events"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:284
+msgid "Review the statistical events recorded with this decision."
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:289
+#, fuzzy
+#| msgid "Measures the customer must complete under the current policy."
msgid ""
-"Deadline should specify when this rules ends and what is the next measures "
-"to apply after expiration."
+"Choose actions the customer must complete after the decision is submitted."
+msgstr "Measures the customer must complete under the current policy."
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:293
+#, fuzzy
+#| msgctxt "operation type"
+#| msgid "Transaction"
+msgid "Transaction rules"
+msgstr "Transaction"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:294
+msgid "Set operation thresholds, escalation measures, and expiration behavior."
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:257
-msgid "Missing rules"
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:298
+msgid "Case disposition"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:260
-msgid "Can't make a decision without rules."
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:299
+#, fuzzy
+#| msgid "The account was not found."
+msgid "Record the rationale and whether the case remains under investigation."
+msgstr "The account was not found."
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:305
+#, fuzzy
+#| msgid "Review and submit."
+msgid "Review and submit"
+msgstr "Review and submit."
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:306
+msgid "Check the complete decision before signing and submitting it."
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:284
-msgid "Missing active measure"
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:326
+#, fuzzy
+#| msgid "Decision steps"
+msgid "Decision progress"
+msgstr "Decision steps"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:407
+#, fuzzy
+#| msgid "Failed to load account decisions."
+msgid "Loading account decision"
+msgstr "Failed to load account decisions."
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:418
+#, fuzzy
+#| msgid "Decision for account:"
+msgid "Decision for account"
+msgstr "Decision for account:"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:425
+#, fuzzy
+#| msgid "Decision for account:"
+msgid "Decision for wallet account"
+msgstr "Decision for account:"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:431
+#, fuzzy
+#| msgid "Decision for bank account:"
+msgid "Decision for bank account"
+msgstr "Decision for bank account:"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:107
+msgid "Enter a valid HTTP or HTTPS URL."
+msgstr "Enter a valid HTTP or HTTPS URL."
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:114
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:176
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:218
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:259
+msgid "Development settings"
+msgstr "Development settings"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:117
+msgid ""
+"These browser-local settings are intended for development and "
+"troubleshooting."
msgstr ""
+"These browser-local settings are intended for development and "
+"troubleshooting."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:287
-msgid "You should specify in the measure section."
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:132
+msgid "Exchange connection"
+msgstr "Exchange connection"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:135
+msgid ""
+"Changing the exchange reloads the application. The override is stored only "
+"in this browser."
msgstr ""
+"Changing the exchange reloads the application. The override is stored only "
+"in this browser."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:294
-msgid "No customer action required."
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:147
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:97
+msgid "Exchange base URL"
+msgstr "Exchange base URL"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:166
+msgid "Leave empty to use the configured URL: %1$s"
+msgstr "Leave empty to use the configured URL: %1$s"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:170
+msgid "Leave empty to derive the exchange URL from this page."
+msgstr "Leave empty to derive the exchange URL from this page."
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:184
+msgid "Currently connected to"
+msgstr "Currently connected to"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:196
+msgid "Apply and reload"
+msgstr "Apply and reload"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:207
+msgid "Use configured URL"
+msgstr "Use configured URL"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:214
+msgid "Preferences"
+msgstr "Preferences"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:221
+msgid "AML SPA dialect"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:297
-msgid "No active measure has been selected."
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:236
+#, fuzzy
+#| msgid "Welcome to the exchange configuration"
+msgid "Use exchange configuration"
+msgstr "Welcome to the exchange configuration"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:240
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:44
+msgid "Testing"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:305
-msgid "Missing properties"
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:244
+#, fuzzy
+#| msgid ""
+#| "Changing the exchange reloads the application. The override is stored "
+#| "only in this browser."
+msgid ""
+"Override how this web interface presents dialect-specific AML rules and "
+"properties. The override is stored only in this browser."
msgstr ""
+"Changing the exchange reloads the application. The override is stored only "
+"in this browser."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:308
-msgid "You should specify in the properties section."
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:262
+msgid "Show debug information"
+msgstr "Show debug information"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:45
+msgid "Fallback dialect for development and testing."
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:318
-msgid "Missing events"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:52
+msgid "TOPS"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:321
-msgid "You should specify in the events section."
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:53
+msgid "Taler Operations deployment for Swiss AML processes."
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:331
-msgid "Missing justification"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:56
+msgid "File note"
+msgstr "File note"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:57
+#, fuzzy
+#| msgid "Current note on the GwG file"
+msgid "Current note on the GwG file."
+msgstr "Current note on the GwG file"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:58
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:64
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:112
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:124
+msgid "Text"
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:334
-msgid "You must complete the justification section."
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:62
+msgid "Customer label"
+msgstr "Customer label"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:68
+msgid "Account open"
+msgstr "Account open"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:69
+#, fuzzy
+#| msgid "Is the account active for deposit and payments?"
+msgid "Whether the account is active for deposits and payments."
+msgstr "Is the account active for deposit and payments?"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:70
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:76
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:82
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:88
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:94
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:100
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:106
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:142
+#, fuzzy
+#| msgid "boolean"
+msgid "Boolean"
+msgstr "boolean"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:74
+msgid "Domestic PEP"
+msgstr "Domestic PEP"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:75
+msgid "Whether the customer is a domestic politically exposed person."
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:344
-msgid "Invalid attributes"
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:80
+msgid "Foreign PEP"
+msgstr "Foreign PEP"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:81
+msgid "Whether the customer is a foreign politically exposed person."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:86
+msgid "International-organization PEP"
+msgstr "International-organization PEP"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:87
+msgid ""
+"Whether the customer is a politically exposed person associated with an "
+"international organization."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:92
+msgid "High-risk customer"
+msgstr "High-risk customer"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:93
+#, fuzzy
+#| msgid "Measures the customer must complete under the current policy."
+msgid "Whether the customer is classified as high risk."
+msgstr "Measures the customer must complete under the current policy."
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:98
+msgid "High-risk country"
+msgstr "High-risk country"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:99
+msgid "Whether the customer is associated with a high-risk country."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:104
+msgid "Account idle"
+msgstr "Account idle"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:105
+msgid "Whether the account has been marked as idle."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:110
+#, fuzzy
+#| msgid "Investigation trigger"
+msgid "Investigation trigger"
+msgstr "Investigation trigger"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:111
+#, fuzzy
+#| msgid "Informal reason why the AML investigation was triggered"
+msgid "Informal reason why the AML investigation was triggered."
+msgstr "Informal reason why the AML investigation was triggered"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:116
+#, fuzzy
+#| msgid "Investigation"
+msgid "Investigation state"
+msgstr "Investigation"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:117
+#, fuzzy
+#| msgid "The MROS reporting state for the account."
+msgid "Special-clarification and MROS reporting state for the account."
+msgstr "The MROS reporting state for the account."
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:118
+#, fuzzy
+#| msgid "Operation"
+msgid "Enumeration"
+msgstr "Operation"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:122
+#, fuzzy
+#| msgid "Sanctions-list best match"
+msgid "Sanction-list best match"
+msgstr "Sanctions-list best match"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:123
+#, fuzzy
+#| msgid "Identifies the sanction list entry that the account matched against"
+msgid ""
+"Sanction-list entry that best matched the account, regardless of match "
+"quality."
+msgstr "Identifies the sanction list entry that the account matched against"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:128
+#, fuzzy
+#| msgid "Sanctions-list rating"
+msgid "Sanction-list rating"
+msgstr "Sanctions-list rating"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:129
+msgid "Score from 0 (no match) to 1,000,000,000 (best match)."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:130
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:136
+msgid "Integer"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:134
+#, fuzzy
+#| msgid "Sanctions-list confidence"
+msgid "Sanction-list confidence"
+msgstr "Sanctions-list confidence"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:135
+msgid ""
+"Score from 0 (no supporting data) to 1,000,000,000 (highest confidence)."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:140
+#, fuzzy
+#| msgid "Suppress sanctions-list match"
+msgid "Suppress sanction-list match"
+msgstr "Suppress sanctions-list match"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:141
+msgid ""
+"Whether this account's sanction-list hit is treated as a false positive."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:148
+#, fuzzy
+#| msgid "Account open"
+msgid "Account opened"
+msgstr "Account open"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:149
+msgid "Recorded when an account changes to open."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:153
+#, fuzzy
+#| msgid "Account case"
+msgid "Account closed"
+msgstr "Account case"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:154
+msgid "Recorded when an account changes from open to closed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:158
+#, fuzzy
+#| msgid "High-risk customer"
+msgid "High-risk customer classification added"
+msgstr "High-risk customer"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:159
+msgid ""
+"Recorded when an open account becomes classified as a high-risk customer."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:163
+#, fuzzy
+#| msgid "High-risk customer"
+msgid "High-risk customer classification removed"
+msgstr "High-risk customer"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:164
+msgid "Recorded when the high-risk customer classification is removed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:168
+#, fuzzy
+#| msgid "High-risk country"
+msgid "High-risk country classification added"
+msgstr "High-risk country"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:169
+msgid ""
+"Recorded when an open account becomes associated with a high-risk country."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:173
+msgid "High-risk country classification removed"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:174
+msgid "Recorded when the high-risk country classification is removed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:178
+msgid "PEP classification added"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:179
+msgid "Recorded when an open account becomes associated with any PEP category."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:183
+#, fuzzy
+#| msgid "No justification was recorded."
+msgid "PEP classification removed"
+msgstr "No justification was recorded."
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:184
+msgid ""
+"Recorded when the account is no longer associated with any PEP category."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:188
+msgid "Foreign PEP classification added"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:189
+msgid "Recorded when an open account becomes associated with a foreign PEP."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:193
+msgid "Foreign PEP classification removed"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:194
+msgid "Recorded when the foreign PEP classification is removed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:198
+msgid "Domestic PEP classification added"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:199
+msgid "Recorded when an open account becomes associated with a domestic PEP."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:203
+msgid "Domestic PEP classification removed"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:204
+msgid "Recorded when the domestic PEP classification is removed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:208
+#, fuzzy
+#| msgid "International-organization PEP"
+msgid "International-organization PEP classification added"
+msgstr "International-organization PEP"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:209
+#, fuzzy
+#| msgid "Does account belong to an international-organization PEP?"
+msgid ""
+"Recorded when an open account becomes associated with an international-"
+"organization PEP."
+msgstr "Does account belong to an international-organization PEP?"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:213
+#, fuzzy
+#| msgid "International-organization PEP"
+msgid "International-organization PEP classification removed"
+msgstr "International-organization PEP"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:214
+msgid ""
+"Recorded when the international-organization PEP classification is removed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:218
+msgid "Simple suspicion reported to MROS"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:219
+msgid "Recorded when a report is filed under Article 305ter paragraph 2 StGB."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:223
+#, fuzzy
+#| msgid "Reported substantiated suspicion"
+msgid "Substantiated suspicion reported to MROS"
+msgstr "Reported substantiated suspicion"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:224
+msgid "Recorded when a report is filed under Article 9 GwG."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:228
+#, fuzzy
+#| msgid "Investigation trigger"
+msgid "Investigation concluded"
+msgstr "Investigation trigger"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:229
+msgid "Recorded when a pending special clarification is concluded."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:233
+#, fuzzy
+#| msgid "Investigation trigger"
+msgid "Investigation conclusion reversed"
+msgstr "Investigation trigger"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:234
+msgid ""
+"Recorded when a previously concluded investigation returns to a non-"
+"concluded state."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:50
+msgid "Browser override"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:52
+#, fuzzy
+#| msgid "Welcome to the exchange configuration"
+msgid "Exchange configuration"
+msgstr "Welcome to the exchange configuration"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:53
+#, fuzzy
+#| msgid "Default rules"
+msgid "Default fallback"
+msgstr "Default rules"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:59
+#, fuzzy
+#| msgid "Welcome to the exchange configuration"
+msgid "Exchange and AML configuration"
+msgstr "Welcome to the exchange configuration"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:62
+msgid ""
+"Exchange identity, the active AML dialect, and the checks and programs "
+"available to AML decisions."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:71
+msgid "Public information reported by this exchange."
msgstr ""
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:347
-msgid "You should check form errors or submit a decision without attributes."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:75
+msgid "Base URL"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:76
+msgid "Protocol"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:77
+msgid "Protocol version"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:78
+#, fuzzy
+#| msgid "Operation"
+msgid "Implementation"
+msgstr "Operation"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:80
+#, fuzzy
+#| msgid "Not provided"
+msgid "Not reported"
+msgstr "Not provided"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:82
+msgid "Currency"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:88
+msgid "AML dialect"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:95
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:119
+#, fuzzy
+#| msgid "Effective decision"
+msgid "Effective dialect"
+msgstr "Effective decision"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:111
+#, fuzzy
+#| msgid "Configure measure"
+msgid "Configured dialect"
+msgstr "Configure measure"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:114
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:504
+#, fuzzy
+#| msgid "Not opened"
+msgid "Not specified"
+msgstr "Not opened"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:129
+msgid "Canonical properties defined by the effective dialect."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:130
+#, fuzzy
+#| msgid "No account properties"
+msgid "This dialect does not define account properties."
+msgstr "No account properties"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:136
+#, fuzzy
+#| msgid "Reset to default"
+msgid "Derived events"
+msgstr "Reset to default"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:137
+#, fuzzy
+#| msgid "No account properties"
+msgid "Canonical events derived from account property changes."
+msgstr "No account properties"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:138
+msgid "This dialect does not define derived events."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:144
+#, fuzzy
+#| msgid "All measures"
+msgid "AML measures"
+msgstr "All measures"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:145
+msgid ""
+"Checks, programs, root measures, and default rules reported by the exchange."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:213
+msgid "%1$s entry"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:214
+msgid "%1$s entries"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:277
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:289
+#, fuzzy
+#| msgid "Failed to load the measures"
+msgid "Failed to load the exchange AML measures."
+msgstr "Failed to load the measures"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:300
+#, fuzzy
+#| msgid "The measures endpoint was not found."
+msgid "The measures endpoint is not available."
+msgstr "The measures endpoint was not found."
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:306
+#, fuzzy
+#| msgid "The account state changed. Reload it and try again."
+msgid "The exchange configuration changed. Reload it and try again."
+msgstr "The account state changed. Reload it and try again."
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:332
+#, fuzzy
+#| msgid "Failed to load the measures"
+msgid "Retry loading measures"
+msgstr "Failed to load the measures"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:351
+#, fuzzy
+#| msgid "Reset measure"
+msgid "Root measures"
+msgstr "Reset measure"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:366
+msgid "No root measures are configured."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:371
+#, fuzzy
+#| msgid "Check"
+msgid "KYC checks"
+msgstr "Check"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:386
+msgid "No KYC checks are configured."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:391
+#, fuzzy
+#| msgid "Program"
+msgid "AML programs"
+msgstr "Program"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:405
+#, fuzzy
+#| msgid "Requirements"
+msgid "Required inputs"
+msgstr "Requirements"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:413
+msgid "No AML programs are configured."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:428
+msgid "No default AML rules are configured."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:480
+#, fuzzy
+#| msgid "Check"
+msgid "KYC check"
+msgstr "Check"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:484
+msgid "Built-in check that proceeds without collecting customer data."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:491
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:497
+#, fuzzy
+#| msgid "Program"
+msgid "AML program"
+msgstr "Program"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:536
+#, fuzzy
+#| msgid "All measures"
+msgid "Fallback measure"
+msgstr "All measures"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:602
+#, fuzzy
+#| msgid "Unavailable"
+msgid "Unavailable reference"
+msgstr "Unavailable"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:48
+msgid "Session and access"
+msgstr "Session and access"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:51
+msgid ""
+"Review this officer's exchange access and manage the unlocked key in this "
+"browser."
+msgstr ""
+"Review this officer's exchange access and manage the unlocked key in this "
+"browser."
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:66
+msgid "Officer access"
+msgstr "Officer access"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:71
+msgid "Officer name"
+msgstr "Officer name"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:77
+msgid "Permissions"
+msgstr "Permissions"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:88
+msgid "Read-only"
+msgstr "Read-only"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:361
-msgid "Clear"
-msgstr ""
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:90
+msgid "Read and write"
+msgstr "Read and write"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:368
-msgid "Send decision"
-msgstr ""
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:118
+msgid "Session security"
+msgstr "Session security"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:173
-msgid "Prev"
-msgstr ""
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:121
+msgid "Lock the session when you leave this device unattended."
+msgstr "Lock the session when you leave this device unattended."
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:182
-msgid "Next"
-msgstr ""
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:133
+msgid "Lock now"
+msgstr "Lock now"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:207
-msgid "Attributes"
-msgstr ""
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:148
+msgid "Unlocked"
+msgstr "Unlocked"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:208
-msgid "Add more information about the customer"
-msgstr ""
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:154
+msgid "Locks automatically"
+msgstr "Locks automatically"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:212
-msgid "Rules"
-msgstr ""
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:165
+msgid "Exact time"
+msgstr "Exact time"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:213
-msgid "Set the limit of the operations"
-msgstr ""
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:185
+msgid "Copy public key"
+msgstr "Copy public key"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:218
-msgid "Trigger notifications."
-msgstr ""
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:200
+msgid "Remove key from this browser"
+msgstr "Remove key from this browser"
-#. screenid: 113
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:222
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:102
-msgid "Measures"
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:203
+msgid ""
+"Removing this key deletes the officer key from this browser. It does not "
+"revoke or change the officer's access at the exchange. Ask the exchange "
+"operator to revoke access if needed."
msgstr ""
+"Removing this key deletes the officer key from this browser. It does not "
+"revoke or change the officer's access at the exchange. Ask the exchange "
+"operator to revoke access if needed."
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:223
-msgid "Ask the customer to take action."
-msgstr ""
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:214
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:222
+msgid "Remove key"
+msgstr "Remove key"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:228
-msgid "Describe the decision."
-msgstr ""
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:221
+msgid "Remove officer key?"
+msgstr "Remove officer key?"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:235
-msgid "Flag the current account state."
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:231
+msgid ""
+"This deletes the officer key from this browser. You will need to create and "
+"enroll a new key to use the AML WebUI here again."
msgstr ""
+"This deletes the officer key from this browser. You will need to create and "
+"enroll a new key to use the AML WebUI here again."
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:239
-msgid "Summary"
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:237
+msgid ""
+"This does not revoke the officer at the exchange. Ask the exchange operator "
+"to revoke its access if the key may be compromised."
msgstr ""
+"This does not revoke the officer at the exchange. Ask the exchange operator "
+"to revoke its access if the key may be compromised."
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:240
-msgid "Review and submit."
-msgstr ""
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:86
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:559
+msgid "Find account"
+msgstr "Find account"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:404
-msgid "Decision for account:"
-msgstr ""
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:89
+msgid "Look up an account by its payto information or normalized payto hash."
+msgstr "Look up an account by its payto information or normalized payto hash."
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:411
-msgid "Decision for wallet:"
-msgstr ""
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:100
+msgid "Find by payto"
+msgstr "Find by payto"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:417
-msgid "Decision for bank account:"
-msgstr ""
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:146
+msgid "Find by normalized payto hash"
+msgstr "Find by normalized payto hash"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:88
-msgid "Search account"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:169
+msgid "Enter a valid 52-character normalized payto hash."
+msgstr "Enter a valid 52-character normalized payto hash."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:179
+msgid "Open account"
+msgstr "Open account"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:154
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:214
msgid "Failed to load account decisions."
-msgstr ""
+msgstr "Failed to load account decisions."
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:163
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:223
msgid "Failed to load the account history."
-msgstr ""
+msgstr "Failed to load the account history."
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:205
-msgid "Check account details"
+#. screenid: 110
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:228
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:82
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:268
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:66
+msgid ""
+"This session signature is invalid, contact administrator or create a new one."
msgstr ""
+"This session signature is invalid, contact administrator or create a new one."
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:212
-msgid "Account most recent decisions"
+#. screenid: 110
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:235
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:89
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:275
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:73
+msgid ""
+"The designated AML session is not known, contact administrator or create a "
+"new one."
msgstr ""
+"The designated AML session is not known, contact administrator or create a "
+"new one."
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:231
-msgid "When"
+#. screenid: 110
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:242
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:96
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:282
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:80
+msgid ""
+"The designated AML session is not enabled, contact administrator or create a "
+"new one."
msgstr ""
+"The designated AML session is not enabled, contact administrator or create a "
+"new one."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:268
+#, fuzzy
+#| msgid "Account not found"
+msgid "Account found"
+msgstr "Account not found"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:265
-msgid "LATEST"
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:271
+msgid ""
+"This account has an AML decision history. Open its case to review current "
+"rules, measures, attributes, and past decisions."
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:270
-msgid "ACTIVE"
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:283
+#, fuzzy
+#| msgid "Open account"
+msgid "Open account case"
+msgstr "Open account"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:309
+msgid "Active"
msgstr ""
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:297
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:311
+#, fuzzy
+#| msgid "Effective decision"
+msgid "No active decision"
+msgstr "Effective decision"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:317
+#, fuzzy
+#| msgid "File status"
+msgid "Case status"
+msgstr "File status"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:321
+#, fuzzy
+#| msgid "Investigation trigger"
+msgid "Investigation required"
+msgstr "Investigation trigger"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:323
+#, fuzzy
+#| msgid "Investigation state"
+msgid "No investigation requested"
+msgstr "Investigation state"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:333
msgid "Account not found"
-msgstr ""
+msgstr "Account not found"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:298
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:335
msgid "There is no history known for this account yet."
-msgstr ""
+msgstr "There is no history known for this account yet."
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:308
-msgid "You can make a decision for this account anyway."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:350
+#, fuzzy
+#| msgid "You can make a decision for this account anyway."
+msgid "Start a decision for this account"
+msgstr "You can make a decision for this account anyway."
#. screenid: 111
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:357
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:400
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:449
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:490
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:377
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:403
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:445
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:493
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:533
msgid "Search"
-msgstr ""
-
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:528
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:761
-msgid "IBAN"
-msgstr ""
+msgstr "Search"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:532
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:575
msgid "Taler Bank"
-msgstr ""
+msgstr "Taler Bank"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:536
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:579
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:364
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:433
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:441
msgid "Wallet"
-msgstr ""
+msgstr "Wallet"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:540
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:583
msgid "Generic Payto:// URI"
-msgstr ""
+msgstr "Generic Payto:// URI"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:543
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:586
msgid "Account type"
-msgstr ""
+msgstr "Account type"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:553
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:596
msgid "Should be 52 characters."
-msgstr ""
+msgstr "Should be 52 characters."
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:555
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:598
msgid "Failed to parse: %1$s"
-msgstr ""
+msgstr "Failed to parse: %1$s"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:567
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:610
msgid "Address contains invalid characters."
-msgstr ""
+msgstr "Address contains invalid characters."
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:569
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:612
msgid "Can't mix uppercased and lowercased characters."
-msgstr ""
+msgstr "Can't mix uppercased and lowercased characters."
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:571
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:614
msgid "The addr checksum doesn't match."
-msgstr ""
+msgstr "The addr checksum doesn't match."
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:573
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:616
msgid "Missing separator or address type."
-msgstr ""
+msgstr "Missing separator or address type."
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:575
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:618
msgid "Address should have less than 90 characters."
-msgstr ""
+msgstr "Address should have less than 90 characters."
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:577
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:620
msgid "Address should have more than 6 characters."
-msgstr ""
+msgstr "Address should have more than 6 characters."
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:579
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:622
msgid "Decoding issue."
-msgstr ""
+msgstr "Decoding issue."
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:581
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:624
msgid "Invalid data"
-msgstr ""
+msgstr "Invalid data"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:591
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:634
msgid "Unsupported country."
-msgstr ""
+msgstr "Unsupported country."
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:593
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:636
msgid "IBANs have fewer than 34 characters."
-msgstr ""
+msgstr "IBANs have fewer than 34 characters."
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:595
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:638
msgid "IBANs have more than 4 characters."
-msgstr ""
+msgstr "IBANs have more than 4 characters."
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:597
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:640
msgid "IBAN length is invalid for this country."
msgstr "IBAN length is invalid for this country."
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:597
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:642
msgid "It should only contain numbers and letters."
-msgstr ""
+msgstr "It should only contain numbers and letters."
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:599
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:644
msgid "The checksum is wrong."
-msgstr ""
+msgstr "The checksum is wrong."
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:617
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:662
msgid "The string should start with payto://"
-msgstr ""
+msgstr "The string should start with payto://"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:619
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:664
msgid "After the target type it should follow a '/' with more information."
-msgstr ""
+msgstr "After the target type it should follow a '/' with more information."
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:621
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:666
msgid ""
"The target type is not supported, only x-taler-bank, taler-reserve or iban"
msgstr ""
+"The target type is not supported, only x-taler-bank, taler-reserve or iban"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:626
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:671
msgid "IBAN is missing"
-msgstr ""
+msgstr "IBAN is missing"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:628
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:673
msgid "Bitcoin address is missing"
-msgstr ""
+msgstr "Bitcoin address is missing"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:630
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:675
msgid "Bank host and account is missing"
-msgstr ""
+msgstr "Bank host and account is missing"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:632
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:634
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:677
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:679
msgid "Exchange host and account is missing"
-msgstr ""
+msgstr "Exchange host and account is missing"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:636
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:681
msgid "Ethereum address is missing"
-msgstr ""
+msgstr "Ethereum address is missing"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:638
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:683
msgid "Cyclos address is missing"
-msgstr ""
+msgstr "Cyclos address is missing"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:640
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:685
msgid "Void address is missing"
-msgstr ""
+msgstr "Void address is missing"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:648
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:693
msgid "Invalid IBAN: %1$s"
-msgstr ""
+msgstr "Invalid IBAN: %1$s"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:655
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:700
msgid "Invalid BTC: %1$s"
-msgstr ""
+msgstr "Invalid BTC: %1$s"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:660
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:683
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:696
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:705
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:728
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:741
msgid "Invalid reserve: %1$s"
-msgstr ""
+msgstr "Invalid reserve: %1$s"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:671
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:681
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:694
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:715
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:716
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:726
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:739
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:760
msgid "Invalid host"
-msgstr ""
+msgstr "Invalid host"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:707
-msgid "Invalid address"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:718
+msgid "Invalid account"
+msgstr "Invalid account"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:745
-msgid "Payto URI"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:752
+msgid "Invalid address"
+msgstr "Invalid address"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:746
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:791
msgid "As defined by RFC 8905"
-msgstr ""
+msgstr "As defined by RFC 8905"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:747
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:792
msgid "payto://"
-msgstr ""
+msgstr "payto://"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:762
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:807
msgid "International Bank Account Number"
-msgstr ""
+msgstr "International Bank Account Number"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:763
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:808
msgid "DE1231231231"
-msgstr ""
+msgstr "DE1231231231"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:775
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:820
msgid "Host"
-msgstr ""
+msgstr "Host"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:776
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:821
msgid "Exchange hostname"
-msgstr ""
+msgstr "Exchange hostname"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:777
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:822
msgid "exchange.taler.net"
-msgstr ""
+msgstr "exchange.taler.net"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:782
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:829
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:827
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:874
msgid "Remove last '/'"
-msgstr ""
+msgstr "Remove last '/'"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:784
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:801
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:332
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:376
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:829
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:846
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:426
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:472
msgid "Invalid value"
-msgstr ""
+msgstr "Invalid value"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:792
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:837
msgid "ID"
-msgstr ""
+msgstr "ID"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:793
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:838
msgid "Wallet reserve public key"
-msgstr ""
+msgstr "Wallet reserve public key"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:794
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:839
msgid "abcdef1235"
-msgstr ""
+msgstr "abcdef1235"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:799
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:844
msgid "Should be 52 characters"
-msgstr ""
-
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:814
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:268
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:338
-msgid "Account"
-msgstr ""
+msgstr "Should be 52 characters"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:815
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:860
msgid "Bank account identification"
-msgstr ""
+msgstr "Bank account identification"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:816
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:861
msgid "DE123123123"
-msgstr ""
+msgstr "DE123123123"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:822
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:867
msgid "Hostname"
-msgstr ""
+msgstr "Hostname"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:823
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:868
msgid "Without the scheme, may include subpath: bank.com, bank.com/path/"
-msgstr ""
+msgstr "Without the scheme, may include subpath: bank.com, bank.com/path/"
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:824
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:869
msgid "bank.demo.taler.net"
+msgstr "bank.demo.taler.net"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:876
+msgid "Invalid hostname"
+msgstr "Invalid hostname"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:68
+msgid "Failed to load account information."
+msgstr "Failed to load account information."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:77
+msgid "Failed to load the account information."
+msgstr "Failed to load the account information."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:115
+msgid "Collection event not found"
+msgstr "Collection event not found"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:117
+msgid "There is no collection event with ID %1$s for this account."
+msgstr "There is no collection event with ID %1$s for this account."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:129
+msgid "Attributes unavailable"
+msgstr "Attributes unavailable"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:131
+msgid "The collection event does not contain readable attributes."
+msgstr "The collection event does not contain readable attributes."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:148
+msgid "Form identifier missing"
+msgstr "Form identifier missing"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:150
+msgid "The collected information does not identify the form used to create it."
+msgstr ""
+"The collected information does not identify the form used to create it."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:165
+msgid "Form not available"
+msgstr "Form not available"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:167
+msgid "Form %1$s is not configured in this AML Web UI."
+msgstr "Form %1$s is not configured in this AML Web UI."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:255
+#, fuzzy
+#| msgid "Collected information"
+msgid "Collected AML/KYC information"
+msgstr "Collected information"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:262
+#, fuzzy
+#| msgid "Forms"
+msgid "Form"
+msgstr "Forms"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:267
+#, fuzzy
+#| msgid "Collected information"
+msgid "Collected"
+msgstr "Collected information"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:270
+msgid "Source"
+msgstr ""
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:274
+#, fuzzy
+#| msgid "Custom properties"
+msgid "Customer process"
+msgstr "Custom properties"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:277
+#, fuzzy
+#| msgid "Events"
+msgid "Event ID"
+msgstr "Events"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:284
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:292
+msgid "Different form version"
+msgstr "Different form version"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:285
+msgid ""
+"The collected information does not identify the form version used. The "
+"latest configured version is shown and field labels may differ from those "
+"used at collection time."
msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:831
-msgid "Invalid hostname"
-msgstr ""
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:293
+#, fuzzy
+#| msgid "Form %1$s is not configured in this AML Web UI."
+msgid ""
+"Form version %1$s is not configured in this AML Web UI. Version %2$s is "
+"shown and field labels may differ."
+msgstr "Form %1$s is not configured in this AML Web UI."
#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:71
-msgid "Failed to load the account information."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:301
+#, fuzzy
+#| msgid "Collected information"
+msgid "Collected information events"
+msgstr "Collected information"
#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:198
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:204
-msgid "Different form version"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:305
+#, fuzzy
+#| msgid "Next event"
+msgid "Older event"
+msgstr "Next event"
#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:199
-msgid "The collected information don't have the form version used."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:316
+#, fuzzy
+#| msgid "Next event"
+msgid "Newer event"
+msgstr "Next event"
#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:205
-msgid ""
-"The collected information used the form version \"%1$s \" but is not "
-"available."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:329
+#, fuzzy
+#| msgid "Submitted attributes"
+msgid "Submitted values"
+msgstr "Submitted attributes"
#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:217
-msgid "Case details"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:369
+#, fuzzy
+#| msgid "Officer name"
+msgid "Officer view"
+msgstr "Officer name"
#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:231
-msgid "Next event"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:371
+#, fuzzy
+#| msgid "Customer label"
+msgid "Customer view"
+msgstr "Customer label"
#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:245
-msgid "Previous event"
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:372
+msgid "JSON view"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:66
-msgid "Direction"
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:403
+#, fuzzy
+#| msgid "System information"
+msgid "Submitted information view"
+msgstr "System information"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:109
+msgid "Incoming"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:69
-msgid "Credit"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:113
+msgid "Outgoing"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:73
-msgid "Debit"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:117
+msgid "KYC authorization"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:77
-msgid "KYC Auth"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:127
+msgid "Wallet credits (P2P)"
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:85
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:140
+#, fuzzy
+#| msgid "Transfers history"
+msgid "Transfer category"
+msgstr "Transfers history"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:147
msgid "Minimum amount"
-msgstr ""
+msgstr "Minimum amount"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:86
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:148
msgid "All amounts below the given threshold will be filtered."
+msgstr "All amounts below the given threshold will be filtered."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:182
+#, fuzzy
+#| msgid "Exchange connection"
+msgid "Exchange transfer activity"
+msgstr "Exchange connection"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:188
+#, fuzzy
+#| msgid "Transfers history"
+msgid "Wallet credit activity"
+msgstr "Transfers history"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:190
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:198
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:241
+#, fuzzy
+#| msgid "Transfers history"
+msgid "Transfer activity"
+msgstr "Transfers history"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:196
+#, fuzzy
+#| msgid "Transfers history for account"
+msgid "Transfer activity for account"
+msgstr "Transfers history for account"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:204
+msgid ""
+"Inspect successful P2P credits received by this wallet. Requests that were "
+"not paid are not shown."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:114
-msgid "Failed to load transfer list."
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:209
+msgid ""
+"Inspect effective bank transfers observed by the exchange. Credit transfers "
+"are incoming, debit transfers are outgoing, and bounced or drain transfers "
+"are not included."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:123
-msgid "Failed to load the transfer list."
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:215
+msgid ""
+"Inspect effective transfers observed by the exchange. Incoming, outgoing, "
+"and KYC authorization entries are bank transfers. Wallet credits are "
+"successful P2P transfers into wallets."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:160
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:233
+#, fuzzy
+#| msgid "Transfers history"
+msgid "Transfer filters"
+msgstr "Transfers history"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:254
+msgid "Failed to load transfer list."
+msgstr "Failed to load transfer list."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:263
+msgid "Failed to load the transfer list."
+msgstr "Failed to load the transfer list."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:299
msgid "Select transaction type"
-msgstr ""
+msgstr "Select transaction type"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:161
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:300
msgid "Please select a transaction type to show transactions."
-msgstr ""
-
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:176
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:234
-msgid "Transfers history for account"
-msgstr ""
+msgstr "Please select a transaction type to show transactions."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:188
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:246
-msgid "Transfers history"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:314
+#, fuzzy
+#| msgid "No transfers yet."
+msgid "No wallet credits yet."
+msgstr "No transfers yet."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:195
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:315
msgid "No transfers yet."
+msgstr "No transfers yet."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:319
+#, fuzzy
+#| msgid "There are no transfers for this account."
+msgid "There are no P2P credits for this wallet."
+msgstr "There are no transfers for this account."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:323
+#, fuzzy
+#| msgid ""
+#| "There are no transfers reported to the exchange with the current "
+#| "threshold."
+msgid ""
+"There are no wallet credits reported to the exchange with the current "
+"threshold."
msgstr ""
+"There are no transfers reported to the exchange with the current threshold."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:197
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:328
msgid "There are no transfers for this account."
-msgstr ""
+msgstr "There are no transfers for this account."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:201
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:332
msgid ""
"There are no transfers reported to the exchange with the current threshold."
msgstr ""
+"There are no transfers reported to the exchange with the current threshold."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:260
-msgid "Date"
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:343
+msgid "Unknown date"
+msgstr "Unknown date"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:355
+msgid "Time"
+msgstr "Time"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:264
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:310
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:359
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:406
msgid "Amount"
-msgstr ""
+msgstr "Amount"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:314
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:393
+msgid "Unknown time"
+msgstr "Unknown time"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:410
+#, fuzzy
+#| msgid "Credit"
+msgid "credited"
+msgstr "Credit"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:412
msgid "sent"
-msgstr ""
+msgstr "sent"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:315
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:413
msgid "received"
-msgstr ""
+msgstr "received"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:348
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:443
msgid "to"
-msgstr ""
+msgstr "to"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:349
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:444
msgid "from"
-msgstr ""
+msgstr "from"
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:165
+msgid "This exchange is not compatible with the AML WebUI."
+msgstr "This exchange is not compatible with the AML WebUI."
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:92
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:101
-msgid "Welcome to the exchange configuration"
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:167
+msgid ""
+"Officer identity and permissions require exchange protocol v40 or newer."
msgstr ""
+"Officer identity and permissions require exchange protocol v40 or newer."
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:372
-msgid "Transfers"
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:191
+msgid "Verifying that this public key is enrolled by the exchange."
+msgstr "Verifying that this public key is enrolled by the exchange."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:278
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:331
+msgid "Read-only officer access"
+msgstr "Read-only officer access"
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:279
+msgid ""
+"You can review AML information, but this officer key cannot submit decisions."
msgstr ""
+"You can review AML information, but this officer key cannot submit decisions."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:332
+msgid "This officer key cannot create or submit AML decisions."
+msgstr "This officer key cannot create or submit AML decisions."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:340
+msgid "Return to account"
+msgstr "Return to account"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:379
-msgid "Profile"
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:466
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:475
+msgid "Failed to load the active AML decision."
+msgstr "Failed to load the active AML decision."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:484
+msgid "The account was not found."
+msgstr "The account was not found."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:488
+msgid "The account state changed. Reload it and try again."
+msgstr "The account state changed. Reload it and try again."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:511
+msgid ""
+"The payto URI does not belong to this account. Return to the account search "
+"and start the decision again."
msgstr ""
+"The payto URI does not belong to this account. Return to the account search "
+"and start the decision again."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:571
+#, fuzzy
+#| msgid "AML navigation"
+msgid "AML configuration"
+msgstr "AML navigation"
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:577
+msgid "Session"
+msgstr "Session"
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:585
+msgid "AML navigation"
+msgstr "AML navigation"
#. screenid: 124
#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:49
msgid "Failed to load server measures."
-msgstr ""
+msgstr "Failed to load server measures."
#. screenid: 124
#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:61
msgid "Failed to load the measures"
-msgstr ""
+msgstr "Failed to load the measures"
+
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:102
+msgid "Measures"
+msgstr "Measures"
#. screenid: 124
#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:105
msgid "A list of all the predefined measures you can use."
-msgstr ""
+msgstr "A list of all the predefined measures you can use."
-#. screenid: 122
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:165
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:174
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:214
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:222
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:90
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:99
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:62
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:71
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:191
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:200
-msgid "Failed to load available measures."
-msgstr ""
+#~ msgid "AML officer justification"
+#~ msgstr "AML officer justification"
-#. screenid: 122
-#. screenid: 102
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:179
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:104
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:76
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:205
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:403
-msgid "The officer session is invalid."
-msgstr ""
+#~ msgid "Effective policy"
+#~ msgstr "Effective policy"
-#. screenid: 122
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:183
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:80
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:209
-msgid "The measures endpoint was not found."
-msgstr ""
+#~ msgid "Account assessment"
+#~ msgstr "Account assessment"
-#. screenid: 122
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:189
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:114
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:86
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:215
-msgid "The officer session is disabled."
-msgstr ""
+#~ msgid "Properties recorded by AML officers for this account."
+#~ msgstr "Properties recorded by AML officers for this account."
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:182
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:190
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:389
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:398
-msgid "Failed to load the active AML decision."
-msgstr ""
+#~ msgid "Account assessment could not be loaded"
+#~ msgstr "Account assessment could not be loaded"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:488
-msgid "The officer session signature is invalid."
-msgstr ""
+#~ msgid "No assessment properties have been recorded for this account."
+#~ msgstr "No assessment properties have been recorded for this account."
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:491
-msgid "The requested AML account or session was not found."
-msgstr ""
+#~ msgid "Filter open, high-risk, and investigated accounts."
+#~ msgstr "Filter open, high-risk, and investigated accounts."
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:495
-msgid "The officer session is disabled or the account state changed."
-msgstr ""
+#, fuzzy
+#~ msgid "Keep case under investigation"
+#~ msgstr "Not under investigation"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:192
-msgid "Invalid expiration"
-msgstr ""
+#~ msgid "Account views"
+#~ msgstr "Account views"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:193
-msgid "Attributes require an expiration date in the future."
-msgstr ""
+#~ msgid "Date"
+#~ msgstr "Date"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:288
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:273
-msgid "Too many SKIP measures"
-msgstr ""
+#~ msgid "Show transfers"
+#~ msgstr "Show transfers"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:289
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:274
-msgid "At most one immediate measure may use the SKIP check."
-msgstr ""
+#, fuzzy
+#~ msgid "View decision history"
+#~ msgstr "Decision history"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:491
-msgid "Require all measures"
-msgstr ""
+#~ msgid "Save PDF"
+#~ msgstr "Save PDF"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:492
-msgid ""
-"Run all selected measures together instead of accepting any one of them."
-msgstr ""
+#~ msgid "Manual review required"
+#~ msgstr "Manual review required"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:172
-msgid "Invalid custom properties"
-msgstr ""
+#~ msgid "At a glance"
+#~ msgstr "At a glance"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:173
-msgid ""
-"Custom property names and values must be non-empty and names must be unique "
-"and different from built-in properties."
-msgstr ""
+#~ msgid "Requirements present"
+#~ msgstr "Requirements present"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:265
-msgid "Unknown measure"
-msgstr ""
+#~ msgid "Current assessment and policy"
+#~ msgstr "Current assessment and policy"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:266
-msgid ""
-"A rule or immediate action references a measure that is not available. "
-"Review the rules and measures before submitting."
-msgstr ""
+#~ msgid "The current account properties and effective AML rules."
+#~ msgstr "The current account properties and effective AML rules."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:274
-msgid "Requires investigation"
-msgstr ""
+#, fuzzy
+#~ msgid "Property"
+#~ msgstr "Properties"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:106
-msgid "Collection event not found"
-msgstr ""
+#~ msgid "The officer session signature is invalid."
+#~ msgstr "The officer session signature is invalid."
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:107
-msgid "There is no collection event with ID %1$s for this account."
-msgstr ""
+#~ msgid "The requested AML account was not found."
+#~ msgstr "The requested AML account was not found."
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:116
-msgid "Attributes unavailable"
-msgstr ""
+#~ msgid "The officer session is disabled or the account state changed."
+#~ msgstr "The officer session is disabled or the account state changed."
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:117
-msgid "The collection event does not contain readable attributes."
-msgstr ""
+#, fuzzy
+#~ msgid "Account audit trail"
+#~ msgstr "Account filters"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:131
-msgid "Form identifier missing"
-msgstr ""
+#~ msgid "(all)"
+#~ msgstr "(all)"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:132
-msgid "The collected information does not identify the form used to create it."
-msgstr ""
+#~ msgid "Info"
+#~ msgstr "Info"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:144
-msgid "Form not available"
-msgstr ""
+#~ msgid "Will show information to the user."
+#~ msgstr "Will show information to the user."
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:145
-msgid "Form %1$s is not configured in this AML Web UI."
-msgstr ""
+#~ msgid ""
+#~ "The account isn't a wallet and there are wallet operation's limits which "
+#~ "may trigger actions that are not required: %1$s"
+#~ msgstr ""
+#~ "The account isn't a wallet and there are wallet operation's limits which "
+#~ "may trigger actions that are not required: %1$s"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:407
-msgid "The account was not found."
-msgstr ""
+#~ msgid ""
+#~ "The account is a wallet and there are wallet operation's limits which are "
+#~ "not limited: %1$s"
+#~ msgstr ""
+#~ "The account is a wallet and there are wallet operation's limits which are "
+#~ "not limited: %1$s"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:411
-msgid "The account state changed. Reload it and try again."
-msgstr ""
+#~ msgid "New rules"
+#~ msgstr "New rules"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:436
-msgid ""
-"The payto URI does not belong to this account. Return to the account search "
-"and start the decision again."
-msgstr ""
+#~ msgid "Set rules to default"
+#~ msgstr "Set rules to default"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:448
-msgid ""
-"This account has no active decision and its payto URI is unknown. Start the "
-"decision from the account search so the account type can be determined "
-"safely."
-msgstr ""
+#~ msgid "Behavior on rule expiration"
+#~ msgstr "Behavior on rule expiration"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:458
-msgid "Return to account"
-msgstr ""
+#~ msgid "Event selection has manual overrides."
+#~ msgstr "Event selection has manual overrides."
+
+#~ msgid ""
+#~ "Events based on properties and new attributes that should be triggered"
+#~ msgstr ""
+#~ "Events based on properties and new attributes that should be triggered"
+
+#~ msgid "Others"
+#~ msgstr "Others"
+
+#~ msgid "Custom list"
+#~ msgstr "Custom list"
+
+#~ msgid "Events without built-in support."
+#~ msgstr "Events without built-in support."
+
+#~ msgid "These measures will ask the customer for information."
+#~ msgstr "These measures will ask the customer for information."
+
+#~ msgid "change form"
+#~ msgstr "change form"
+
+#~ msgid ""
+#~ "Select a form to submit new information about the customer or continue to "
+#~ "the next step"
+#~ msgstr ""
+#~ "Select a form to submit new information about the customer or continue to "
+#~ "the next step"
+
+#~ msgid "Form:"
+#~ msgstr "Form:"
+
+#~ msgid "Keep investigation?"
+#~ msgstr "Keep investigation?"
+
+#~ msgid "Full name of the account holder"
+#~ msgstr "Full name of the account holder"
+
+#~ msgid "Update"
+#~ msgstr "Update"
+
+#~ msgid "Remove"
+#~ msgstr "Remove"
+
+#~ msgid "Show complete form"
+#~ msgstr "Show complete form"
+
+#~ msgid "Show as verification"
+#~ msgstr "Show as verification"
+
+#~ msgid "Only required when no check is specified"
+#~ msgstr "Only required when no check is specified"
+
+#~ msgid "Without a check the program will run automatically"
+#~ msgstr "Without a check the program will run automatically"
+
+#~ msgid "It should be a number"
+#~ msgstr "It should be a number"
+
+#~ msgid "It should be a safe integer"
+#~ msgstr "It should be a safe integer"
+
+#~ msgid "Server measures"
+#~ msgstr "Server measures"
+
+#~ msgid "New measures"
+#~ msgstr "New measures"
+
+#~ msgid ""
+#~ "Measures that are available/executed directly after the decision is "
+#~ "confirmed."
+#~ msgstr ""
+#~ "Measures that are available/executed directly after the decision is "
+#~ "confirmed."
+
+#~ msgid ""
+#~ "The session is disabled or a more recent decision was already submitted."
+#~ msgstr ""
+#~ "The session is disabled or a more recent decision was already submitted."
+
+#~ msgid ""
+#~ "This decision declares that the MROS report has concluded. Please make "
+#~ "sure that this is the case"
+#~ msgstr ""
+#~ "This decision declares that the MROS report has concluded. Please make "
+#~ "sure that this is the case"
+
+#~ msgid "I want to check first!"
+#~ msgstr "I want to check first!"
+
+#~ msgid ""
+#~ "Deadline should specify when this rules ends and what is the next "
+#~ "measures to apply after expiration."
+#~ msgstr ""
+#~ "Deadline should specify when this rules ends and what is the next "
+#~ "measures to apply after expiration."
+
+#~ msgid "Can't make a decision without rules."
+#~ msgstr "Can't make a decision without rules."
+
+#~ msgid "Missing active measure"
+#~ msgstr "Missing active measure"
+
+#~ msgid "You should specify in the measure section."
+#~ msgstr "You should specify in the measure section."
+
+#~ msgid "You should specify in the properties section."
+#~ msgstr "You should specify in the properties section."
+
+#~ msgid "You should specify in the events section."
+#~ msgstr "You should specify in the events section."
+
+#~ msgid "Missing justification"
+#~ msgstr "Missing justification"
+
+#~ msgid ""
+#~ "You should check form errors or submit a decision without attributes."
+#~ msgstr ""
+#~ "You should check form errors or submit a decision without attributes."
+
+#~ msgid "Clear"
+#~ msgstr "Clear"
+
+#~ msgid "Attributes"
+#~ msgstr "Attributes"
+
+#~ msgid "Add more information about the customer"
+#~ msgstr "Add more information about the customer"
+
+#~ msgid "Rules"
+#~ msgstr "Rules"
+
+#~ msgid "Set the limit of the operations"
+#~ msgstr "Set the limit of the operations"
+
+#~ msgid "Trigger notifications."
+#~ msgstr "Trigger notifications."
+
+#~ msgid "Ask the customer to take action."
+#~ msgstr "Ask the customer to take action."
+
+#~ msgid "Flag the current account state."
+#~ msgstr "Flag the current account state."
+
+#~ msgid "loading..."
+#~ msgstr "loading..."
+
+#~ msgid "Decision for wallet:"
+#~ msgstr "Decision for wallet:"
+
+#~ msgid "Check account details"
+#~ msgstr "Check account details"
+
+#~ msgid "Account most recent decisions"
+#~ msgstr "Account most recent decisions"
+
+#~ msgid "When"
+#~ msgstr "When"
+
+#~ msgid "LATEST"
+#~ msgstr "LATEST"
+
+#~ msgid "ACTIVE"
+#~ msgstr "ACTIVE"
+
+#~ msgid "Requires investigation"
+#~ msgstr "Requires investigation"
+
+#~ msgid "The collected information don't have the form version used."
+#~ msgstr "The collected information don't have the form version used."
+
+#~ msgid ""
+#~ "The collected information used the form version \"%1$s \" but is not "
+#~ "available."
+#~ msgstr ""
+#~ "The collected information used the form version \"%1$s \" but is not "
+#~ "available."
+
+#~ msgid "Case details"
+#~ msgstr "Case details"
+
+#~ msgid "Previous event"
+#~ msgstr "Previous event"
+
+#~ msgid "Direction"
+#~ msgstr "Direction"
+
+#~ msgid "Debit"
+#~ msgstr "Debit"
+
+#~ msgid "KYC Auth"
+#~ msgstr "KYC Auth"
+
+#~ msgid "Previous AML decisions that are no longer active."
+#~ msgstr "Previous AML decisions that are no longer active."
+
+#~ msgid "The account has no KYC information."
+#~ msgstr "The account has no KYC information."
+
+#~ msgid "Download KYC report"
+#~ msgstr "Download KYC report"
+
+#~ msgid "KYC report ready"
+#~ msgstr "KYC report ready"
+
+#~ msgid "Use testing dialect"
+#~ msgstr "Use testing dialect"
+
+#~ msgid "Since"
+#~ msgstr "Since"
+
+#~ msgid "Already completed."
+#~ msgstr "Already completed."
+
+#~ msgid "The server doesn't support PDF download. Contact the administrator."
+#~ msgstr "The server doesn't support PDF download. Contact the administrator."
+
+#~ msgid "Failed to load decision history."
+#~ msgstr "Failed to load decision history."
+
+#~ msgid "Failed to load current legitimizations."
+#~ msgstr "Failed to load current legitimizations."
+
+#~ msgid "Case history for selected account"
+#~ msgstr "Case history for selected account"
+
+#~ msgid "ID:"
+#~ msgstr "ID:"
+
+#~ msgid "Payto:"
+#~ msgstr "Payto:"
+
+#~ msgid "Export as PDF"
+#~ msgstr "Export as PDF"
+
+#~ msgid "PDF"
+#~ msgstr "PDF"
+
+#~ msgid "Click here to save the file in your computer."
+#~ msgstr "Click here to save the file in your computer."
+
+#~ msgid "Every attribute collection event (via form upload or KYC provider)."
+#~ msgstr "Every attribute collection event (via form upload or KYC provider)."
+
+#~ msgid ""
+#~ "There is no decision for this account yet. The account is limited by the "
+#~ "default rules."
+#~ msgstr ""
+#~ "There is no decision for this account yet. The account is limited by the "
+#~ "default rules."
+
+#~ msgid "No AML history found"
+#~ msgstr "No AML history found"
+
+#~ msgid "Current active measures"
+#~ msgstr "Current active measures"
+
+#~ msgid "Case queue"
+#~ msgstr "Case queue"
+
+#~ msgid "Access"
+#~ msgstr "Access"
+
+#~ msgid "Confirm forgetting this session"
+#~ msgstr "Confirm forgetting this session"
+
+#~ msgid ""
+#~ "This account has no active decision and its payto URI is unknown. Start "
+#~ "the decision from the account search so the account type can be "
+#~ "determined safely."
+#~ msgstr ""
+#~ "This account has no active decision and its payto URI is unknown. Start "
+#~ "the decision from the account search so the account type can be "
+#~ "determined safely."
diff --git a/packages/taler-exchange-aml-webui/src/i18n/es.po b/packages/taler-exchange-aml-webui/src/i18n/es.po
@@ -1,3 +1,4 @@
+#
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: taler@gnu.org\n"
@@ -5,2378 +6,5227 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
#. screenid: 118
-#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:103
-msgid "Use testing dialect"
-msgstr "Usar dialecto de prueba"
-
-#. screenid: 118
-#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:105
+#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:114
msgid "Allow Insecure password"
msgstr "Permitir contraseña insegura"
#. screenid: 118
-#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:107
+#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:116
msgid "Keep session after reload"
msgstr "Mantener la sesión después de recargar"
#. screenid: 118
-#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:109
+#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:118
msgid "Don't compress request"
msgstr "No comprimir la solicitud"
#. screenid: 101
-#: packages/taler-exchange-aml-webui/src/ExchangeAmlFrame.tsx:75
-msgid "Preferences"
-msgstr "Preferencias"
+#: packages/taler-exchange-aml-webui/src/ExchangeAmlFrame.tsx:85
+msgid "Lock session"
+msgstr "Bloquear sesión"
#. screenid: 101
-#: packages/taler-exchange-aml-webui/src/ExchangeAmlFrame.tsx:120
-#, fuzzy
-msgid "Show debug information"
-msgstr "Mostrar información de depuración"
+#: packages/taler-exchange-aml-webui/src/ExchangeAmlFrame.tsx:90
+msgid "Lock"
+msgstr "Bloquear"
#. screenid: 125
#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:46
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:45
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:94
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:47
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:47
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:115
msgid "Password"
msgstr "Contraseña"
#. screenid: 125
#. screenid: 122
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:50
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:71
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:555
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:996
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:749
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:780
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:797
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:827
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:841
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:51
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:72
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:629
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1108
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:794
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:825
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:842
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:872
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:886
msgid "Required"
msgstr "Requerido"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:54
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:55
msgid "should have at least 12 characters"
msgstr "debe tener al menos 12 caracteres"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:56
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:57
msgid "should have lowercase and uppercase characters"
msgstr "debe tener letras minúsculas y mayúsculas"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:58
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:59
msgid "should have numbers"
msgstr "debe tener números"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:60
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:61
msgid "should have at least one character which is not a number or letter"
msgstr "debe tener al menos un carácter que no sea un número o una letra"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:67
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:68
msgid "Repeat password"
msgstr "Repetir contraseña"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:73
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:74
msgid "doesn't match"
msgstr "no coincide"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:105
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:112
#, fuzzy
msgid "Create session"
msgstr "Crear cuenta"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:117
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:139
msgid "Create"
msgstr "Crear"
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:66
-msgid "Failed to unlock the session."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountBadges.tsx:28
+msgid "Wallet account"
+msgstr "Cuenta de cartera"
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:69
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:243
-msgid "Authorization denied for this session. Contact the administrator."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountBadges.tsx:28
+msgid "Bank account"
+msgstr "Cuenta bancaria"
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:80
-#, fuzzy
-msgid "Session locked"
-msgstr "Cuenta bloqueada"
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/components/AccountBadges.tsx:40
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:93
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:245
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:296
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:100
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:130
+msgid "Under investigation"
+msgstr "Bajo investigación"
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:83
-#, fuzzy
-msgid ""
-"Your session is normally locked anytime you reload. To unlock type your "
-"password again."
-msgstr ""
-"Tu cuenta se bloquea normalmente cada vez que recargas. Para desbloquearla, "
-"escribe tu contraseña nuevamente."
+#: packages/taler-exchange-aml-webui/src/components/AccountBadges.tsx:89
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:101
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:254
+msgid "High risk"
+msgstr "Alto riesgo"
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:108
-msgid "Unlock"
-msgstr "Desbloquear"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:51
+msgid "Payment target type"
+msgstr ""
-#. screenid: 119
-#. screenid: 112
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:116
-#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:81
-#, fuzzy
-msgid "Forget session"
-msgstr "Olvidar cuenta"
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:81
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:199
+msgid "Account holder"
+msgstr "Titular de la cuenta"
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:55
-msgid "There are no rules for operations"
-msgstr "No hay reglas para las operaciones"
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:107
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:110
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:571
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:806
+msgid "IBAN"
+msgstr "IBAN"
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:58
-#, fuzzy
-msgid "This means that no operation has any limit."
-msgstr "Esto significa que todas las operaciones no tienen límite."
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:109
+msgid "BIC"
+msgstr ""
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:69
-msgid "Add custom rule"
-msgstr "Añadir regla personalizada"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:114
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:119
+msgid "Bank"
+msgstr ""
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:94
-msgid "Operation"
-msgstr "Operación"
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:115
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:120
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:154
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:160
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:295
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:859
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:364
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:435
+msgid "Account"
+msgstr "Cuenta"
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:100
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:625
-msgid "Threshold"
-msgstr "Umbral"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:116
+msgid "Taler bank"
+msgstr "Banco Taler"
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:106
-msgid "Escalation"
-msgstr "Escalamiento"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:121
+msgid "Cyclos"
+msgstr ""
-#. screenid: 121
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:120
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:243
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:800
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:844
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:902
-msgid "%1$s"
-msgstr "%1$s"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:124
+msgid "Bitcoin address"
+msgstr ""
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:195
-msgctxt "threshold"
-msgid "%1$s every %2$s"
-msgstr "%1$s cada %2$s"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:129
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:144
+msgid "Reserve public key"
+msgstr ""
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:213
-msgid "(all)"
-msgstr "(todos)"
-
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:59
-#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:69
-msgid "Since"
-msgstr "Desde"
-
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:70
-msgid "Expired"
-msgstr "Vencido"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:133
+msgid "Bitcoin"
+msgstr ""
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:72
-msgid "Expires"
-msgstr "Vence"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:136
+msgid "Ethereum address"
+msgstr ""
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:82
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:724
-msgid "Successor measure"
-msgstr "Medida sucesora"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:139
+msgid "Ethereum"
+msgstr ""
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:140
-msgid "AML officer justification"
-msgstr "Justificación del oficial de AML"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:142
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:70
+msgid "Exchange"
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/components/ShowDefaultRules.tsx:11
-msgid "Default rules"
-msgstr "Reglas predeterminadas"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:149
+msgid "Taler reserve"
+msgstr "Reserva de Taler"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:42
-msgid "Forms"
-msgstr "Formularios"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:150
+msgid "Taler reserve (HTTP)"
+msgstr ""
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:45
-#, fuzzy
-msgid "Measures used to gather information about the customer."
-msgstr "Medidas usadas para recopilar información sobre el cliente."
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:157
+msgid "Test account"
+msgstr "Cuenta de prueba"
-#. screenid: 123
-#. screenid: 108
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:69
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:162
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:248
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:153
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:552
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:992
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:192
-msgid "Name"
-msgstr "Nombre"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:180
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:225
+msgid "Account details unavailable"
+msgstr ""
-#. screenid: 123
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:76
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:169
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:584
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:837
-msgid "Check"
-msgstr "Verificar"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:54
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:96
+msgid "Not opened"
+msgstr "No abierto"
-#. screenid: 123
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:82
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:255
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:564
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:791
-msgid "Program"
-msgstr "Programa"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:59
+msgid "Opened:"
+msgstr "Abierto:"
-#. screenid: 123
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:88
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:175
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:267
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:607
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:805
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:893
-msgid "Context"
-msgstr "Contexto"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:68
+msgid "Closed:"
+msgstr "Cerrado:"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:102
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:189
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:281
-msgid "Modify"
-msgstr "Modificar"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:94
+msgid "Closed"
+msgstr "Cerrado"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:135
-msgid "Info"
-msgstr "Información"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:95
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:263
+msgid "Open"
+msgstr "Abierto"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:138
-msgid "Will show information to the user."
-msgstr "Mostrará información al usuario."
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:125
+msgid "No note"
+msgstr "Sin nota"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:221
-msgid "Instant measures"
-msgstr "Medidas instantáneas"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:136
+msgid "Show full note"
+msgstr "Mostrar la nota completa"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:224
-msgid "Triggered immediately without customer interaction."
-msgstr "Se activan de inmediato sin interacción del cliente."
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:146
+msgid "System information"
+msgstr "Información del sistema"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:261
-msgid "Input requirement"
-msgstr "Requisito de entrada"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:149
+msgid "Transactions remain below the threshold that opens an AML file."
+msgstr ""
+"Las transacciones siguen por debajo del umbral que abre un expediente de AML."
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:78
-msgid "Already completed."
-msgstr "Ya completado."
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:122
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:202
+msgid "Account case"
+msgstr "Caso de cuenta"
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:80
-msgid "Waiting to be completed."
-msgstr "Esperando a ser completado."
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:149
+msgid "Failed to download AML file."
+msgstr "No se pudo descargar el archivo AML."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:183
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:365
-msgid "Current active rules"
-msgstr "Reglas activas actuales"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:152
+msgid "No AML file is available for this account."
+msgstr "No hay ningún archivo AML disponible para esta cuenta."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:188
-msgid "There are no rules for this account yet."
-msgstr "Aún no hay reglas para esta cuenta."
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:154
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:72
+msgid "Authorization denied for this session. Contact the administrator."
+msgstr ""
+"Autorización denegada para esta sesión. Póngase en contacto con el "
+"administrador."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:238
-msgid "New rule form"
-msgstr "Formulario de nueva regla"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:156
+msgid "The account or session was not found."
+msgstr "No se encontró la cuenta o la sesión."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:250
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:230
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:412
-msgid "Add"
-msgstr "Añadir"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:158
+msgid "The session is disabled. Contact the administrator."
+msgstr ""
+"La sesión está deshabilitada. Póngase en contacto con el administrador."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:258
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:221
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:403
-msgid "Cancel"
-msgstr "Cancelar"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:160
+msgid "The exchange does not support PDF reports."
+msgstr "El Exchange no admite informes PDF."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:356
-msgid "Basic plan"
-msgstr "Plan básico"
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:175
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:354
+msgid "Read-only officers cannot create AML decisions."
+msgstr ""
+"Los responsables con acceso de solo lectura no pueden crear decisiones de "
+"AML."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:367
-msgid "Premium"
-msgstr "Premium"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:177
+msgid "A payto URI is required to create a new decision."
+msgstr "Se requiere un URI payto para crear una nueva decisión."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:378
-msgid "E-commerce"
-msgstr "Comercio electrónico"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:194
+msgid "Back to accounts"
+msgstr "Volver a las cuentas"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:389
-msgid "Point of Sale"
-msgstr "Punto de venta"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:224
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:505
+msgid "File no. %1$s"
+msgstr "Expediente n.º %1$s"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:408
-msgid "Check rules"
-msgstr "Verificar reglas"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:253
+msgid "New decision"
+msgstr "Nueva decisión"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:428
-msgid ""
-"The account is a wallet and there are bank account operation's limits which "
-"may trigger actions that are not required: %1$s"
-msgstr ""
-"La cuenta es una cartera y existen límites de operaciones de cuenta bancaria "
-"que pueden activar acciones que no son necesarias: %1$s"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:265
+msgid "Download AML file (PDF)"
+msgstr "Descargar archivo AML (PDF)"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:437
-msgid ""
-"The account isn't a wallet and there are wallet operation's limits which may "
-"trigger actions that are not required: %1$s"
-msgstr ""
-"La cuenta no es una cartera y existen límites de operaciones de cartera que "
-"pueden activar acciones que no son necesarias: %1$s"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:278
+msgid "AML file download started."
+msgstr "Se ha iniciado la descarga del archivo AML."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:446
-msgid ""
-"The account is a wallet and there are wallet operation's limits which are "
-"not limited: %1$s"
-msgstr ""
-"La cuenta es una cartera y existen límites de operaciones de cartera que no "
-"están limitados: %1$s"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:284
+#, fuzzy
+#| msgid "Account open"
+msgid "Account notes"
+msgstr "Cuenta abierta"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:454
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:293
#, fuzzy
-msgid ""
-"The AML account is a bank account, but not all account-related operations "
-"are limited ( %1$s)."
+#| msgid "Account assessment could not be loaded"
+msgid "Current account status and notes could not be loaded."
+msgstr "No se pudo cargar la evaluación de la cuenta"
+
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:302
+msgid "Try again"
msgstr ""
-"La cuenta de AML es una cuenta bancaria, pero no todas las operaciones "
-"relacionadas con la cuenta están limitadas (%1$s)."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:482
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:269
-msgid "New rules"
-msgstr "Nuevas reglas"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:316
+msgid "Account identifiers"
+msgstr "Identificadores de la cuenta"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:503
-msgid "Reset rules to current state"
-msgstr "Restablecer las reglas al estado actual"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:325
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:509
+msgid "Technical identifiers"
+msgstr "Identificadores técnicos"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:511
-msgid "Set rules to default"
-msgstr "Establecer reglas predeterminadas"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:329
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:513
+msgid "Full payto URI"
+msgstr "URI payto completo"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:519
-msgid "Freeze account"
-msgstr "Congelar cuenta"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:331
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:144
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:155
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:173
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:190
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:390
+msgid "Unavailable"
+msgstr "No disponible"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:535
-msgid "Behavior on rule expiration"
-msgstr "Comportamiento al vencer la regla"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:332
+msgid "Copy payto URI"
+msgstr "Copiar URI payto"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:546
-msgid "Reset measure"
-msgstr "Restablecer medida"
+#. screenid: 113
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:335
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:517
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:188
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:157
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:289
+msgid "Normalized payto hash"
+msgstr "Hash payto normalizado"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:558
-msgid "Reset expiration"
-msgstr "Restablecer vencimiento"
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:337
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:194
+msgid "Copy normalized payto hash"
+msgstr "Copiar hash payto normalizado"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:583
-msgctxt "operation type"
-msgid "Withdraw"
-msgstr "Retirada"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:341
+#, fuzzy
+#| msgid "number"
+msgid "File number"
+msgstr "número"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:585
-msgctxt "operation type"
-msgid "Deposit"
-msgstr "Depósito"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:343
+#, fuzzy
+#| msgid "Not a number"
+msgid "Copy file number"
+msgstr "No es un número"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:587
-msgctxt "operation type"
-msgid "Merge"
-msgstr "Fusión"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:351
+msgid "Account case views"
+msgstr "Vistas del caso de la cuenta"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:589
-msgctxt "operation type"
-msgid "Aggregate"
-msgstr "Agregación"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:355
+msgid "Overview"
+msgstr "Resumen"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:591
-msgctxt "operation type"
-msgid "Balance"
-msgstr "Saldo"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:360
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:565
+msgid "Transfers"
+msgstr "Transferencias"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:593
-msgctxt "operation type"
-msgid "Refund"
-msgstr "Reembolso"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:365
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:67
+msgid "Decision history"
+msgstr "Historial de decisiones"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:595
-msgctxt "operation type"
+#: packages/taler-exchange-aml-webui/src/components/ConfirmationModal.tsx:73
msgid "Close"
msgstr "Cerrar"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:597
-msgctxt "operation type"
-msgid "Transaction"
-msgstr "Transacción"
-
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:612
-msgid "Operation type"
-msgstr "Tipo de operación"
-
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:633
-msgid "Timeframe"
-msgstr "Marco temporal"
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/ConfirmationModal.tsx:91
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:207
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:534
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:280
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:469
+msgid "Cancel"
+msgstr "Cancelar"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:639
-msgid "Exposed"
-msgstr "Expuesto"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:36
+msgid "AML officer enrollment request"
+msgstr "Solicitud de registro de oficial de AML"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:640
-msgid "Is this limit communicated to the customer?"
-msgstr "¿Se comunica este límite al cliente?"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:37
+msgid ""
+"Please enroll this AML officer public key:\n"
+"\n"
+"%1$s"
+msgstr ""
+"Registre esta clave pública del oficial de AML:\n"
+"\n"
+"%1$s"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:652
-msgid "Escalation measure"
-msgstr "Medida de escalamiento"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:59
+msgid "Officer key awaiting enrollment"
+msgstr "Clave del oficial de AML pendiente de registro"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:653
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:62
msgid ""
-"Measures that the customer will need to satisfy to apply for a new threshold."
-msgstr "Medidas que el cliente deberá cumplir para solicitar un nuevo umbral."
-
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:658
-msgid "All measures"
-msgstr "Todas las medidas"
+"This browser has created an AML officer key, but the exchange has not "
+"granted it access. Ask the exchange operator or administrator to enroll the "
+"public key below."
+msgstr ""
+"Este navegador ha creado una clave de oficial de AML, pero el exchange no le "
+"ha concedido acceso. Pida al operador o administrador del exchange que "
+"registre la clave pública que aparece a continuación."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:659
-msgid "Hint the customer that all measures should be completed"
-msgstr "Indicar al cliente que debe completar todas las medidas"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:70
+msgid "AML officer public key"
+msgstr "Clave pública del oficial de AML"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:672
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:157
-msgid "Expiration"
-msgstr "Vencimiento"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:76
+msgid "Copy AML officer public key"
+msgstr "Copiar la clave pública del agente AML"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:673
-msgid "Predefined shortcuts"
-msgstr "Atajos predefinidos"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:82
+msgid "After the operator confirms enrollment, retry the access check."
+msgstr ""
+"Una vez que el operador confirme el registro, vuelva a comprobar el acceso."
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:92
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:69
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:212
+msgid "Retry access check"
+msgstr "Volver a comprobar el acceso"
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:101
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:188
+msgid "Checking officer access"
+msgstr "Comprobando el acceso del oficial de AML"
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:104
+msgid "Last checked at %1$s"
+msgstr "Última comprobación a las %1$s"
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:114
+msgid "Request enrollment"
+msgstr "Solicitar registro"
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:121
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:128
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:77
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:85
+msgid "Discard this key"
+msgstr "Descartar esta clave"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:677
-msgid "In a week"
-msgstr "En una semana"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:127
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:84
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:250
+msgid "Confirmation required"
+msgstr "Confirmación requerida"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:685
-msgid "In a month"
-msgstr "En un mes"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:135
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:92
+msgid ""
+"Discarding this key removes the officer session from this browser. You will "
+"need to create a new key to use the AML WebUI again."
+msgstr ""
+"Al descartar esta clave, se elimina de este navegador la sesión del oficial "
+"de AML. Deberá crear una clave nueva para volver a utilizar la interfaz web "
+"de AML."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:693
-msgid "In a year"
-msgstr "En un año"
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:41
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:205
+msgid "Failed to check AML officer access."
+msgstr "No se pudo comprobar el acceso del responsable de AML."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:701
-msgid "Never"
-msgstr "Nunca"
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:45
+msgid ""
+"This officer key cannot authenticate with the exchange. Retry the check or "
+"discard the key and create a new session."
+msgstr ""
+"Esta clave de responsable no puede autenticarse en el exchange. Vuelva a "
+"intentar la comprobación o descarte la clave y cree una sesión nueva."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:712
-msgid "Expiration date"
-msgstr "Fecha de vencimiento"
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:50
+msgid "The exchange rejected the officer access check."
+msgstr "El exchange rechazó la comprobación de acceso del responsable."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:713
-msgid "Until when are the new rules active."
-msgstr "Hasta cuándo estarán activas las nuevas reglas."
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:57
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:211
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:522
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:101
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:612
+msgid "Technical details"
+msgstr "Detalles técnicos"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:725
-msgid "Measure taken automatically upon expiration of the current decision."
-msgstr "Medida tomada automáticamente al vencer la decisión actual."
-
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:107
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:62
-msgid "Failed to load account information."
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:69
+msgid "Failed to unlock the session."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:125
-msgid "Failed to load decision history."
-msgstr ""
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:95
+#, fuzzy
+msgid "Session locked"
+msgstr "Cuenta bloqueada"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:143
-msgid "Failed to load current legitimizations."
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:98
+#, fuzzy
+msgid ""
+"Your session is normally locked anytime you reload. To unlock type your "
+"password again."
msgstr ""
+"Tu cuenta se bloquea normalmente cada vez que recargas. Para desbloquearla, "
+"escribe tu contraseña nuevamente."
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:188
-msgid "New decision"
-msgstr "Nueva decisión"
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:136
+msgid "Unlock"
+msgstr "Desbloquear"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:196
-msgid "Show transfers"
-msgstr "Mostrar transferencias"
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:144
+msgid "Forget session"
+msgstr "Olvidar sesión"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:236
-msgid "Failed to download report."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:162
+#, fuzzy
+#| msgid "No account properties"
+msgid "Review derived account properties"
+msgstr "Sin propiedades de cuenta"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:165
+msgid ""
+"Values may be derived from the selected AML/KYC form. Confirm them against "
+"the case record and change only values that require an officer override."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:241
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:187
#, fuzzy
-msgid "The account has no KYC info."
-msgstr "No se encontró la cuenta"
+#| msgid "Reset to default"
+msgid "Reset to derived values"
+msgstr "Restablecer a los valores predeterminados"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:245
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:183
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:195
-msgid "Session not found. Contact the administrator."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:192
+msgid "Invalid custom properties"
+msgstr "Propiedades personalizadas no válidas"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:247
-msgid "The session is disabled. Contact the administrator."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:193
+msgid ""
+"Custom property names and values must be non-empty and names must be unique "
+"and different from built-in properties."
msgstr ""
+"Los nombres y valores de las propiedades personalizadas no pueden estar "
+"vacíos; los nombres deben ser únicos y diferentes de las propiedades "
+"integradas."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:216
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:466
+msgid "Properties"
+msgstr "Propiedades"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:249
-msgid "The server doesn't support PDF download. Contact the administrator."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:217
+msgid "Built-in property names are preserved when the decision is submitted."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:260
-msgid "Case history for selected account"
-msgstr "Historial del caso para la cuenta seleccionada"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:223
+msgid "Custom properties"
+msgstr "Propiedades personalizadas"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:224
+msgid "Add more properties that are not listed above."
+msgstr "Añade más propiedades que no estén listadas arriba."
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:229
+msgid "New properties"
+msgstr "Nuevas propiedades"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:265
-msgid "ID:"
-msgstr "ID:"
+#. screenid: 123
+#. screenid: 108
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:234
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:73
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:171
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:261
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:204
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:626
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1104
+msgid "Name"
+msgstr "Nombre"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:271
-msgid "Payto:"
-msgstr "Payto:"
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:240
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:720
+msgid "Value"
+msgstr "Valor"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:282
-msgid "Export as PDF"
-msgstr "Exportar como PDF"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:262
+msgid "Current note on the GwG file"
+msgstr "Nota actual del expediente GwG"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:298
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:279
-msgid "Export completed"
-msgstr "Exportación completada"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:267
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:63
+msgid "Customer name or internal alias."
+msgstr "Nombre del cliente o alias interno."
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:301
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:282
-msgid "Click here to save the file in your computer."
-msgstr "Haz clic aquí para guardar el archivo en tu computadora."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:272
+msgid "Is the account active for deposit and payments?"
+msgstr "¿Está la cuenta activa para depósitos y pagos?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:310
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:411
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:208
-msgid "Under investigation"
-msgstr "Bajo investigación"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:277
+msgid "Is the account idle?"
+msgstr "¿Está la cuenta inactiva?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:311
-msgid ""
-"This account requires a manual review and is waiting for a decision to be "
-"made."
-msgstr ""
-"Esta cuenta requiere una revisión manual y está a la espera de una decisión."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:278
+msgid "No operation for a period of time"
+msgstr "Sin operaciones durante un período de tiempo"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:322
-msgid "Collected information"
-msgstr "Información recopilada"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:283
+msgid "Does account belong to a domestic PEP?"
+msgstr "¿Pertenece la cuenta a un PEP nacional?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:325
-msgid "Every attribute collection event (via form upload or KYC provider)."
-msgstr ""
-"Cada evento de recopilación de atributos (mediante carga de formulario o "
-"proveedor KYC)."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:288
+msgid "Does account belong to a foreign PEP?"
+msgstr "¿Pertenece la cuenta a un PEP extranjero?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:333
-msgid "No collected attributes for this account."
-msgstr "No hay atributos recopilados para esta cuenta."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:293
+msgid "Does account belong to an international-organization PEP?"
+msgstr "¿Pertenece la cuenta a un PEP de organización internacional?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:347
-msgid "Current account properties"
-msgstr "Propiedades actuales de la cuenta"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:298
+msgid "Does account belong to a high risk customer?"
+msgstr "¿Pertenece la cuenta a un cliente de alto riesgo?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:354
-msgid "No active decision found"
-msgstr "No se encontró ninguna decisión activa"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:303
+msgid "Does account belong to a person from a high risk country?"
+msgstr "¿Pertenece la cuenta a una persona de un país de alto riesgo?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:355
-msgid ""
-"There is no decision for this account yet. The account is limited by the "
-"default rules."
-msgstr ""
-"Aún no hay ninguna decisión para esta cuenta. La cuenta está limitada por "
-"las reglas predeterminadas."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:308
+msgid "The MROS reporting state for the account."
+msgstr "El estado de informe MROS de la cuenta."
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:384
-msgid "Previous AML decisions"
-msgstr "Decisiones de AML anteriores"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:313
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:307
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:175
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:199
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:497
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:630
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:653
+msgid "None"
+msgstr "Ninguno"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:403
-msgid "No AML history found"
-msgstr "No se encontró historial de AML"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:317
+msgid "Pending investigation"
+msgstr "Investigación pendiente"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:409
-msgid "Current active measures"
-msgstr "Medidas activas actuales"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:321
+msgid "Investigated without suspicion"
+msgstr "Investigado sin sospecha"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:537
-msgid "Now"
-msgstr "Ahora"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:325
+msgid "Reported simple suspicion"
+msgstr "Sospecha simple informada"
-#. screenid: 112
-#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:43
-#, fuzzy
-msgid "Session public key"
-msgstr "Clave pública"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:329
+msgid "Reported substantiated suspicion"
+msgstr "Sospecha fundamentada informada"
-#. screenid: 112
-#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:59
-#, fuzzy
-msgid "Request session activation"
-msgstr "Solicitar activación de cuenta"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:336
+msgid "Informal reason why the AML investigation was triggered"
+msgstr "Motivo informal por el que se activó la investigación de AML"
-#. screenid: 112
-#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:70
-msgid "Lock session"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:341
+msgid "Identifies the sanction list entry that the account matched against"
msgstr ""
+"Identifica la entrada de la lista de sanciones con la que coincidió la cuenta"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:73
-msgid "Failed to load accounts"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:343
+msgid "Best match, does not mean it was a good match."
+msgstr "Mejor coincidencia, no significa que fue una buena coincidencia."
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:347
+msgid "Score for how good the sanction list match was"
+msgstr "Puntaje de qué tan buena fue la coincidencia con la lista de sanciones"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:349
+msgid "Integer score from 0 (no match) to 1,000,000,000 (best match)."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:83
-#, fuzzy
-msgid "Failed to load the accounts"
-msgstr "Historial del caso para la cuenta seleccionada"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:353
+msgid "Score for how much supporting data we had for the sanction list match"
+msgstr ""
+"Puntaje de cuántos datos de respaldo teníamos para la coincidencia con la "
+"lista de sanciones"
-#. screenid: 111
-#. screenid: 110
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:88
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:168
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:76
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:128
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:66
-#, fuzzy
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:355
msgid ""
-"This session signature is invalid, contact administrator or create a new one."
+"Integer score from 0 (no supporting data) to 1,000,000,000 (highest "
+"confidence)."
msgstr ""
-"La firma de esta cuenta no es válida; contacta al administrador o crea una "
-"nueva."
-#. screenid: 111
-#. screenid: 110
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:95
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:175
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:83
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:135
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:73
-#, fuzzy
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:359
msgid ""
-"The designated AML session is not known, contact administrator or create a "
-"new one."
+"Suppress flagging this account when it creates a hit on a sanctions list, "
+"this is a false-positive"
msgstr ""
-"La cuenta de AML designada no es conocida; contacta al administrador o crea "
-"una nueva."
+"Suprimir la marcación de esta cuenta cuando genera una coincidencia en una "
+"lista de sanciones; es un falso positivo"
-#. screenid: 111
-#. screenid: 110
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:102
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:182
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:90
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:142
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:80
+#: packages/taler-exchange-aml-webui/src/components/DecisionProperties.tsx:46
#, fuzzy
-msgid ""
-"The designated AML session is not enabled, contact administrator or create a "
-"new one."
-msgstr ""
-"La cuenta de AML designada no está habilitada; contacta al administrador o "
-"crea una nueva."
+#| msgid "No account properties"
+msgid "No account properties were recorded."
+msgstr "Sin propiedades de cuenta"
+
+#: packages/taler-exchange-aml-webui/src/components/DecisionProperties.tsx:91
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:317
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:509
+msgid "Yes"
+msgstr "Sí"
+
+#: packages/taler-exchange-aml-webui/src/components/DecisionProperties.tsx:91
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:317
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:509
+msgid "No"
+msgstr "No"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:122
-msgid "High risk accounts. Only with custom rules."
-msgstr "Cuentas de alto riesgo. Solo con reglas personalizadas."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:59
+msgid "There are no rules for operations"
+msgstr "No hay reglas para las operaciones"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:123
-msgid "Account with custom rules."
-msgstr "Cuenta con reglas personalizadas."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:62
+msgid "This means that no operation has any limit."
+msgstr "Esto significa que ninguna operación tiene límites."
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:125
-msgid "High risk accounts"
-msgstr "Cuentas de alto riesgo"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:90
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:312
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:500
+msgid "Operation"
+msgstr "Operación"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:126
-msgid "All known accounts."
-msgstr "Todas las cuentas conocidas."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:96
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:695
+msgid "Threshold"
+msgstr "Umbral"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:130
-msgid "High risk accounts under investigation. Only with custom rules."
-msgstr ""
-"Cuentas de alto riesgo bajo investigación. Solo con reglas personalizadas."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:102
+msgid "Escalation"
+msgstr "Escalamiento"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:131
-msgid "Accounts under investigation. Only with custom rules."
-msgstr "Cuentas bajo investigación. Solo con reglas personalizadas."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:108
+msgid "Visibility"
+msgstr "Visibilidad"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:133
-msgid "High risk accounts under investigation."
-msgstr "Cuentas de alto riesgo bajo investigación."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:114
+msgid "Priority"
+msgstr "Prioridad"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:134
-msgid "Accounts under investigation."
-msgstr "Cuentas bajo investigación."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:121
+msgid "Actions"
+msgstr "Acciones"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:137
-msgid "High risk accounts without investigation. Only with custom rules."
-msgstr ""
-"Cuentas de alto riesgo sin investigación. Solo con reglas personalizadas."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:142
+msgctxt "threshold"
+msgid "%1$s every %2$s"
+msgstr "%1$s cada %2$s"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:138
-msgid "Accounts without investigation. Only with custom rules."
-msgstr "Cuentas sin investigación. Solo con reglas personalizadas."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:161
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:725
+msgid "Block operation"
+msgstr "Bloquear operación"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:140
-msgid "High risk accounts without investigation."
-msgstr "Cuentas de alto riesgo sin investigación."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:163
+msgid "All required:"
+msgstr "Todas obligatorias:"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:141
-msgid "Accounts without investigation."
-msgstr "Cuentas sin investigación."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:165
+msgid "Any one:"
+msgstr "Cualquiera:"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:174
-msgid "Failed to download"
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:182
+msgid "Customer-visible"
+msgstr "Visible para el cliente"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:177
-#, fuzzy
-msgid "There are no accounts in the resultset."
-msgstr "Aún no hay reglas para esta cuenta."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:184
+msgid "Internal"
+msgstr "Interno"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:179
-msgid "The format requested is not acceptable from the service provider."
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:197
+msgid "Move %1$s rule up"
+msgstr "Subir la regla %1$s"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:181
-msgid "Authorization denied for this session."
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:206
+msgid "Move %1$s rule down"
+msgstr "Bajar la regla %1$s"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:185
-msgid "The session is disabled. Contact the administrator"
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:217
+msgid "Edit %1$s rule"
+msgstr "Editar la regla %1$s"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:240
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:368
-msgid "Accounts"
-msgstr "Cuentas"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:240
+msgid "Remove %1$s rule"
+msgstr "Eliminar la regla %1$s"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:247
-msgid "Export as file"
-msgstr "Exportar como archivo"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:282
+msgctxt "operation type"
+msgid "Withdraw"
+msgstr "Retirada"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:318
-msgid "No results"
-msgstr "Sin resultados"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:284
+msgctxt "operation type"
+msgid "Deposit"
+msgstr "Depósito"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:329
-msgid "#"
-msgstr "#"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:286
+msgctxt "operation type"
+msgid "Merge"
+msgstr "Fusión"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:335
-msgid "Account Identification"
-msgstr "Identificación de la cuenta"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:288
+msgctxt "operation type"
+msgid "Aggregate"
+msgstr "Agregación"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:341
-msgid "Open time"
-msgstr "Hora de apertura"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:290
+msgctxt "operation type"
+msgid "Balance"
+msgstr "Saldo"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:347
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:243
-msgid "Status"
-msgstr "Estado"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:292
+msgctxt "operation type"
+msgid "Refund"
+msgstr "Reembolso"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:365
-msgid "From %1$s %2$s To %3$s"
-msgstr "Desde %1$s %2$s Hasta %3$s"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:294
+msgctxt "operation type"
+msgid "Close"
+msgstr "Cerrar"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:371
-msgid "Since %1$s"
-msgstr "Desde %1$s"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:296
+msgctxt "operation type"
+msgid "Transaction"
+msgstr "Transacción"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:374
-msgid "Not opened"
-msgstr "No abierta"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:83
+#, fuzzy
+#| msgid "Decision date"
+msgid "Decision provenance"
+msgstr "Fecha de la decisión"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:419
-msgid "High risk"
-msgstr "Alto riesgo"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:85
+#, fuzzy
+#| msgid "Decision date"
+msgid "Decision made by"
+msgstr "Fecha de la decisión"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:427
-msgid "With custom rules"
-msgstr "Con reglas personalizadas"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:88
+#, fuzzy
+#| msgid "AML officer public key"
+msgid "AML officer (name unavailable)"
+msgstr "Clave pública del oficial de AML"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:642
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:673
-msgid "Invalid account"
-msgstr "Cuenta inválida"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:89
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:369
+msgid "Automated outcome"
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:657
-msgid "Search by ID"
-msgstr "Buscar por ID"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:91
+msgid "Resulting case disposition"
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:687
-msgid "Under investigation: "
-msgstr "Bajo investigación: "
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:94
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:246
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:105
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:132
+msgid "Not under investigation"
+msgstr "No está bajo investigación"
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:99
+#, fuzzy
+#| msgid "Justification"
+msgid "Justification:"
+msgstr "Justificación"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:696
-msgid "High risk:"
-msgstr "Alto riesgo:"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:101
+msgid "No justification was recorded."
+msgstr "No se registró ninguna justificación."
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:705
-msgid "Custom rules:"
-msgstr "Reglas personalizadas:"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:112
+#, fuzzy
+#| msgid "System information"
+msgid "View submitted customer information"
+msgstr "Información del sistema"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:47
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:366
-msgid "Dashboard"
-msgstr "Panel"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:120
+#, fuzzy
+#| msgid "Instant measures"
+msgid "Immediate measures requested"
+msgstr "Medidas instantáneas"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:88
-msgid "Failed to load TOPS statistics."
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:123
+msgid "This decision did not request an immediate measure."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:99
-msgid "Statistics"
-msgstr "Estadísticas"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:131
+#, fuzzy
+#| msgid "All listed measures must be completed."
+msgid "All listed measures were requested (AND)."
+msgstr "Deben completarse todas las medidas indicadas."
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:187
-msgid "Accounts open"
-msgstr "Cuentas abiertas"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:132
+#, fuzzy
+#| msgid "Any one listed measure may be completed."
+msgid "Any listed measure may satisfy the request (OR)."
+msgstr "Puede completarse cualquiera de las medidas indicadas."
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:190
-msgid "New files last year"
-msgstr "Expedientes nuevos el año pasado"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:151
+msgid "Operation rules"
+msgstr "Reglas de operación"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:193
-msgid "Closed files last year"
-msgstr "Expedientes cerrados el año pasado"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:156
+msgid "No operation-specific rules were stored."
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:196
-msgid "MROS substantiated"
-msgstr "MROS fundamentados"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:163
+#, fuzzy
+#| msgid "Select transaction type"
+msgid "Policy transition"
+msgstr "Selecciona el tipo de transacción"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:199
-msgid "MROS simple"
-msgstr "MROS simples"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:165
+msgid "Policy expires"
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:202
-msgid "High risk files"
-msgstr "Expedientes de alto riesgo"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:173
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:796
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:362
+msgid "Successor measure"
+msgstr "Medida sucesora"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:205
-msgid "PEP files"
-msgstr "Expedientes PEP"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:174
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:479
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:163
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:365
+msgid "Exchange defaults"
+msgstr "Valores predeterminados del Exchange"
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:179
+#, fuzzy
+#| msgid "Custom measures"
+msgid "Custom measure definitions"
+msgstr "Medidas personalizadas"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:267
-msgid "Number of accounts that are opened"
-msgstr "Número de cuentas abiertas"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:182
+#, fuzzy
+#| msgid "No active measure has been selected."
+msgid "No custom measures were stored."
+msgstr "No se ha seleccionado ninguna medida activa."
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:270
-msgid "Number of new GwG files in the last year"
-msgstr "Número de expedientes GwG nuevos en el último año"
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:202
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:278
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:128
+msgid "Account properties"
+msgstr "Propiedades de la cuenta"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:273
-msgid "Number of GwG files closed in the last year"
-msgstr "Número de expedientes GwG cerrados en el último año"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:214
+#, fuzzy
+#| msgid "Decision date"
+msgid "Decision row"
+msgstr "Fecha de la decisión"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:276
-msgid "Number of MROS reports based on Art 9 Abs. 1 GwG (per year)"
-msgstr "Número de informes MROS basados en el Art. 9 Abs. 1 GwG (por año)"
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:217
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:174
+msgid "Officer public key"
+msgstr "Clave pública del responsable"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:279
-msgid "Number of MROS reports based on Art 305ter Abs. 2 StGB (per year)"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:219
+msgid "Not applicable"
msgstr ""
-"Número de informes MROS basados en el Art. 305ter Abs. 2 StGB (por año)"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:282
-msgid "Number of GwG files of high-risk customers"
-msgstr "Número de expedientes GwG de clientes de alto riesgo"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:277
+#, fuzzy
+#| msgid "System information"
+msgid "Stored custom definition"
+msgstr "Información del sistema"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:285
-msgid "Number of GwG files managed with “increased risk” due to PEP status"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:284
+msgid ""
+"Current measure metadata is still loading; the stored machine name is shown."
msgstr ""
-"Número de expedientes GwG gestionados con «riesgo incrementado» debido al "
-"estado de PEP"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:288
-#, fuzzy
-msgid "Number of customers with open proceeding."
-msgstr "Número de cuentas abiertas"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:286
+msgid ""
+"The current measure configuration could not be loaded; the stored machine "
+"name is shown."
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:343
-msgid "previous"
-msgstr "anterior"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:287
+msgid ""
+"No stored or currently configured definition is available for this reference."
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:386
-msgid "Decreased by"
-msgstr "Disminuyó en"
+#. screenid: 123
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:291
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:80
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:178
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:659
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:938
+msgid "Check"
+msgstr "Verificar"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:390
-msgid "Increased by"
-msgstr "Aumentó en"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:295
+msgid "Built-in check that requires no customer interaction."
+msgstr ""
-#. screenid: 108
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:115
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:217
-msgid "Events"
-msgstr "Eventos"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:296
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:304
+#, fuzzy
+#| msgid "Attributes unavailable"
+msgid "Description unavailable"
+msgstr "Atributos no disponibles"
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:116
-msgid ""
-"The events will be triggered only after the decision has been confirmed."
-msgstr "Los eventos solo se activarán después de que se confirme la decisión."
+#. screenid: 123
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:299
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:86
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:268
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:639
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:891
+msgid "Program"
+msgstr "Programa"
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:121
-msgid "Calculated"
-msgstr "Calculado"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:316
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:508
+msgid "Voluntary"
+msgstr ""
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:122
-msgid "Events based on properties and new attributes that should be triggered"
-msgstr "Eventos basados en propiedades y nuevos atributos que deben activarse"
+#. screenid: 123
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:320
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:92
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:184
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:280
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:682
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:907
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:644
+msgid "Context"
+msgstr "Contexto"
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:134
-msgid "Others"
-msgstr "Otros"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:349
+msgid "Decision date"
+msgstr "Fecha de la decisión"
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:135
-msgid "Events that can be triggered manually"
-msgstr "Eventos que se pueden activar manualmente"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:357
+msgid "Expired"
+msgstr "Vencido"
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:147
-msgid "Custom list"
-msgstr "Lista personalizada"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:357
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:419
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:354
+msgid "Expires"
+msgstr "Vence"
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:148
-msgid "Events without built-in support."
-msgstr "Eventos sin soporte incorporado."
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:362
+#, fuzzy
+#| msgid "Decision date"
+msgid "Decision status"
+msgstr "Fecha de la decisión"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:132
-msgid "Complete the form"
-msgstr "Completar el formulario"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:363
+#, fuzzy
+#| msgid "Send decision"
+msgid "Current"
+msgstr "Enviar decisión"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:135
-msgid "These measures will ask the customer for information."
-msgstr "Estas medidas solicitarán información al cliente."
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:363
+msgid "Historical"
+msgstr ""
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:153
-msgid "change form"
-msgstr "cambiar formulario"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:365
+msgid "Made by"
+msgstr ""
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:158
-msgid "Expiration date of the information filled in this form."
-msgstr "Fecha de vencimiento de la información completada en este formulario."
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:368
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:272
+#, fuzzy
+#| msgid "AML officer public key"
+msgid "AML officer"
+msgstr "Clave pública del oficial de AML"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:217
-msgid "Include new information"
-msgstr "Incluir nueva información"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:44
+msgid "Forms"
+msgstr "Formularios"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:218
-msgid ""
-"Select a form to submit new information about the customer or continue to "
-"the next step"
-msgstr ""
-"Selecciona un formulario para enviar nueva información sobre el cliente o "
-"continúa al siguiente paso"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:47
+msgid "Measures used to gather information about the customer."
+msgstr "Medidas utilizadas para recopilar información sobre el cliente."
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:223
-msgid "Form:"
-msgstr "Formulario:"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:62
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:160
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:250
+msgid "Select"
+msgstr "Seleccionar"
-#. screenid: 106
-#. screenid: 113
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:81
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:227
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:237
-msgid "Justification"
-msgstr "Justificación"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:107
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:199
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:295
+msgid "Modify"
+msgstr "Modificar"
-#. screenid: 106
-#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:86
-msgid "Keep investigation?"
-msgstr "¿Mantener investigación?"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:141
+#, fuzzy
+#| msgid "System information"
+msgid "Information"
+msgstr "Información del sistema"
-#. screenid: 106
-#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:91
-msgid "Account holder"
-msgstr "Titular de la cuenta"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:144
+#, fuzzy
+#| msgid "KYC information filed by the customer or an AML officer."
+msgid "Shows information to the customer without running an AML program."
+msgstr "Información KYC presentada por el cliente o un agente AML."
-#. screenid: 106
-#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:93
-msgid "Full name of the account holder"
-msgstr "Nombre completo del titular de la cuenta"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:232
+msgid "Instant measures"
+msgstr "Medidas instantáneas"
-#. screenid: 122
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:90
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:394
-msgid "loading..."
-msgstr "cargando..."
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:235
+msgid "Triggered immediately without customer interaction."
+msgstr "Se activan de inmediato sin interacción del cliente."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:239
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:421
-msgid "Update"
-msgstr "Actualizar"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:274
+msgid "Input requirement"
+msgstr "Requisito de entrada"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:246
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:428
-msgid "Remove"
-msgstr "Quitar"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:56
+msgid "Started"
+msgstr "Iniciado"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:473
-msgid "Configure verification type: %1$s"
-msgstr "Configurar tipo de verificación: %1$s"
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:64
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:301
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:140
+msgid "Status"
+msgstr "Estado"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:484
-msgid "Show complete form"
-msgstr "Mostrar formulario completo"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:76
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:447
+msgid "Forbidden"
+msgstr "Prohibido"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:505
-msgid "Configure measure"
-msgstr "Configurar medida"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:78
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:443
+msgid "Completed"
+msgstr "Completado"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:515
-msgid "Show as verification"
-msgstr "Mostrar como verificación"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:79
+msgid "Waiting for customer"
+msgstr "Esperando al cliente"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:557
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:998
-msgid "There is already a measure with that name"
-msgstr "Ya existe una medida con ese nombre"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:92
+msgid "The operation is categorically forbidden by this requirement."
+msgstr "Esta exigencia prohíbe categóricamente la operación."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:571
-msgid "Only required when no check is specified"
-msgstr "Solo se requiere cuando no se especifica ninguna verificación"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:100
+msgid "All listed measures must be completed."
+msgstr "Deben completarse todas las medidas indicadas."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:575
-msgid "Missing check or program"
-msgstr "Falta la verificación o el programa"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:104
+msgid "Any one listed measure may be completed."
+msgstr "Puede completarse cualquiera de las medidas indicadas."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:585
-msgid "Without a check the program will run automatically"
-msgstr "Sin una verificación, el programa se ejecutará automáticamente"
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:24
+msgid "Expiration shortcuts"
+msgstr "Atajos de caducidad"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:614
-msgid "Field name"
-msgstr "Nombre del campo"
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:29
+msgid "In a week"
+msgstr "En una semana"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:619
-msgid "Type"
-msgstr "Tipo"
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:30
+msgid "In a month"
+msgstr "En un mes"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:623
-msgid "string"
-msgstr "cadena"
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:31
+msgid "In a year"
+msgstr "En un año"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:627
-msgid "number"
-msgstr "número"
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:50
+msgid "Never"
+msgstr "Nunca"
#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:631
-msgid "boolean"
-msgstr "booleano"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:115
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:98
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:63
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:72
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:209
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:218
+msgid "Failed to load available measures."
+msgstr "No se pudieron cargar las medidas disponibles."
#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:635
-msgid "json"
-msgstr "json"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:120
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:112
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:77
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:223
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:294
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:480
+msgid "The officer session is invalid."
+msgstr "La sesión del responsable de AML no es válida."
#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:644
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:197
-msgid "Value"
-msgstr "Valor"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:124
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:116
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:81
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:227
+msgid "The measures endpoint was not found."
+msgstr "No se encontró el punto de acceso de las medidas."
#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:663
-msgid "There are unsatisfied inputs: %1$s"
-msgstr "Hay entradas no satisfechas: %1$s"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:130
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:122
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:87
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:233
+msgid "The officer session is disabled."
+msgstr "La sesión del responsable de AML está deshabilitada."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:674
-msgid "There are missing inputs: %1$s"
-msgstr "Faltan entradas: %1$s"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:195
+msgid "Edit proposed rule"
+msgstr "Editar regla propuesta"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:694
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:711
-msgid "There are missing requirements: %1$s"
-msgstr "Faltan requisitos: %1$s"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:197
+msgid "Add proposed rule"
+msgstr "Añadir regla propuesta"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:751
-msgid "Can't be empty"
-msgstr "No puede estar vacío"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:216
+msgid "Save rule"
+msgstr "Guardar regla"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:755
-msgid "It should be a number"
-msgstr "Debe ser un número"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:218
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:372
+msgid "Add rule"
+msgstr "Añadir regla"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:757
-msgid "Not a number"
-msgstr "No es un número"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:356
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:348
+#, fuzzy
+#| msgid "Properties"
+msgid "Proposed rules"
+msgstr "Propiedades"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:759
-msgid "It should be finite"
-msgstr "Debe ser finito"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:359
+msgid ""
+"This complete rule set replaces the currently applied rules and exchange "
+"defaults until it expires. Higher rows take precedence."
+msgstr ""
+"Este conjunto completo de reglas sustituye las reglas aplicadas actualmente "
+"y las predeterminadas del intercambio hasta que caduque. Las filas "
+"superiores tienen prioridad."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:761
-msgid "It should be a safe integer"
-msgstr "Debe ser un entero seguro"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:390
+msgid "Rules for another account type"
+msgstr "Reglas para otro tipo de cuenta"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:766
-msgid "It should be either \"true\" or \"false\""
-msgstr "Debe ser \"true\" o \"false\""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:393
+msgid "These operations do not apply to this account type: %1$s."
+msgstr "Estas operaciones no se aplican a este tipo de cuenta: %1$s."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:771
-msgid "Couldn't parse as json string: %1$s"
-msgstr "No se pudo interpretar como cadena json: %1$s"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:400
+msgid "Operations without limits"
+msgstr "Operaciones sin límites"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:797
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:940
-msgid "Description"
-msgstr "Descripción"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:401
+msgid "No proposed rule limits these operations: %1$s."
+msgstr "Ninguna regla propuesta limita estas operaciones: %1$s."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:813
-msgid "Inputs"
-msgstr "Entradas"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:408
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:336
+msgid "Invalid proposed rules"
+msgstr "Reglas propuestas no válidas"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:849
-msgid "Output"
-msgstr "Salida"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:409
+msgid ""
+"Edit the highlighted rule set before continuing. Hard blocks cannot be "
+"combined with measures, and Balance and Refund rules must use an instant "
+"timeframe."
+msgstr ""
+"Edite el conjunto de reglas resaltado antes de continuar. Los bloqueos "
+"estrictos no pueden combinarse con medidas, y las reglas de saldo y "
+"reembolso deben usar un período instantáneo."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:859
-msgid "Requires"
-msgstr "Requiere"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:432
+msgid "Remove proposed rule?"
+msgstr "¿Eliminar la regla propuesta?"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:867
-msgid "Fallback"
-msgstr "Alternativa"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:434
+msgid ""
+"This is the final rule. Removing it leaves every applicable operation "
+"unlimited."
+msgstr ""
+"Esta es la última regla. Al eliminarla, todas las operaciones aplicables "
+"quedarán sin límite."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:993
-msgid "Name of the verification measure"
-msgstr "Nombre de la medida de verificación"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:439
+msgid "The rule will be removed from the proposed set."
+msgstr "La regla se eliminará del conjunto propuesto."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1005
-msgid "Read only"
-msgstr "Solo lectura"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:449
+msgid "Keep rule"
+msgstr "Conservar regla"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1006
-msgid "Prevent the customer from changing the address"
-msgstr "Impedir que el cliente cambie la dirección"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:459
+msgid "Remove rule"
+msgstr "Eliminar regla"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:256
-msgid "Configure verification measure: \"%1$s\""
-msgstr "Configurar medida de verificación: \"%1$s\""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:467
+msgid "Replace proposed rules"
+msgstr "Sustituir reglas propuestas"
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:294
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:115
-msgid "Add custom measure"
-msgstr "Añadir medida personalizada"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:470
+msgid "Preview a complete replacement before applying it."
+msgstr "Previsualice la sustitución completa antes de aplicarla."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:300
-msgid "Custom measures"
-msgstr "Medidas personalizadas"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:476
+msgid "Currently applied"
+msgstr "Aplicadas actualmente"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:329
-msgid "Server measures"
-msgstr "Medidas del servidor"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:486
+msgid "E-commerce"
+msgstr "Comercio electrónico"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:426
-msgid "New measures"
-msgstr "Nuevas medidas"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:489
+msgid "Point of Sale"
+msgstr "Punto de venta"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:427
-msgid ""
-"Measures that are available/executed directly after the decision is "
-"confirmed."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:496
+msgid "Basic plan"
+msgstr "Plan básico"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:501
+msgid "Premium"
+msgstr "Premium"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:510
+msgid "Freeze account"
+msgstr "Congelar cuenta"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:518
+msgid "Replacement preview"
+msgstr "Vista previa de la sustitución"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:521
+msgid "Confirm account freeze"
+msgstr "Confirmar bloqueo de la cuenta"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:522
+msgid "Every applicable operation will receive a zero hard limit."
+msgstr "Cada operación aplicable recibirá un límite estricto de cero."
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:548
+msgid "Apply replacement"
+msgstr "Aplicar sustitución"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:556
+#, fuzzy
+#| msgid "Reset expiration"
+msgid "Rule expiration"
+msgstr "Restablecer vencimiento"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:559
+msgid "Choose how long the proposed rules apply and what happens afterwards."
msgstr ""
-"Medidas disponibles/ejecutadas directamente después de confirmar la decisión."
+"Elija cuánto tiempo se aplican las reglas propuestas y qué sucede después."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:154
-msgid "Reset to default"
-msgstr "Restablecer a los valores predeterminados"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:578
+msgid "The proposed rules never expire, so no successor action will run."
+msgstr ""
+"Las reglas propuestas no caducan, por lo que no se ejecutará ninguna acción "
+"posterior."
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:175
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:234
-msgid "Properties"
-msgstr "Propiedades"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:598
+msgid "Restore currently applied expiration"
+msgstr "Restaurar la caducidad aplicada actualmente"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:181
-msgid "Custom properties"
-msgstr "Propiedades personalizadas"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:682
+msgid "Operation type"
+msgstr "Tipo de operación"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:182
-msgid "Add more properties that are not listed above."
-msgstr "Añade más propiedades que no estén listadas arriba."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:704
+msgid "Timeframe"
+msgstr "Marco temporal"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:187
-msgid "New properties"
-msgstr "Nuevas propiedades"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:705
+msgid ""
+"Use Y, M, D, h, m or s after each number. Forever accumulates over the "
+"account's full history."
+msgstr ""
+"Use Y, M, D, h, m o s después de cada número. «Para siempre» acumula todo el "
+"historial de la cuenta."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:218
-msgid "Current note on the GwG file"
-msgstr "Nota actual del expediente GwG"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:709
+msgid "Instant timeframe"
+msgstr "Período instantáneo"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:223
-msgid "Customer name or internal alias."
-msgstr "Nombre del cliente o alias interno."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:710
+msgid ""
+"Balance and Refund limits apply to one balance or transaction, so their "
+"timeframe is fixed to zero."
+msgstr ""
+"Los límites de saldo y reembolso se aplican a un saldo o una transacción, "
+"por lo que su período se fija en cero."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:228
-msgid "Is the account active for deposit and payments?"
-msgstr "¿Está la cuenta activa para depósitos y pagos?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:716
+msgid "Exposed"
+msgstr "Expuesto"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:233
-msgid "Is the account idle?"
-msgstr "¿Está la cuenta inactiva?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:717
+msgid "Is this limit communicated to the customer?"
+msgstr "¿Se comunica este límite al cliente?"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:234
-msgid "No operation for a period of time"
-msgstr "Sin operaciones durante un período de tiempo"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:723
+msgid "When the threshold is crossed"
+msgstr "Cuando se supera el umbral"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:239
-msgid "Does account belong to a domestic PEP?"
-msgstr "¿Pertenece la cuenta a un PEP nacional?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:726
+msgid "Require measures"
+msgstr "Exigir medidas"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:244
-msgid "Does account belong to a foreign PEP?"
-msgstr "¿Pertenece la cuenta a un PEP extranjero?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:740
+msgid "Required measures"
+msgstr "Medidas obligatorias"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:249
-msgid "Does account belong to an international-organization PEP?"
-msgstr "¿Pertenece la cuenta a un PEP de organización internacional?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:741
+msgid ""
+"Measures that the customer will need to satisfy to apply for a new threshold."
+msgstr "Medidas que el cliente deberá cumplir para solicitar un nuevo umbral."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:254
-msgid "Does account belong to a high risk customer?"
-msgstr "¿Pertenece la cuenta a un cliente de alto riesgo?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:747
+msgid "All measures"
+msgstr "Todas las medidas"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:259
-msgid "Does account belong to a person from a high risk country?"
-msgstr "¿Pertenece la cuenta a una persona de un país de alto riesgo?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:748
+msgid "Hint the customer that all measures should be completed"
+msgstr "Indicar al cliente que debe completar todas las medidas"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:264
-msgid "The MROS reporting state for the account."
-msgstr "El estado de informe MROS de la cuenta."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:767
+msgid "Expiration date"
+msgstr "Fecha de vencimiento"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:269
-msgid "None"
-msgstr "Ninguno"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:768
+msgid "Until when are the new rules active."
+msgstr "Hasta cuándo estarán activas las nuevas reglas."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:273
-msgid "Pending investigation"
-msgstr "Investigación pendiente"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:773
+msgid "Choose a future expiration date or Never."
+msgstr "Elija una fecha de caducidad futura o «Nunca»."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:277
-msgid "Investigated without suspicion"
-msgstr "Investigado sin sospecha"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:779
+msgid "After expiration"
+msgstr "Después de la caducidad"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:281
-msgid "Reported simple suspicion"
-msgstr "Sospecha simple informada"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:781
+msgid "Return to exchange defaults"
+msgstr "Volver a los valores predeterminados del intercambio"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:285
-msgid "Reported substantiated suspicion"
-msgstr "Sospecha fundamentada informada"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:782
+msgid "Trigger a successor measure"
+msgstr "Activar una medida sucesora"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:292
-msgid "Informal reason why the AML investigation was triggered"
-msgstr "Motivo informal por el que se activó la investigación de AML"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:797
+msgid "Measure taken automatically upon expiration of the current decision."
+msgstr "Medida tomada automáticamente al vencer la decisión actual."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:297
-msgid "Identifies the sanction list entry that the account matched against"
-msgstr ""
-"Identifica la entrada de la lista de sanciones con la que coincidió la cuenta"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:805
+msgid "This successor measure is no longer available."
+msgstr "Esta medida sucesora ya no está disponible."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:299
-msgid "Best match, does not mean it was a good match."
-msgstr "Mejor coincidencia, no significa que fue una buena coincidencia."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:133
+msgid "Case summary"
+msgstr "Resumen del caso"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:303
-msgid "Score for how good the sanction list match was"
-msgstr "Puntaje de qué tan buena fue la coincidencia con la lista de sanciones"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:134
+msgid "Current review state and the latest account activity."
+msgstr "Estado actual de la revisión y actividad más reciente de la cuenta."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:308
-msgid "Score for how much supporting data we had for the sanction list match"
-msgstr ""
-"Puntaje de cuántos datos de respaldo teníamos para la coincidencia con la "
-"lista de sanciones"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:138
+msgid "Review status"
+msgstr "Estado de revisión"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:313
-msgid ""
-"Suppress flagging this account when it creates a hit on a sanctions list, "
-"this is a false-positive"
-msgstr ""
-"Suprimir la marcación de esta cuenta cuando genera una coincidencia en una "
-"lista de sanciones; es un falso positivo"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:142
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:153
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:171
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:188
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:492
+msgid "Loading…"
+msgstr "Cargando…"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:190
-#, fuzzy
-msgid "Failed to make the decision."
-msgstr "Describir la decisión."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:146
+msgid "Manual review required — waiting for an AML decision."
+msgstr "Se requiere una revisión manual: a la espera de una decisión AML."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:193
-#, fuzzy
-msgid "Invalid credentials."
-msgstr "Se dieron las credenciales incorrectas."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:147
+msgid "No manual review"
+msgstr "Sin revisión manual"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:197
-#, fuzzy
-msgid ""
-"The session is disabled or a more recent decision was already submitted."
-msgstr "El oficial está deshabilitado o ya se envió una decisión más reciente."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:150
+msgid "Effective decision"
+msgstr "Decisión vigente"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:208
-msgid "Confirmation required"
-msgstr "Confirmación requerida"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:168
+msgid "Requirements"
+msgstr "Requisitos"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:209
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:185
+msgid "Latest collected information"
+msgstr "Última información recopilada"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:208
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:305
#, fuzzy
-msgid ""
-"This decision declares that the MROS report has concluded. Please make sure "
-"that this is the case"
+#| msgid "Send decision"
+msgid "Current decision"
+msgstr "Enviar decisión"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:209
+#, fuzzy
+#| msgid ""
+#| "The AML decision and operation rules currently applied to this account."
+msgid "The complete AML decision currently applied to this account."
msgstr ""
-"Esta decisión declara que el informe MROS ha concluido. Asegúrate de que "
-"este sea el caso"
+"La decisión AML y las reglas de operación que se aplican actualmente a esta "
+"cuenta."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:222
-msgid "I want to check first!"
-msgstr "¡Quiero verificar primero!"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:216
+msgid "Effective policy could not be loaded"
+msgstr "No se pudo cargar la política vigente"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:229
-msgid "Confirm decision"
-msgstr "Confirmar decisión"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:234
+msgid "Exchange defaults apply"
+msgstr "Se aplican los valores predeterminados del Exchange"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:245
-msgid "Missing deadline"
-msgstr "Falta el plazo"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:235
+msgid "No AML officer decision is active for this account."
+msgstr "No hay ninguna decisión activa de un agente AML para esta cuenta."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:248
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:238
+msgid "Account type unavailable"
+msgstr "Tipo de cuenta no disponible"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:239
msgid ""
-"Deadline should specify when this rules ends and what is the next measures "
-"to apply after expiration."
+"Open this case from the account directory or payto search to see the "
+"applicable default rules."
msgstr ""
-"El plazo debe especificar cuándo terminan estas reglas y cuáles son las "
-"siguientes medidas a aplicar tras el vencimiento."
+"Abra este caso desde el directorio de cuentas o la búsqueda payto para ver "
+"las reglas predeterminadas aplicables."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:257
-msgid "Missing rules"
-msgstr "Faltan reglas"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:248
+msgid "Default rules could not be loaded"
+msgstr "No se pudieron cargar las reglas predeterminadas"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:260
-msgid "Can't make a decision without rules."
-msgstr "No se puede tomar una decisión sin reglas."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:255
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:419
+#: packages/taler-exchange-aml-webui/src/components/ShowDefaultRules.tsx:11
+msgid "Default rules"
+msgstr "Reglas predeterminadas"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:284
-msgid "Missing active measure"
-msgstr "Falta la medida activa"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:266
+msgid "Collected information"
+msgstr "Información recopilada"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:287
-msgid "You should specify in the measure section."
-msgstr "Debes especificarlo en la sección de medidas."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:267
+msgid "KYC information filed by the customer or an AML officer."
+msgstr "Información KYC presentada por el cliente o un agente AML."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:294
-msgid "No customer action required."
-msgstr "No se requiere ninguna acción del cliente."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:273
+msgid "Collected information could not be loaded"
+msgstr "No se pudo cargar la información recopilada"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:297
-msgid "No active measure has been selected."
-msgstr "No se ha seleccionado ninguna medida activa."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:279
+msgid "No collected information"
+msgstr "Sin información recopilada"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:305
-msgid "Missing properties"
-msgstr "Faltan propiedades"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:280
+msgid "No KYC information has been collected for this account."
+msgstr "No se ha recopilado información KYC para esta cuenta."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:308
-msgid "You should specify in the properties section."
-msgstr "Debes especificarlo en la sección de propiedades."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:302
+msgid "Active requirements"
+msgstr "Requisitos activos"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:318
-msgid "Missing events"
-msgstr "Faltan eventos"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:303
+msgid "Measures the customer must complete under the current policy."
+msgstr "Medidas que el cliente debe completar según la política actual."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:321
-msgid "You should specify in the events section."
-msgstr "Debes especificarlo en la sección de eventos."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:309
+msgid "Active requirements could not be loaded"
+msgstr "No se pudieron cargar los requisitos activos"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:331
-msgid "Missing justification"
-msgstr "Falta la justificación"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:315
+msgid "No active requirements"
+msgstr "Sin requisitos activos"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:334
-msgid "You must complete the justification section."
-msgstr "Debes completar la sección de justificación."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:316
+msgid "The customer has no active legitimization measures to complete."
+msgstr "El cliente no tiene medidas de legitimación activas que completar."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:344
-msgid "Invalid attributes"
-msgstr "Atributos inválidos"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:413
+msgid "Officer decision"
+msgstr "Decisión del agente"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:347
-msgid "You should check form errors or submit a decision without attributes."
-msgstr ""
-"Debes revisar los errores del formulario o enviar una decisión sin atributos."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:416
+msgid "Does not expire"
+msgstr "No caduca"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:361
-msgid "Clear"
-msgstr "Limpiar"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:439
+msgid "Waiting"
+msgstr "En espera"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:368
-msgid "Send decision"
-msgstr "Enviar decisión"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:451
+msgid "More on later pages"
+msgstr "Hay más en las páginas siguientes"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:173
-msgid "Prev"
-msgstr "Anterior"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:510
+msgid "Try loading this section again."
+msgstr "Intente cargar esta sección de nuevo."
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:182
-msgid "Next"
-msgstr "Siguiente"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:518
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:97
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:633
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:205
+msgid "Retry"
+msgstr "Reintentar"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:207
-msgid "Attributes"
-msgstr "Atributos"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:566
+msgid "Unconfigured form"
+msgstr "Formulario no configurado"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:208
-msgid "Add more information about the customer"
-msgstr "Añadir más información sobre el cliente"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:567
+msgid "Form not identified"
+msgstr "Formulario no identificado"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:212
-msgid "Rules"
-msgstr "Reglas"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:576
+msgid "Filed by an AML officer"
+msgstr "Presentado por un agente AML"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:213
-msgid "Set the limit of the operations"
-msgstr "Establecer el límite de las operaciones"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:577
+msgid "Provided by the customer"
+msgstr "Proporcionado por el cliente"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:218
-msgid "Trigger notifications."
-msgstr "Activar notificaciones."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:581
+msgid "Attribute data is unavailable."
+msgstr "Los datos de atributos no están disponibles."
-#. screenid: 113
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:222
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:102
-msgid "Measures"
-msgstr "Medidas"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:595
+msgid "View details"
+msgstr "Ver detalles"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:223
-msgid "Ask the customer to take action."
-msgstr "Pedir al cliente que tome una acción."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:70
+msgid ""
+"Review superseded AML decisions for this account, from newest to oldest."
+msgstr ""
+"Revisar las decisiones AML sustituidas de esta cuenta, de la más reciente a "
+"la más antigua."
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:228
-msgid "Describe the decision."
-msgstr "Describir la decisión."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:79
+msgid "Loading decision history…"
+msgstr "Cargando el historial de decisiones…"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:235
-msgid "Flag the current account state."
-msgstr "Marcar el estado actual de la cuenta."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:84
+msgid "Decision history could not be loaded"
+msgstr "No se pudo cargar el historial de decisiones"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:239
-msgid "Summary"
-msgstr "Resumen"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:87
+msgid "Try loading the decision history again."
+msgstr "Intente cargar de nuevo el historial de decisiones."
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:240
-msgid "Review and submit."
-msgstr "Revisar y enviar."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:111
+msgid "No previous decisions"
+msgstr "Sin decisiones anteriores"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:404
-msgid "Decision for account:"
-msgstr "Decisión para la cuenta:"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:114
+msgid "No superseded AML decisions have been recorded for this account."
+msgstr "No se han registrado decisiones AML sustituidas para esta cuenta."
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:411
-msgid "Decision for wallet:"
-msgstr "Decisión para la cartera:"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:125
+msgid "Previous decisions"
+msgstr "Decisiones anteriores"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:417
-msgid "Decision for bank account:"
-msgstr "Decisión para la cuenta bancaria:"
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:153
+msgid "The export could not be prepared. Try again."
+msgstr "No se pudo preparar la exportación. Inténtelo de nuevo."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:88
-msgid "Search account"
-msgstr "Buscar cuenta"
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:164
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:173
+msgid "Failed to load accounts"
+msgstr "No se pudieron cargar las cuentas"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:154
-msgid "Failed to load account decisions."
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:193
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:552
+msgid "Accounts"
+msgstr "Cuentas"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:196
+msgid "Review accounts known to the exchange for AML and KYC handling."
msgstr ""
+"Revise las cuentas conocidas por el exchange para la gestión de AML y KYC."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:163
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:203
+msgid "Export filtered accounts"
+msgstr "Exportar las cuentas filtradas"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:211
+msgid "Download CSV"
+msgstr "Descargar CSV"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:218
+msgid "Download Excel"
+msgstr "Descargar Excel"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:226
+msgid "Preparing export…"
+msgstr "Preparando la exportación…"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:230
+msgid "Export failed"
+msgstr "La exportación ha fallado"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:236
+msgid "Account filters"
+msgstr "Filtros de cuentas"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:242
+msgid "Investigation"
+msgstr "Investigación"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:244
+msgid "All accounts"
+msgstr "Todas las cuentas"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:251
+msgid "Risk"
+msgstr "Riesgo"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:253
+msgid "All risk levels"
+msgstr "Todos los niveles de riesgo"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:255
+msgid "Not high risk"
+msgstr "Sin alto riesgo"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:260
+msgid "File status"
+msgstr "Estado del expediente"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:262
+msgid "All file statuses"
+msgstr "Todos los estados del expediente"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:264
+msgid "Not open"
+msgstr "No abierto"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:273
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:589
+msgid "Clear filters"
+msgstr "Borrar filtros"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:283
+msgid "Showing %1$s accounts · newest first"
+msgstr "Se muestran %1$s cuentas · las más recientes primero"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:290
+msgid "AML and KYC accounts"
+msgstr "Cuentas de AML y KYC"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:298
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:458
+msgid "Account lifecycle"
+msgstr "Ciclo de vida del expediente"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:304
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:467
+msgid "Latest note"
+msgstr "Nota más reciente"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:550
+msgid "Copied"
+msgstr "Copiado"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:550
+msgid "Copy"
+msgstr "Copiar"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:576
+msgid "No matching accounts"
+msgstr "No hay cuentas coincidentes"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:576
+msgid "No accounts yet"
+msgstr "Aún no hay cuentas"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:580
+msgid "No accounts match the selected filters."
+msgstr "Ninguna cuenta coincide con los filtros seleccionados."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:581
+msgid "The exchange has not recorded any AML or KYC accounts yet."
+msgstr "El exchange aún no ha registrado ninguna cuenta de AML o KYC."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:647
+msgid "This officer session is not authorized to list accounts."
+msgstr "Esta sesión de agente no está autorizada para listar cuentas."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:649
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:674
+msgid "The exchange does not recognize this officer session."
+msgstr "El exchange no reconoce esta sesión de agente."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:651
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:676
+msgid "This officer session is currently disabled."
+msgstr "Esta sesión de agente está deshabilitada actualmente."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:668
+msgid "There are no matching accounts to export."
+msgstr "No hay cuentas coincidentes para exportar."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:670
+msgid "The exchange does not support the selected export format."
+msgstr "El exchange no admite el formato de exportación seleccionado."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:672
+msgid "This officer session is not authorized to export accounts."
+msgstr "Esta sesión de agente no está autorizada para exportar cuentas."
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:52
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:546
+msgid "Dashboard"
+msgstr "Panel"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:55
+msgid ""
+"Review cases requiring attention, investigate accounts, and monitor AML "
+"reporting indicators."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:77
+msgid "Review case queue"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:80
+#, fuzzy
+#| msgid "Accounts under investigation."
+msgid "Review accounts currently under investigation."
+msgstr "Cuentas bajo investigación."
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:94
+#, fuzzy
+#| msgid "Show transfers"
+msgid "Inspect transfers"
+msgstr "Mostrar transferencias"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:97
+msgid "Find credit, debit, and KYC authorization activity."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:128
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:165
+msgid "Statistics"
+msgstr "Estadísticas"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:132
+msgid "No reporting profile for this dialect"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:137
+msgid ""
+"The testing dialect does not define dashboard statistics. Select TOPS in "
+"development settings to inspect the TOPS reporting profile."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:154
+msgid "Failed to load TOPS statistics."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:192
+#, fuzzy
+#| msgid "Attributes unavailable"
+msgid "Some statistics are unavailable."
+msgstr "Atributos no disponibles"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:195
+msgid "The available values are shown below. Missing values are not zero."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:275
+msgid "Accounts open"
+msgstr "Cuentas abiertas"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:278
+msgid "New files last year"
+msgstr "Expedientes nuevos el año pasado"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:281
+msgid "Closed files last year"
+msgstr "Expedientes cerrados el año pasado"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:284
+msgid "MROS substantiated"
+msgstr "MROS fundamentados"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:287
+msgid "MROS simple"
+msgstr "MROS simples"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:290
+msgid "High risk files"
+msgstr "Expedientes de alto riesgo"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:293
+msgid "PEP files"
+msgstr "Expedientes PEP"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:333
+msgid "Number of accounts that are opened"
+msgstr "Número de cuentas abiertas"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:336
+msgid "Number of new GwG files in the last year"
+msgstr "Número de expedientes GwG nuevos en el último año"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:339
+msgid "Number of GwG files closed in the last year"
+msgstr "Número de expedientes GwG cerrados en el último año"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:342
+msgid "Number of MROS reports based on Art 9 Abs. 1 GwG (per year)"
+msgstr "Número de informes MROS basados en el Art. 9 Abs. 1 GwG (por año)"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:345
+msgid "Number of MROS reports based on Art 305ter Abs. 2 StGB (per year)"
+msgstr ""
+"Número de informes MROS basados en el Art. 305ter Abs. 2 StGB (por año)"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:348
+msgid "Number of GwG files of high-risk customers"
+msgstr "Número de expedientes GwG de clientes de alto riesgo"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:351
+msgid "Number of GwG files managed with “increased risk” due to PEP status"
+msgstr ""
+"Número de expedientes GwG gestionados con «riesgo incrementado» debido al "
+"estado de PEP"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:354
+#, fuzzy
+msgid "Number of customers with open proceeding."
+msgstr "Número de cuentas abiertas"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:400
+msgid "previous"
+msgstr "anterior"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:443
+msgid "Decreased by"
+msgstr "Disminuyó en"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:447
+msgid "Increased by"
+msgstr "Aumentó en"
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:114
+msgid ""
+"The built-in event selection differs from the events derived from the "
+"proposed account state."
+msgstr ""
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:119
+msgid ""
+"Built-in events are derived from changes to the proposed account properties. "
+"They are stored for reporting and statistics; they do not notify the "
+"customer."
+msgstr ""
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:138
+#, fuzzy
+#| msgid "Reset to default"
+msgid "Reset to derived events"
+msgstr "Restablecer a los valores predeterminados"
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:169
+msgid "Calculated"
+msgstr "Calculado"
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:170
+msgid ""
+"Events derived from proposed property changes and submitted information."
+msgstr ""
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:184
+msgid "Other built-in events"
+msgstr ""
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:185
+#, fuzzy
+#| msgid "Events that can be triggered manually"
+msgid "Additional events that may be recorded manually."
+msgstr "Eventos que se pueden activar manualmente"
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:198
+#, fuzzy
+#| msgid "Next event"
+msgid "Custom events"
+msgstr "Próximo evento"
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:199
+msgid "Operator-defined event names that are not part of the selected dialect."
+msgstr ""
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:213
+#, fuzzy
+#| msgid "Describe the decision."
+msgid "Events recorded with this decision"
+msgstr "Describir la decisión."
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:214
+#, fuzzy
+#| msgid ""
+#| "The events will be triggered only after the decision has been confirmed."
+msgid "Events are added only after the decision is successfully submitted."
+msgstr "Los eventos solo se activarán después de que se confirme la decisión."
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:209
+#, fuzzy
+#| msgid "System information"
+msgid "Add customer information"
+msgstr "Información del sistema"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:212
+msgid ""
+"The completed form is attached to this AML decision as reviewed account "
+"information. It does not create a customer-facing measure."
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:223
+#, fuzzy
+#| msgid "Collected information"
+msgid "Selected form"
+msgstr "Información recopilada"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:233
+#, fuzzy
+#| msgid "Complete the form"
+msgid "Choose another form"
+msgstr "Completar el formulario"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:242
+msgid "Expiration"
+msgstr "Vencimiento"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:243
+msgid "Expiration date of the information filled in this form."
+msgstr "Fecha de vencimiento de la información completada en este formulario."
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:254
+#, fuzzy
+#| msgid "Context"
+msgid "Form context"
+msgstr "Contexto"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:261
+#, fuzzy
+#| msgid "Context"
+msgid "Advanced form context"
+msgstr "Contexto"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:264
+msgid ""
+"Only change this operator-defined JSON when the form documentation requires "
+"additional context."
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:270
+#, fuzzy
+#| msgid "Context"
+msgid "Context as JSON"
+msgstr "Contexto"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:291
+#, fuzzy
+msgid "Invalid JSON"
+msgstr "Host inválido"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:296
+msgid "Invalid expiration"
+msgstr "Caducidad no válida"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:297
+msgid "Attributes require an expiration date in the future or set to Never."
+msgstr ""
+"Los atributos requieren una fecha de caducidad futura o deben configurarse "
+"como «Nunca»."
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:355
+msgid "Include new information"
+msgstr "Incluir nueva información"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:356
+msgid ""
+"This step is optional. Select a form to attach newly reviewed AML/KYC "
+"information, or continue without one."
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:361
+msgid "AML/KYC form"
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:362
+msgid "Search AML/KYC forms"
+msgstr "Buscar formularios AML/KYC"
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:101
+#, fuzzy
+#| msgid "Accounts under investigation."
+msgid "The account will be included in the AML investigation queue."
+msgstr "Cuentas bajo investigación."
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:106
+#, fuzzy
+#| msgid "Accounts under investigation."
+msgid "The account will not be included in the AML investigation queue."
+msgstr "Cuentas bajo investigación."
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:114
+#, fuzzy
+#| msgid "Investigation"
+msgid "Current investigation status"
+msgstr "Investigación"
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:128
+#, fuzzy
+#| msgid "No previous decisions"
+msgid "No previous decision"
+msgstr "Sin decisiones anteriores"
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:140
+#, fuzzy
+#| msgid "Investigation"
+msgid "Investigation status after this decision"
+msgstr "Investigación"
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:145
+#, fuzzy
+#| msgid "Measures the customer must complete under the current policy."
+msgid ""
+"Choose whether the account should remain in the AML investigation queue "
+"after this decision is submitted."
+msgstr "Medidas que el cliente debe completar según la política actual."
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:201
+msgid ""
+"Full name used in the payto URI when creating this previously unknown "
+"account."
+msgstr ""
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:208
+#, fuzzy
+#| msgid "Decision date"
+msgid "Decision rationale"
+msgstr "Fecha de la decisión"
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:209
+msgid ""
+"Record the facts and reasoning needed to understand this decision in a later "
+"audit or review."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:264
+#, fuzzy
+#| msgid "Custom measures"
+msgid "Create custom measure"
+msgstr "Medidas personalizadas"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:266
+#, fuzzy
+#| msgid "Add custom measure"
+msgid "Edit custom measure"
+msgstr "Añadir medida personalizada"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:270
+msgid ""
+"Combine a customer check with an AML program, or use SKIP to run a program "
+"immediately. Context values must satisfy the selected check and program "
+"requirements."
+msgstr ""
+
+#. screenid: 122
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:289
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:478
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:366
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:115
+msgid "Add custom measure"
+msgstr "Añadir medida personalizada"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:299
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:488
+msgid "Save changes"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:306
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:495
+#, fuzzy
+#| msgid "Add custom measure"
+msgid "Remove custom measure"
+msgstr "Añadir medida personalizada"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:547
+#, fuzzy
+#| msgid "Configure verification type: %1$s"
+msgid "Configure %1$s verification"
+msgstr "Configurar tipo de verificación: %1$s"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:558
+msgid "Use advanced measure editor"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:587
+#, fuzzy
+#| msgid "Name of the verification measure"
+msgid "Use guided verification editor"
+msgstr "Nombre de la medida de verificación"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:632
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1111
+msgid "There is already a measure with that name"
+msgstr "Ya existe una medida con ese nombre"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:646
+msgid ""
+"Runs immediately for SKIP measures, or after a successful check. It may be "
+"omitted for a check that only presents or collects information."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:650
+msgid "Missing check or program"
+msgstr "Falta la verificación o el programa"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:660
+msgid ""
+"The customer-facing check to perform before the program. Leave empty to use "
+"SKIP and run the program immediately."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:683
+msgid ""
+"Configuration values required by the selected check or program. Property "
+"names and value types must match the exchange configuration."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:690
+msgid "Field name"
+msgstr "Nombre del campo"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:695
+msgid "Type"
+msgstr "Tipo"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:699
+msgid "string"
+msgstr "cadena"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:703
+msgid "number"
+msgstr "número"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:707
+msgid "boolean"
+msgstr "booleano"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:711
+msgid "json"
+msgstr "json"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:738
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:792
+#, fuzzy
+#| msgid "Form not available"
+msgid "Program \"%1$s\" is not available"
+msgstr "Formulario no disponible"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:742
+msgid "There are unsatisfied inputs: %1$s"
+msgstr "Hay entradas no satisfechas: %1$s"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:750
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:772
+msgid "Check \"%1$s\" is not available"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:756
+msgid "There are missing inputs: %1$s"
+msgstr "Faltan entradas: %1$s"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:779
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:799
+msgid "There are missing requirements: %1$s"
+msgstr "Faltan requisitos: %1$s"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:855
+msgid "Can't be empty"
+msgstr "No puede estar vacío"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:859
+msgid "Not a number"
+msgstr "No es un número"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:861
+msgid "It should be finite"
+msgstr "Debe ser finito"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:866
+msgid "It should be either \"true\" or \"false\""
+msgstr "Debe ser \"true\" o \"false\""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:871
+msgid "Couldn't parse as json string: %1$s"
+msgstr "No se pudo interpretar como cadena json: %1$s"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:899
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:946
+msgid "Description"
+msgstr "Descripción"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:915
+msgid "Inputs"
+msgstr "Entradas"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:954
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:534
+#, fuzzy
+#| msgid "Output"
+msgid "Outputs"
+msgstr "Salida"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:962
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:401
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:533
+#, fuzzy
+#| msgid "Required"
+msgid "Required context"
+msgstr "Requerido"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:970
+msgid "Fallback"
+msgstr "Alternativa"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:993
+#, fuzzy
+#| msgid "Context"
+msgid "Context values"
+msgstr "Contexto"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1045
+msgid "Selected pipeline"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1048
+msgid "Review how the exchange will execute this measure."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1105
+msgid "Name of the verification measure"
+msgstr "Nombre de la medida de verificación"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1118
+msgid "Read only"
+msgstr "Solo lectura"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1119
+msgid "Prevent the customer from changing the address"
+msgstr "Impedir que el cliente cambie la dirección"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:154
+msgid "Customer actions after submission"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:157
+msgid ""
+"Immediate measures start as soon as this decision is accepted. A measure may "
+"show information, collect customer data, or run an AML program. Leave the "
+"selection empty when no immediate customer action is required."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:302
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:301
+msgid "Too many SKIP measures"
+msgstr "Demasiadas medidas SKIP"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:303
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:302
+msgid "At most one immediate measure may use the SKIP check."
+msgstr "Como máximo una medida inmediata puede usar la comprobación SKIP."
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:332
+#, fuzzy
+#| msgid "Configure verification measure: \"%1$s\""
+msgid "Configure verification measure “%1$s”"
+msgstr "Configurar medida de verificación: \"%1$s\""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:372
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:522
+msgid "Custom measures"
+msgstr "Medidas personalizadas"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:375
+msgid "Measures defined only for this proposed decision."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:399
+msgid "Edit"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:407
+#, fuzzy
+#| msgid "All measures"
+msgid "Available exchange measures"
+msgstr "Todas las medidas"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:410
+msgid "Reusable templates configured by the exchange operator"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:432
+msgid "Use as template"
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:512
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:288
+#, fuzzy
+#| msgid "Instant measures"
+msgid "Immediate measures"
+msgstr "Medidas instantáneas"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:513
+msgid ""
+"Selected measures begin immediately after the decision is accepted by the "
+"exchange."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:518
+#, fuzzy
+#| msgid "Require all measures"
+msgid "Require every selected measure"
+msgstr "Exigir todas las medidas"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:519
+#, fuzzy
+#| msgid ""
+#| "Run all selected measures together instead of accepting any one of them."
+msgid ""
+"When enabled, all selected measures must be completed. Otherwise, completing "
+"any one of them is sufficient."
+msgstr ""
+"Ejecutar juntas todas las medidas seleccionadas en lugar de aceptar "
+"cualquiera de ellas."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:190
+#, fuzzy
+msgid "Failed to make the decision."
+msgstr "Describir la decisión."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:193
+#, fuzzy
+msgid "Invalid credentials."
+msgstr "Se dieron las credenciales incorrectas."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:195
+msgid "Session not found. Contact the administrator."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:197
+msgid ""
+"The exchange rejected the decision because the officer session is disabled "
+"or the account has a newer decision. Reload the account before trying again."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:251
+msgid ""
+"This decision records that an MROS report was filed. Confirm that the report "
+"has actually been submitted before continuing."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:264
+#, fuzzy
+#| msgid "No manual review"
+msgid "Go back and review"
+msgstr "Sin revisión manual"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:271
+msgid "Confirm decision"
+msgstr "Confirmar decisión"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:283
+msgid "Unknown measure"
+msgstr "Medida desconocida"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:284
+msgid ""
+"A rule or immediate action references a measure that is not available. "
+"Review the rules and measures before submitting."
+msgstr ""
+"Una regla o acción inmediata hace referencia a una medida que no está "
+"disponible. Revise las reglas y las medidas antes de enviar."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:291
+#, fuzzy
+#| msgid "Add custom measure"
+msgid "Invalid custom measure"
+msgstr "Añadir medida personalizada"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:292
+msgid ""
+"A custom measure references an unavailable check or program, lacks required "
+"context, or cannot provide the selected program inputs. Review the immediate "
+"measures before submitting."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:310
+msgid "Missing deadline"
+msgstr "Falta el plazo"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:311
+msgid "Set when the proposed rules expire and what should happen afterward."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:319
+msgid "Invalid rule expiration"
+msgstr "Caducidad de reglas no válida"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:320
+msgid "Rule expiration must be in the future or set to Never."
+msgstr ""
+"La caducidad de las reglas debe estar en el futuro o establecerse en «Nunca»."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:327
+msgid "Missing rules"
+msgstr "Faltan reglas"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:328
+msgid ""
+"A decision must contain the complete rule set that will apply to the account."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:337
+msgid ""
+"Review the proposed rules. Hard blocks must be explicit, and Balance and "
+"Refund rules must use an instant timeframe."
+msgstr ""
+"Revise las reglas propuestas. Los bloqueos estrictos deben ser explícitos, y "
+"las reglas de saldo y reembolso deben usar un período instantáneo."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:376
+msgid "Immediate measures not reviewed"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:378
+#, fuzzy
+#| msgid "Measures the customer must complete under the current policy."
+msgid "Review whether the customer must complete any immediate measures."
+msgstr "Medidas que el cliente debe completar según la política actual."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:384
+#, fuzzy
+#| msgid "Triggered immediately without customer interaction."
+msgid "No immediate customer action"
+msgstr "Se activan de inmediato sin interacción del cliente."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:385
+msgid "No measure will start when this decision is submitted."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:396
+#, fuzzy
+#| msgid "Account properties"
+msgid "Account properties not reviewed"
+msgstr "Propiedades de la cuenta"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:398
+msgid "Review the account properties before submitting the decision."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:409
+msgid "Reporting events not reviewed"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:411
+msgid "Review which statistical events will be recorded with the decision."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:420
+msgid "Case disposition incomplete"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:421
+msgid "You must complete the justification section."
+msgstr "Debes completar la sección de justificación."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:430
+msgid "Invalid attributes"
+msgstr "Atributos inválidos"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:431
+msgid ""
+"Correct the selected form or continue without attaching new customer "
+"information."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:443
+#, fuzzy
+#| msgid "Check account details"
+msgid "Decision details"
+msgstr "Verificar detalles de la cuenta"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:447
+msgid "Justification"
+msgstr "Justificación"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:450
+#, fuzzy
+#| msgid "Not opened"
+msgid "Not provided"
+msgstr "No abierta"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:454
+#, fuzzy
+#| msgid "Accounts under investigation."
+msgid "The account remains under investigation."
+msgstr "Cuentas bajo investigación."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:458
+#, fuzzy
+#| msgid "Accounts under investigation."
+msgid "The account will not remain under investigation."
+msgstr "Cuentas bajo investigación."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:487
+msgid "No account properties"
+msgstr "Sin propiedades de cuenta"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:493
+msgid "Events"
+msgstr "Eventos"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:496
+#, fuzzy
+#| msgid "Next event"
+msgid "No events"
+msgstr "Próximo evento"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:501
+#, fuzzy
+#| msgid "Invalid attributes"
+msgid "Submitted attributes"
+msgstr "Atributos inválidos"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:509
+#, fuzzy
+#| msgid "Expiration date"
+msgid "expiration set"
+msgstr "Fecha de vencimiento"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:515
+#, fuzzy
+#| msgid "Invalid attributes"
+msgid "No new attributes"
+msgstr "Atributos inválidos"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:537
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:550
+#, fuzzy
+#| msgid "Officer decision"
+msgid "Discard decision"
+msgstr "Decisión del agente"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:544
+#, fuzzy
+#| msgid "Send decision"
+msgid "Submit AML decision"
+msgstr "Enviar decisión"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:549
+#, fuzzy
+#| msgid "Discard this key"
+msgid "Discard this decision?"
+msgstr "Descartar esta clave"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:554
+msgid ""
+"All entries made in this decision wizard will be lost. No change will be "
+"submitted to the exchange."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:571
+#, fuzzy
+#| msgid "Review status"
+msgid "Review this step"
+msgstr "Estado de revisión"
+
+#. screenid: 113
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:172
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:250
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:507
+#, fuzzy
+#| msgid "Back to accounts"
+msgid "Back to account"
+msgstr "Volver a las cuentas"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:177
+#, fuzzy
+#| msgid "New decision"
+msgid "New AML decision"
+msgstr "Nueva decisión"
+
+#. screenid: 113
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:201
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:297
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:790
+msgid "Payto URI"
+msgstr "URI Payto"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:218
+#, fuzzy
+#| msgctxt "threshold"
+#| msgid "%1$s every %2$s"
+msgid "Step %1$s of %2$s"
+msgstr "%1$s cada %2$s"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:236
+msgid "Decision steps"
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:245
+#, fuzzy
+#| msgid "Previous event"
+msgid "Previous step"
+msgstr "Evento anterior"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:254
+#, fuzzy
+#| msgid "Next event"
+msgid "Next step"
+msgstr "Próximo evento"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:273
+#, fuzzy
+#| msgid "System information"
+msgid "Customer information"
+msgstr "Información del sistema"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:274
+#, fuzzy
+#| msgid ""
+#| "You can review AML information, but this officer key cannot submit "
+#| "decisions."
+msgid "Optionally add reviewed AML/KYC information to this decision."
+msgstr ""
+"Puede revisar la información AML, pero esta clave de responsable no puede "
+"enviar decisiones."
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:279
+msgid "Review the account state derived from the available information."
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:283
+#, fuzzy
+#| msgid "Missing events"
+msgid "Reporting events"
+msgstr "Faltan eventos"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:284
+msgid "Review the statistical events recorded with this decision."
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:289
+#, fuzzy
+#| msgid "Measures the customer must complete under the current policy."
+msgid ""
+"Choose actions the customer must complete after the decision is submitted."
+msgstr "Medidas que el cliente debe completar según la política actual."
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:293
+#, fuzzy
+#| msgctxt "operation type"
+#| msgid "Transaction"
+msgid "Transaction rules"
+msgstr "Transacción"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:294
+msgid "Set operation thresholds, escalation measures, and expiration behavior."
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:298
+msgid "Case disposition"
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:299
+#, fuzzy
+#| msgid "Accounts under investigation."
+msgid "Record the rationale and whether the case remains under investigation."
+msgstr "Cuentas bajo investigación."
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:305
+#, fuzzy
+#| msgid "Review and submit."
+msgid "Review and submit"
+msgstr "Revisar y enviar."
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:306
+msgid "Check the complete decision before signing and submitting it."
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:326
+#, fuzzy
+#| msgid "Decision date"
+msgid "Decision progress"
+msgstr "Fecha de la decisión"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:407
+#, fuzzy
+#| msgid "Failed to load account decisions."
+msgid "Loading account decision"
+msgstr "No se pudieron cargar las decisiones de la cuenta."
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:418
+#, fuzzy
+#| msgid "Decision for account:"
+msgid "Decision for account"
+msgstr "Decisión para la cuenta:"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:425
+#, fuzzy
+#| msgid "Decision for account:"
+msgid "Decision for wallet account"
+msgstr "Decisión para la cuenta:"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:431
+#, fuzzy
+#| msgid "Decision for bank account:"
+msgid "Decision for bank account"
+msgstr "Decisión para la cuenta bancaria:"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:107
+msgid "Enter a valid HTTP or HTTPS URL."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:114
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:176
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:218
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:259
+msgid "Development settings"
+msgstr "Configuración de desarrollo"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:117
+msgid ""
+"These browser-local settings are intended for development and "
+"troubleshooting."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:132
+#, fuzzy
+#| msgid "Exchange hostname"
+msgid "Exchange connection"
+msgstr "Nombre de host del exchange"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:135
+msgid ""
+"Changing the exchange reloads the application. The override is stored only "
+"in this browser."
+msgstr ""
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:147
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:97
+msgid "Exchange base URL"
+msgstr "URL base del exchange"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:166
+msgid "Leave empty to use the configured URL: %1$s"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:170
+msgid "Leave empty to derive the exchange URL from this page."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:184
+msgid "Currently connected to"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:196
+msgid "Apply and reload"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:207
+msgid "Use configured URL"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:214
+msgid "Preferences"
+msgstr "Preferencias"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:221
+msgid "AML SPA dialect"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:236
+#, fuzzy
+#| msgid "Welcome to the exchange configuration"
+msgid "Use exchange configuration"
+msgstr "Bienvenido a la configuración del exchange"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:240
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:44
+msgid "Testing"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:244
+msgid ""
+"Override how this web interface presents dialect-specific AML rules and "
+"properties. The override is stored only in this browser."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:262
+#, fuzzy
+msgid "Show debug information"
+msgstr "Mostrar información de depuración"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:45
+msgid "Fallback dialect for development and testing."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:52
+msgid "TOPS"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:53
+msgid "Taler Operations deployment for Swiss AML processes."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:56
+msgid "File note"
+msgstr "Nota del expediente"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:57
+#, fuzzy
+#| msgid "Current note on the GwG file"
+msgid "Current note on the GwG file."
+msgstr "Nota actual del expediente GwG"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:58
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:64
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:112
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:124
+msgid "Text"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:62
+msgid "Customer label"
+msgstr "Etiqueta del cliente"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:68
+msgid "Account open"
+msgstr "Cuenta abierta"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:69
+#, fuzzy
+#| msgid "Is the account active for deposit and payments?"
+msgid "Whether the account is active for deposits and payments."
+msgstr "¿Está la cuenta activa para depósitos y pagos?"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:70
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:76
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:82
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:88
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:94
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:100
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:106
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:142
+#, fuzzy
+#| msgid "boolean"
+msgid "Boolean"
+msgstr "booleano"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:74
+msgid "Domestic PEP"
+msgstr "PEP nacional"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:75
+msgid "Whether the customer is a domestic politically exposed person."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:80
+msgid "Foreign PEP"
+msgstr "PEP extranjera"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:81
+msgid "Whether the customer is a foreign politically exposed person."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:86
+msgid "International-organization PEP"
+msgstr "PEP de una organización internacional"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:87
+msgid ""
+"Whether the customer is a politically exposed person associated with an "
+"international organization."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:92
+msgid "High-risk customer"
+msgstr "Cliente de alto riesgo"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:93
+#, fuzzy
+#| msgid "Measures the customer must complete under the current policy."
+msgid "Whether the customer is classified as high risk."
+msgstr "Medidas que el cliente debe completar según la política actual."
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:98
+msgid "High-risk country"
+msgstr "País de alto riesgo"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:99
+msgid "Whether the customer is associated with a high-risk country."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:104
+msgid "Account idle"
+msgstr "Cuenta inactiva"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:105
+msgid "Whether the account has been marked as idle."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:110
+#, fuzzy
+#| msgid "Investigation trigger"
+msgid "Investigation trigger"
+msgstr "Motivo de la investigación"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:111
+#, fuzzy
+#| msgid "Informal reason why the AML investigation was triggered"
+msgid "Informal reason why the AML investigation was triggered."
+msgstr "Motivo informal por el que se activó la investigación de AML"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:116
+#, fuzzy
+#| msgid "Investigation"
+msgid "Investigation state"
+msgstr "Investigación"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:117
+#, fuzzy
+#| msgid "The MROS reporting state for the account."
+msgid "Special-clarification and MROS reporting state for the account."
+msgstr "El estado de informe MROS de la cuenta."
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:118
+#, fuzzy
+#| msgid "Operation"
+msgid "Enumeration"
+msgstr "Operación"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:122
+#, fuzzy
+#| msgid "Sanctions-list best match"
+msgid "Sanction-list best match"
+msgstr "Mejor coincidencia en la lista de sanciones"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:123
+#, fuzzy
+#| msgid "Identifies the sanction list entry that the account matched against"
+msgid ""
+"Sanction-list entry that best matched the account, regardless of match "
+"quality."
+msgstr ""
+"Identifica la entrada de la lista de sanciones con la que coincidió la cuenta"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:128
+#, fuzzy
+#| msgid "Sanctions-list rating"
+msgid "Sanction-list rating"
+msgstr "Valoración de la coincidencia en la lista de sanciones"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:129
+msgid "Score from 0 (no match) to 1,000,000,000 (best match)."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:130
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:136
+#, fuzzy
+#| msgid "Internal"
+msgid "Integer"
+msgstr "Interno"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:134
+#, fuzzy
+#| msgid "Sanctions-list confidence"
+msgid "Sanction-list confidence"
+msgstr "Confianza de la coincidencia en la lista de sanciones"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:135
+msgid ""
+"Score from 0 (no supporting data) to 1,000,000,000 (highest confidence)."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:140
+#, fuzzy
+#| msgid "Suppress sanctions-list match"
+msgid "Suppress sanction-list match"
+msgstr "Suprimir coincidencia en la lista de sanciones"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:141
+msgid ""
+"Whether this account's sanction-list hit is treated as a false positive."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:148
+#, fuzzy
+#| msgid "Account open"
+msgid "Account opened"
+msgstr "Cuenta abierta"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:149
+msgid "Recorded when an account changes to open."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:153
+#, fuzzy
+#| msgid "Account case"
+msgid "Account closed"
+msgstr "Caso de cuenta"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:154
+msgid "Recorded when an account changes from open to closed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:158
+#, fuzzy
+#| msgid "High-risk customer"
+msgid "High-risk customer classification added"
+msgstr "Cliente de alto riesgo"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:159
+msgid ""
+"Recorded when an open account becomes classified as a high-risk customer."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:163
+#, fuzzy
+#| msgid "High-risk customer"
+msgid "High-risk customer classification removed"
+msgstr "Cliente de alto riesgo"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:164
+msgid "Recorded when the high-risk customer classification is removed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:168
+#, fuzzy
+#| msgid "High-risk country"
+msgid "High-risk country classification added"
+msgstr "País de alto riesgo"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:169
+msgid ""
+"Recorded when an open account becomes associated with a high-risk country."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:173
+msgid "High-risk country classification removed"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:174
+msgid "Recorded when the high-risk country classification is removed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:178
+msgid "PEP classification added"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:179
+msgid "Recorded when an open account becomes associated with any PEP category."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:183
+#, fuzzy
+#| msgid "No justification was recorded."
+msgid "PEP classification removed"
+msgstr "No se registró ninguna justificación."
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:184
+msgid ""
+"Recorded when the account is no longer associated with any PEP category."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:188
+msgid "Foreign PEP classification added"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:189
+msgid "Recorded when an open account becomes associated with a foreign PEP."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:193
+msgid "Foreign PEP classification removed"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:194
+msgid "Recorded when the foreign PEP classification is removed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:198
+msgid "Domestic PEP classification added"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:199
+msgid "Recorded when an open account becomes associated with a domestic PEP."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:203
+msgid "Domestic PEP classification removed"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:204
+msgid "Recorded when the domestic PEP classification is removed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:208
+#, fuzzy
+#| msgid "International-organization PEP"
+msgid "International-organization PEP classification added"
+msgstr "PEP de una organización internacional"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:209
+#, fuzzy
+#| msgid "Does account belong to an international-organization PEP?"
+msgid ""
+"Recorded when an open account becomes associated with an international-"
+"organization PEP."
+msgstr "¿Pertenece la cuenta a un PEP de organización internacional?"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:213
+#, fuzzy
+#| msgid "International-organization PEP"
+msgid "International-organization PEP classification removed"
+msgstr "PEP de una organización internacional"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:214
+msgid ""
+"Recorded when the international-organization PEP classification is removed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:218
+msgid "Simple suspicion reported to MROS"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:219
+msgid "Recorded when a report is filed under Article 305ter paragraph 2 StGB."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:223
+#, fuzzy
+#| msgid "Reported substantiated suspicion"
+msgid "Substantiated suspicion reported to MROS"
+msgstr "Sospecha fundamentada informada"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:224
+msgid "Recorded when a report is filed under Article 9 GwG."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:228
+#, fuzzy
+#| msgid "Investigation trigger"
+msgid "Investigation concluded"
+msgstr "Motivo de la investigación"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:229
+msgid "Recorded when a pending special clarification is concluded."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:233
+#, fuzzy
+#| msgid "Investigation trigger"
+msgid "Investigation conclusion reversed"
+msgstr "Motivo de la investigación"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:234
+msgid ""
+"Recorded when a previously concluded investigation returns to a non-"
+"concluded state."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:50
+msgid "Browser override"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:52
+#, fuzzy
+#| msgid "Welcome to the exchange configuration"
+msgid "Exchange configuration"
+msgstr "Bienvenido a la configuración del exchange"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:53
+#, fuzzy
+#| msgid "Default rules"
+msgid "Default fallback"
+msgstr "Reglas predeterminadas"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:59
+#, fuzzy
+#| msgid "Welcome to the exchange configuration"
+msgid "Exchange and AML configuration"
+msgstr "Bienvenido a la configuración del exchange"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:62
+msgid ""
+"Exchange identity, the active AML dialect, and the checks and programs "
+"available to AML decisions."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:71
+msgid "Public information reported by this exchange."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:75
+msgid "Base URL"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:76
+msgid "Protocol"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:77
+msgid "Protocol version"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:78
+#, fuzzy
+#| msgid "Operation"
+msgid "Implementation"
+msgstr "Operación"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:80
+#, fuzzy
+#| msgid "Not opened"
+msgid "Not reported"
+msgstr "No abierta"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:82
+msgid "Currency"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:88
+msgid "AML dialect"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:95
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:119
+#, fuzzy
+#| msgid "Effective decision"
+msgid "Effective dialect"
+msgstr "Decisión vigente"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:111
+#, fuzzy
+#| msgid "Configure measure"
+msgid "Configured dialect"
+msgstr "Configurar medida"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:114
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:504
+#, fuzzy
+#| msgid "Not opened"
+msgid "Not specified"
+msgstr "No abierto"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:129
+msgid "Canonical properties defined by the effective dialect."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:130
+#, fuzzy
+#| msgid "No account properties"
+msgid "This dialect does not define account properties."
+msgstr "Sin propiedades de cuenta"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:136
+#, fuzzy
+#| msgid "Reset to default"
+msgid "Derived events"
+msgstr "Restablecer a los valores predeterminados"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:137
+#, fuzzy
+#| msgid "No account properties"
+msgid "Canonical events derived from account property changes."
+msgstr "Sin propiedades de cuenta"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:138
+msgid "This dialect does not define derived events."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:144
+#, fuzzy
+#| msgid "All measures"
+msgid "AML measures"
+msgstr "Todas las medidas"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:145
+msgid ""
+"Checks, programs, root measures, and default rules reported by the exchange."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:213
+#, fuzzy
+#| msgctxt "threshold"
+#| msgid "%1$s every %2$s"
+msgid "%1$s entry"
+msgstr "%1$s cada %2$s"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:214
+msgid "%1$s entries"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:277
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:289
+#, fuzzy
+msgid "Failed to load the exchange AML measures."
+msgstr "Medidas activas actuales"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:300
+#, fuzzy
+#| msgid "The measures endpoint was not found."
+msgid "The measures endpoint is not available."
+msgstr "No se encontró el punto de acceso de las medidas."
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:306
+#, fuzzy
+#| msgid "The account state changed. Reload it and try again."
+msgid "The exchange configuration changed. Reload it and try again."
+msgstr ""
+"El estado de la cuenta ha cambiado. Vuelva a cargarla e inténtelo de nuevo."
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:332
+#, fuzzy
+#| msgid "Required measures"
+msgid "Retry loading measures"
+msgstr "Medidas obligatorias"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:351
+#, fuzzy
+#| msgid "Reset measure"
+msgid "Root measures"
+msgstr "Restablecer medida"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:366
+msgid "No root measures are configured."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:371
+#, fuzzy
+#| msgid "Check"
+msgid "KYC checks"
+msgstr "Verificar"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:386
+msgid "No KYC checks are configured."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:391
+#, fuzzy
+#| msgid "Program"
+msgid "AML programs"
+msgstr "Programa"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:405
+#, fuzzy
+#| msgid "Requirements"
+msgid "Required inputs"
+msgstr "Requisitos"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:413
+msgid "No AML programs are configured."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:428
+msgid "No default AML rules are configured."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:480
+#, fuzzy
+#| msgid "Check"
+msgid "KYC check"
+msgstr "Verificar"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:484
+msgid "Built-in check that proceeds without collecting customer data."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:491
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:497
+#, fuzzy
+#| msgid "Program"
+msgid "AML program"
+msgstr "Programa"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:536
+#, fuzzy
+#| msgid "All measures"
+msgid "Fallback measure"
+msgstr "Todas las medidas"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:602
+#, fuzzy
+#| msgid "Unavailable"
+msgid "Unavailable reference"
+msgstr "No disponible"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:48
+msgid "Session and access"
+msgstr "Sesión y acceso"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:51
+msgid ""
+"Review this officer's exchange access and manage the unlocked key in this "
+"browser."
+msgstr ""
+"Revise el acceso de este responsable al exchange y gestione la clave "
+"desbloqueada en este navegador."
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:66
+msgid "Officer access"
+msgstr "Acceso del responsable"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:71
+msgid "Officer name"
+msgstr "Nombre del responsable"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:77
+msgid "Permissions"
+msgstr "Permisos"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:88
+msgid "Read-only"
+msgstr "Solo lectura"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:90
+msgid "Read and write"
+msgstr "Lectura y escritura"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:118
+msgid "Session security"
+msgstr "Seguridad de la sesión"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:121
+msgid "Lock the session when you leave this device unattended."
+msgstr "Bloquee la sesión cuando deje este dispositivo desatendido."
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:133
+msgid "Lock now"
+msgstr "Bloquear ahora"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:148
+msgid "Unlocked"
+msgstr "Desbloqueada"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:154
+msgid "Locks automatically"
+msgstr "Bloqueo automático"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:165
+msgid "Exact time"
+msgstr "Hora exacta"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:185
+msgid "Copy public key"
+msgstr "Copiar clave pública"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:200
+msgid "Remove key from this browser"
+msgstr "Eliminar la clave de este navegador"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:203
+msgid ""
+"Removing this key deletes the officer key from this browser. It does not "
+"revoke or change the officer's access at the exchange. Ask the exchange "
+"operator to revoke access if needed."
+msgstr ""
+"Eliminar esta clave borra la clave del responsable de este navegador. No "
+"revoca ni modifica el acceso del responsable en el exchange. Si es "
+"necesario, solicite al operador del exchange que revoque el acceso."
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:214
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:222
+msgid "Remove key"
+msgstr "Eliminar clave"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:221
+msgid "Remove officer key?"
+msgstr "¿Eliminar la clave del responsable?"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:231
+msgid ""
+"This deletes the officer key from this browser. You will need to create and "
+"enroll a new key to use the AML WebUI here again."
+msgstr ""
+"Esto borra la clave del responsable de este navegador. Deberá crear y "
+"registrar una nueva clave para volver a utilizar aquí la interfaz web de AML."
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:237
+msgid ""
+"This does not revoke the officer at the exchange. Ask the exchange operator "
+"to revoke its access if the key may be compromised."
+msgstr ""
+"Esto no revoca al responsable en el exchange. Solicite al operador del "
+"exchange que revoque su acceso si la clave pudiera estar comprometida."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:86
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:559
+msgid "Find account"
+msgstr "Buscar cuenta"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:89
+msgid "Look up an account by its payto information or normalized payto hash."
+msgstr ""
+"Busque una cuenta por su información payto o por su hash payto normalizado."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:100
+msgid "Find by payto"
+msgstr "Buscar por payto"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:146
+msgid "Find by normalized payto hash"
+msgstr "Buscar por hash payto normalizado"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:169
+msgid "Enter a valid 52-character normalized payto hash."
+msgstr "Introduzca un hash payto normalizado válido de 52 caracteres."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:179
+msgid "Open account"
+msgstr "Abrir cuenta"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:214
+msgid "Failed to load account decisions."
+msgstr "No se pudieron cargar las decisiones de la cuenta."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:223
+msgid "Failed to load the account history."
+msgstr "No se pudo cargar el historial de la cuenta."
+
+#. screenid: 111
+#. screenid: 110
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:228
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:82
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:268
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:66
+msgid ""
+"This session signature is invalid, contact administrator or create a new one."
+msgstr ""
+"La firma de esta sesión no es válida. Póngase en contacto con el "
+"administrador o cree una nueva."
+
+#. screenid: 111
+#. screenid: 110
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:235
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:89
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:275
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:73
+msgid ""
+"The designated AML session is not known, contact administrator or create a "
+"new one."
+msgstr ""
+"La sesión AML indicada es desconocida. Póngase en contacto con el "
+"administrador o cree una nueva."
+
+#. screenid: 111
+#. screenid: 110
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:242
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:96
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:282
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:80
+msgid ""
+"The designated AML session is not enabled, contact administrator or create a "
+"new one."
+msgstr ""
+"La sesión AML indicada no está habilitada. Póngase en contacto con el "
+"administrador o cree una nueva."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:268
+#, fuzzy
+#| msgid "Account not found"
+msgid "Account found"
+msgstr "Cuenta no encontrada"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:271
+msgid ""
+"This account has an AML decision history. Open its case to review current "
+"rules, measures, attributes, and past decisions."
+msgstr ""
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:283
+#, fuzzy
+#| msgid "Open account"
+msgid "Open account case"
+msgstr "Abrir cuenta"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:309
+msgid "Active"
+msgstr ""
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:311
+#, fuzzy
+#| msgid "Effective decision"
+msgid "No active decision"
+msgstr "Decisión vigente"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:317
+#, fuzzy
+#| msgid "File status"
+msgid "Case status"
+msgstr "Estado del expediente"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:321
+#, fuzzy
+#| msgid "Investigation trigger"
+msgid "Investigation required"
+msgstr "Motivo de la investigación"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:323
+#, fuzzy
+#| msgid "Investigation state"
+msgid "No investigation requested"
+msgstr "Estado de la investigación"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:333
+msgid "Account not found"
+msgstr "Cuenta no encontrada"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:335
+msgid "There is no history known for this account yet."
+msgstr "Aún no hay historial conocido para esta cuenta."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:350
+#, fuzzy
+#| msgid "You can make a decision for this account anyway."
+msgid "Start a decision for this account"
+msgstr "Aun así, puedes tomar una decisión para esta cuenta."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:403
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:445
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:493
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:533
+msgid "Search"
+msgstr "Buscar"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:575
+msgid "Taler Bank"
+msgstr "Taler Bank"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:579
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:364
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:433
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:441
+msgid "Wallet"
+msgstr "Cartera"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:583
+msgid "Generic Payto:// URI"
+msgstr "URI genérica Payto://"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:586
+msgid "Account type"
+msgstr "Tipo de cuenta"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:596
+msgid "Should be 52 characters."
+msgstr "Debe tener 52 caracteres."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:598
+msgid "Failed to parse: %1$s"
+msgstr "No se pudo interpretar: %1$s"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:610
+msgid "Address contains invalid characters."
+msgstr "La dirección contiene caracteres inválidos."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:612
+msgid "Can't mix uppercased and lowercased characters."
+msgstr "No se pueden mezclar mayúsculas y minúsculas."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:614
+msgid "The addr checksum doesn't match."
+msgstr "La suma de verificación de la dirección no coincide."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:616
+msgid "Missing separator or address type."
+msgstr "Falta el separador o el tipo de dirección."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:618
+msgid "Address should have less than 90 characters."
+msgstr "La dirección debe tener menos de 90 caracteres."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:620
+msgid "Address should have more than 6 characters."
+msgstr "La dirección debe tener más de 6 caracteres."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:622
+msgid "Decoding issue."
+msgstr "Problema de decodificación."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:624
+msgid "Invalid data"
+msgstr "Datos no válidos"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:634
+msgid "Unsupported country."
+msgstr "País no compatible."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:636
+msgid "IBANs have fewer than 34 characters."
+msgstr "Los IBAN tienen menos de 34 caracteres."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:638
+msgid "IBANs have more than 4 characters."
+msgstr "Los IBAN tienen más de 4 caracteres."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:640
+msgid "IBAN length is invalid for this country."
+msgstr "La longitud del IBAN no es válida para este país."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:642
+msgid "It should only contain numbers and letters."
+msgstr "Solo debe contener números y letras."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:644
+msgid "The checksum is wrong."
+msgstr "La suma de verificación es incorrecta."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:662
+msgid "The string should start with payto://"
+msgstr "La cadena debe comenzar con payto://"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:664
+msgid "After the target type it should follow a '/' with more information."
+msgstr "Después del tipo de destino debe seguir un '/' con más información."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:666
+msgid ""
+"The target type is not supported, only x-taler-bank, taler-reserve or iban"
+msgstr ""
+"El tipo de destino no es compatible, solo x-taler-bank, taler-reserve o iban"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:671
+msgid "IBAN is missing"
+msgstr "Falta el IBAN"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:673
+msgid "Bitcoin address is missing"
+msgstr "Falta la dirección de Bitcoin"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:675
+msgid "Bank host and account is missing"
+msgstr "Falta el host y la cuenta del banco"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:677
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:679
+msgid "Exchange host and account is missing"
+msgstr "Falta el host y la cuenta del exchange"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:681
+msgid "Ethereum address is missing"
+msgstr "Falta la dirección de Ethereum"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:683
+msgid "Cyclos address is missing"
+msgstr "Falta la dirección de Cyclos"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:685
+msgid "Void address is missing"
+msgstr "Falta la dirección void"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:693
+msgid "Invalid IBAN: %1$s"
+msgstr "IBAN inválido: %1$s"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:700
+msgid "Invalid BTC: %1$s"
+msgstr "BTC inválido: %1$s"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:705
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:728
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:741
+msgid "Invalid reserve: %1$s"
+msgstr "Reserva inválida: %1$s"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:716
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:726
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:739
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:760
+msgid "Invalid host"
+msgstr "Host inválido"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:718
+msgid "Invalid account"
+msgstr "Cuenta inválida"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:752
+msgid "Invalid address"
+msgstr "Dirección inválida"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:791
+msgid "As defined by RFC 8905"
+msgstr "Según se define en el RFC 8905"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:792
+msgid "payto://"
+msgstr "payto://"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:807
+msgid "International Bank Account Number"
+msgstr "Número de cuenta bancaria internacional"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:808
+msgid "DE1231231231"
+msgstr "DE1231231231"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:820
+msgid "Host"
+msgstr "Host"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:821
+msgid "Exchange hostname"
+msgstr "Nombre de host del exchange"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:822
+msgid "exchange.taler.net"
+msgstr "exchange.taler.net"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:827
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:874
+msgid "Remove last '/'"
+msgstr "Quitar el último '/'"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:829
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:846
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:426
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:472
+msgid "Invalid value"
+msgstr "Valor inválido"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:837
+msgid "ID"
+msgstr "ID"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:838
+msgid "Wallet reserve public key"
+msgstr "Clave pública de reserva de la cartera"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:839
+msgid "abcdef1235"
+msgstr "abcdef1235"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:844
+msgid "Should be 52 characters"
+msgstr "Debe tener 52 caracteres"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:860
+msgid "Bank account identification"
+msgstr "Identificación de la cuenta bancaria"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:861
+msgid "DE123123123"
+msgstr "DE123123123"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:867
+msgid "Hostname"
+msgstr "Nombre de host"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:868
+msgid "Without the scheme, may include subpath: bank.com, bank.com/path/"
+msgstr "Sin el esquema, puede incluir subruta: bank.com, bank.com/path/"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:869
+msgid "bank.demo.taler.net"
+msgstr "bank.demo.taler.net"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:876
+msgid "Invalid hostname"
+msgstr "Nombre de host inválido"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:68
+msgid "Failed to load account information."
+msgstr "No se pudo cargar la información de la cuenta."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:77
+msgid "Failed to load the account information."
+msgstr ""
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:115
+msgid "Collection event not found"
+msgstr "No se encontró el evento de recopilación"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:117
+msgid "There is no collection event with ID %1$s for this account."
+msgstr "No hay ningún evento de recopilación con el ID %1$s para esta cuenta."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:129
+msgid "Attributes unavailable"
+msgstr "Atributos no disponibles"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:131
+msgid "The collection event does not contain readable attributes."
+msgstr "El evento de recopilación no contiene atributos legibles."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:148
+msgid "Form identifier missing"
+msgstr "Falta el identificador del formulario"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:150
+msgid "The collected information does not identify the form used to create it."
+msgstr ""
+"La información recopilada no identifica el formulario utilizado para crearla."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:165
+msgid "Form not available"
+msgstr "Formulario no disponible"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:167
+msgid "Form %1$s is not configured in this AML Web UI."
+msgstr "El formulario %1$s no está configurado en esta interfaz web de AML."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:255
+#, fuzzy
+#| msgid "Collected information"
+msgid "Collected AML/KYC information"
+msgstr "Información recopilada"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:262
+#, fuzzy
+#| msgid "Forms"
+msgid "Form"
+msgstr "Formularios"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:267
+#, fuzzy
+#| msgid "Collected information"
+msgid "Collected"
+msgstr "Información recopilada"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:270
+msgid "Source"
+msgstr ""
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:274
+#, fuzzy
+#| msgid "Custom properties"
+msgid "Customer process"
+msgstr "Propiedades personalizadas"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:277
+#, fuzzy
+#| msgid "Events"
+msgid "Event ID"
+msgstr "Eventos"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:284
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:292
+msgid "Different form version"
+msgstr "Versión de formulario diferente"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:285
+msgid ""
+"The collected information does not identify the form version used. The "
+"latest configured version is shown and field labels may differ from those "
+"used at collection time."
+msgstr ""
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:293
+#, fuzzy
+#| msgid "Form %1$s is not configured in this AML Web UI."
+msgid ""
+"Form version %1$s is not configured in this AML Web UI. Version %2$s is "
+"shown and field labels may differ."
+msgstr "El formulario %1$s no está configurado en esta interfaz web de AML."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:301
+#, fuzzy
+#| msgid "Collected information"
+msgid "Collected information events"
+msgstr "Información recopilada"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:305
+#, fuzzy
+#| msgid "Next event"
+msgid "Older event"
+msgstr "Próximo evento"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:316
+#, fuzzy
+#| msgid "Next event"
+msgid "Newer event"
+msgstr "Próximo evento"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:329
+#, fuzzy
+#| msgid "Invalid attributes"
+msgid "Submitted values"
+msgstr "Atributos inválidos"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:369
+#, fuzzy
+#| msgid "Officer name"
+msgid "Officer view"
+msgstr "Nombre del responsable"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:371
+#, fuzzy
+#| msgid "Customer-visible"
+msgid "Customer view"
+msgstr "Visible para el cliente"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:372
+msgid "JSON view"
+msgstr ""
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:403
+#, fuzzy
+#| msgid "System information"
+msgid "Submitted information view"
+msgstr "Información del sistema"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:109
+msgid "Incoming"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:113
+msgid "Outgoing"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:117
+msgid "KYC authorization"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:127
+msgid "Wallet credits (P2P)"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:140
+#, fuzzy
+#| msgid "Transfers history"
+msgid "Transfer category"
+msgstr "Historial de transferencias"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:147
+msgid "Minimum amount"
+msgstr "Monto mínimo"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:148
+msgid "All amounts below the given threshold will be filtered."
+msgstr "Se filtrarán todos los montos por debajo del umbral indicado."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:182
+#, fuzzy
+#| msgid "Exchange hostname"
+msgid "Exchange transfer activity"
+msgstr "Nombre de host del exchange"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:188
+#, fuzzy
+#| msgid "Transfers history"
+msgid "Wallet credit activity"
+msgstr "Historial de transferencias"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:190
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:198
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:241
+#, fuzzy
+#| msgid "Transfers history"
+msgid "Transfer activity"
+msgstr "Historial de transferencias"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:196
+#, fuzzy
+#| msgid "Transfers history for account"
+msgid "Transfer activity for account"
+msgstr "Historial de transferencias de la cuenta"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:204
+msgid ""
+"Inspect successful P2P credits received by this wallet. Requests that were "
+"not paid are not shown."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:209
+msgid ""
+"Inspect effective bank transfers observed by the exchange. Credit transfers "
+"are incoming, debit transfers are outgoing, and bounced or drain transfers "
+"are not included."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:215
+msgid ""
+"Inspect effective transfers observed by the exchange. Incoming, outgoing, "
+"and KYC authorization entries are bank transfers. Wallet credits are "
+"successful P2P transfers into wallets."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:233
+#, fuzzy
+#| msgid "Transfers history"
+msgid "Transfer filters"
+msgstr "Historial de transferencias"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:254
+#, fuzzy
+msgid "Failed to load transfer list."
+msgstr "No se pudo interpretar: %1$s"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:263
+msgid "Failed to load the transfer list."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:299
+msgid "Select transaction type"
+msgstr "Selecciona el tipo de transacción"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:300
+msgid "Please select a transaction type to show transactions."
+msgstr "Selecciona un tipo de transacción para mostrar las transacciones."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:314
+#, fuzzy
+#| msgid "No transfers yet."
+msgid "No wallet credits yet."
+msgstr "Aún no hay transferencias."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:315
+msgid "No transfers yet."
+msgstr "Aún no hay transferencias."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:319
#, fuzzy
-msgid "Failed to load the account history."
-msgstr "Nombre completo del titular de la cuenta"
+#| msgid "There are no transfers for this account."
+msgid "There are no P2P credits for this wallet."
+msgstr "No hay transferencias para esta cuenta."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:205
-msgid "Check account details"
-msgstr "Verificar detalles de la cuenta"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:323
+#, fuzzy
+#| msgid ""
+#| "There are no transfers reported to the exchange with the current "
+#| "threshold."
+msgid ""
+"There are no wallet credits reported to the exchange with the current "
+"threshold."
+msgstr "No hay transferencias informadas al exchange con el umbral actual."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:212
-msgid "Account most recent decisions"
-msgstr "Decisiones más recientes de la cuenta"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:328
+msgid "There are no transfers for this account."
+msgstr "No hay transferencias para esta cuenta."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:231
-msgid "When"
-msgstr "Cuándo"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:332
+msgid ""
+"There are no transfers reported to the exchange with the current threshold."
+msgstr "No hay transferencias informadas al exchange con el umbral actual."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:265
-msgid "LATEST"
-msgstr "MÁS RECIENTE"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:343
+msgid "Unknown date"
+msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:270
-msgid "ACTIVE"
-msgstr "ACTIVA"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:355
+msgid "Time"
+msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:297
-msgid "Account not found"
-msgstr "Cuenta no encontrada"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:359
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:406
+msgid "Amount"
+msgstr "Monto"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:298
-msgid "There is no history known for this account yet."
-msgstr "Aún no hay historial conocido para esta cuenta."
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:393
+msgid "Unknown time"
+msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:308
-msgid "You can make a decision for this account anyway."
-msgstr "Aun así, puedes tomar una decisión para esta cuenta."
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:410
+#, fuzzy
+#| msgid "Credit"
+msgid "credited"
+msgstr "Crédito"
-#. screenid: 111
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:357
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:400
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:449
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:490
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:377
-msgid "Search"
-msgstr "Buscar"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:412
+msgid "sent"
+msgstr "enviado"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:528
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:761
-msgid "IBAN"
-msgstr "IBAN"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:413
+msgid "received"
+msgstr "recibido"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:532
-msgid "Taler Bank"
-msgstr "Taler Bank"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:443
+msgid "to"
+msgstr "a"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:536
-msgid "Wallet"
-msgstr "Cartera"
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:444
+msgid "from"
+msgstr "de"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:540
-msgid "Generic Payto:// URI"
-msgstr "URI genérica Payto://"
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:165
+msgid "This exchange is not compatible with the AML WebUI."
+msgstr "Este exchange no es compatible con la interfaz web de AML."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:543
-msgid "Account type"
-msgstr "Tipo de cuenta"
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:167
+msgid ""
+"Officer identity and permissions require exchange protocol v40 or newer."
+msgstr ""
+"La identidad y los permisos del responsable requieren el protocolo del "
+"exchange v40 o posterior."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:553
-msgid "Should be 52 characters."
-msgstr "Debe tener 52 caracteres."
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:191
+msgid "Verifying that this public key is enrolled by the exchange."
+msgstr "Comprobando que esta clave pública esté registrada en el exchange."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:555
-msgid "Failed to parse: %1$s"
-msgstr "No se pudo interpretar: %1$s"
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:278
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:331
+msgid "Read-only officer access"
+msgstr "Acceso de responsable de solo lectura"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:567
-msgid "Address contains invalid characters."
-msgstr "La dirección contiene caracteres inválidos."
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:279
+msgid ""
+"You can review AML information, but this officer key cannot submit decisions."
+msgstr ""
+"Puede revisar la información AML, pero esta clave de responsable no puede "
+"enviar decisiones."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:569
-msgid "Can't mix uppercased and lowercased characters."
-msgstr "No se pueden mezclar mayúsculas y minúsculas."
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:332
+msgid "This officer key cannot create or submit AML decisions."
+msgstr "Esta clave de responsable no puede crear ni enviar decisiones de AML."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:571
-msgid "The addr checksum doesn't match."
-msgstr "La suma de verificación de la dirección no coincide."
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:340
+msgid "Return to account"
+msgstr "Volver a la cuenta"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:573
-msgid "Missing separator or address type."
-msgstr "Falta el separador o el tipo de dirección."
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:466
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:475
+msgid "Failed to load the active AML decision."
+msgstr "No se pudo cargar la decisión AML activa."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:575
-msgid "Address should have less than 90 characters."
-msgstr "La dirección debe tener menos de 90 caracteres."
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:484
+msgid "The account was not found."
+msgstr "No se encontró la cuenta."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:577
-msgid "Address should have more than 6 characters."
-msgstr "La dirección debe tener más de 6 caracteres."
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:488
+msgid "The account state changed. Reload it and try again."
+msgstr ""
+"El estado de la cuenta ha cambiado. Vuelva a cargarla e inténtelo de nuevo."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:579
-msgid "Decoding issue."
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:511
+msgid ""
+"The payto URI does not belong to this account. Return to the account search "
+"and start the decision again."
msgstr ""
+"El URI payto no pertenece a esta cuenta. Vuelva a la búsqueda de cuentas e "
+"inicie de nuevo la decisión."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:581
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:571
#, fuzzy
-msgid "Invalid data"
-msgstr "Host inválido"
+#| msgid "AML navigation"
+msgid "AML configuration"
+msgstr "Navegación AML"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:591
-msgid "Unsupported country."
-msgstr "País no compatible."
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:577
+msgid "Session"
+msgstr "Sesión"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:593
-msgid "IBANs have fewer than 34 characters."
-msgstr "Los IBAN tienen menos de 34 caracteres."
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:585
+msgid "AML navigation"
+msgstr "Navegación AML"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:595
-msgid "IBANs have more than 4 characters."
-msgstr "Los IBAN tienen más de 4 caracteres."
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:49
+#, fuzzy
+msgid "Failed to load server measures."
+msgstr "Medidas del servidor"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:597
-msgid "IBAN length is invalid for this country."
-msgstr "La longitud del IBAN no es válida para este país."
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:61
+#, fuzzy
+msgid "Failed to load the measures"
+msgstr "Medidas activas actuales"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:597
-msgid "It should only contain numbers and letters."
-msgstr "Solo debe contener números y letras."
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:102
+msgid "Measures"
+msgstr "Medidas"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:599
-msgid "The checksum is wrong."
-msgstr "La suma de verificación es incorrecta."
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:105
+#, fuzzy
+msgid "A list of all the predefined measures you can use."
+msgstr "Una lista de todas las medidas predefinidas disponibles para usar."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:617
-msgid "The string should start with payto://"
-msgstr "La cadena debe comenzar con payto://"
+#~ msgid "AML officer justification"
+#~ msgstr "Justificación del oficial de AML"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:619
-msgid "After the target type it should follow a '/' with more information."
-msgstr "Después del tipo de destino debe seguir un '/' con más información."
+#~ msgid "Effective policy"
+#~ msgstr "Política vigente"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:621
-msgid ""
-"The target type is not supported, only x-taler-bank, taler-reserve or iban"
-msgstr ""
-"El tipo de destino no es compatible, solo x-taler-bank, taler-reserve o iban"
+#~ msgid "Account assessment"
+#~ msgstr "Evaluación de la cuenta"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:626
-msgid "IBAN is missing"
-msgstr "Falta el IBAN"
+#~ msgid "Properties recorded by AML officers for this account."
+#~ msgstr "Propiedades registradas por agentes AML para esta cuenta."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:628
-msgid "Bitcoin address is missing"
-msgstr "Falta la dirección de Bitcoin"
+#~ msgid "Account assessment could not be loaded"
+#~ msgstr "No se pudo cargar la evaluación de la cuenta"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:630
-msgid "Bank host and account is missing"
-msgstr "Falta el host y la cuenta del banco"
+#~ msgid "No assessment properties have been recorded for this account."
+#~ msgstr "No se han registrado propiedades de evaluación para esta cuenta."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:632
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:634
-msgid "Exchange host and account is missing"
-msgstr "Falta el host y la cuenta del exchange"
+#~ msgid "Currently applied rules"
+#~ msgstr "Reglas aplicadas actualmente"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:636
-msgid "Ethereum address is missing"
-msgstr "Falta la dirección de Ethereum"
+#~ msgid ""
+#~ "This account has no account-specific decision. The exchange default rules "
+#~ "currently apply."
+#~ msgstr ""
+#~ "Esta cuenta no tiene una decisión específica. Actualmente se aplican las "
+#~ "reglas predeterminadas del intercambio."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:638
-msgid "Cyclos address is missing"
-msgstr "Falta la dirección de Cyclos"
+#, fuzzy
+#~ msgid "Keep case under investigation"
+#~ msgstr "No está bajo investigación"
+
+#~ msgid "Account views"
+#~ msgstr "Vistas de cuentas"
+
+#~ msgid "Date"
+#~ msgstr "Fecha"
+
+#~ msgid "Show transfers"
+#~ msgstr "Mostrar transferencias"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:640
#, fuzzy
-msgid "Void address is missing"
-msgstr "Falta la dirección de Bitcoin"
+#~ msgid "View decision history"
+#~ msgstr "Historial de decisiones"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:648
-msgid "Invalid IBAN: %1$s"
-msgstr "IBAN inválido: %1$s"
+#~ msgid "Save PDF"
+#~ msgstr "Guardar PDF"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:655
-msgid "Invalid BTC: %1$s"
-msgstr "BTC inválido: %1$s"
+#~ msgid "Manual review required"
+#~ msgstr "Se requiere revisión manual"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:660
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:683
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:696
-msgid "Invalid reserve: %1$s"
-msgstr "Reserva inválida: %1$s"
+#~ msgid "At a glance"
+#~ msgstr "De un vistazo"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:671
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:681
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:694
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:715
-msgid "Invalid host"
-msgstr "Host inválido"
+#~ msgid "Requirements present"
+#~ msgstr "Hay requisitos"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:707
-msgid "Invalid address"
-msgstr "Dirección inválida"
+#~ msgid "Current assessment and policy"
+#~ msgstr "Evaluación y política actuales"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:745
-msgid "Payto URI"
-msgstr "URI Payto"
+#~ msgid "The current account properties and effective AML rules."
+#~ msgstr "Las propiedades actuales de la cuenta y las reglas AML vigentes."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:746
-msgid "As defined by RFC 8905"
-msgstr "Según se define en el RFC 8905"
+#, fuzzy
+#~ msgid "Property"
+#~ msgstr "Propiedades"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:747
-msgid "payto://"
-msgstr "payto://"
+#~ msgid "The officer session signature is invalid."
+#~ msgstr "La firma de la sesión del responsable de AML no es válida."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:762
-msgid "International Bank Account Number"
-msgstr "Número de cuenta bancaria internacional"
+#~ msgid "The requested AML account was not found."
+#~ msgstr "No se encontró la cuenta AML solicitada."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:763
-msgid "DE1231231231"
-msgstr "DE1231231231"
+#~ msgid "The officer session is disabled or the account state changed."
+#~ msgstr ""
+#~ "La sesión del responsable de AML está deshabilitada o cambió el estado de "
+#~ "la cuenta."
+
+#, fuzzy
+#~ msgid "Account audit trail"
+#~ msgstr "Filtros de cuentas"
+
+#~ msgid "(all)"
+#~ msgstr "(todos)"
+
+#~ msgid "Info"
+#~ msgstr "Información"
+
+#~ msgid "Will show information to the user."
+#~ msgstr "Mostrará información al usuario."
+
+#~ msgid ""
+#~ "The account isn't a wallet and there are wallet operation's limits which "
+#~ "may trigger actions that are not required: %1$s"
+#~ msgstr ""
+#~ "La cuenta no es una cartera y existen límites de operaciones de cartera "
+#~ "que pueden activar acciones que no son necesarias: %1$s"
+
+#~ msgid ""
+#~ "The account is a wallet and there are wallet operation's limits which are "
+#~ "not limited: %1$s"
+#~ msgstr ""
+#~ "La cuenta es una cartera y existen límites de operaciones de cartera que "
+#~ "no están limitados: %1$s"
+
+#~ msgid "New rules"
+#~ msgstr "Nuevas reglas"
+
+#~ msgid "Set rules to default"
+#~ msgstr "Establecer reglas predeterminadas"
+
+#~ msgid "Behavior on rule expiration"
+#~ msgstr "Comportamiento al vencer la regla"
+
+#~ msgid ""
+#~ "Events based on properties and new attributes that should be triggered"
+#~ msgstr ""
+#~ "Eventos basados en propiedades y nuevos atributos que deben activarse"
+
+#~ msgid "Others"
+#~ msgstr "Otros"
+
+#~ msgid "Custom list"
+#~ msgstr "Lista personalizada"
+
+#~ msgid "Events without built-in support."
+#~ msgstr "Eventos sin soporte incorporado."
+
+#~ msgid "These measures will ask the customer for information."
+#~ msgstr "Estas medidas solicitarán información al cliente."
+
+#~ msgid ""
+#~ "Select a form to submit new information about the customer or continue to "
+#~ "the next step"
+#~ msgstr ""
+#~ "Selecciona un formulario para enviar nueva información sobre el cliente o "
+#~ "continúa al siguiente paso"
+
+#~ msgid "Form:"
+#~ msgstr "Formulario:"
+
+#~ msgid "Keep investigation?"
+#~ msgstr "¿Mantener investigación?"
+
+#~ msgid "Full name of the account holder"
+#~ msgstr "Nombre completo del titular de la cuenta"
+
+#~ msgid "Update"
+#~ msgstr "Actualizar"
+
+#~ msgid "Remove"
+#~ msgstr "Quitar"
+
+#~ msgid "Show complete form"
+#~ msgstr "Mostrar formulario completo"
+
+#~ msgid "Show as verification"
+#~ msgstr "Mostrar como verificación"
+
+#~ msgid "Only required when no check is specified"
+#~ msgstr "Solo se requiere cuando no se especifica ninguna verificación"
+
+#~ msgid "Without a check the program will run automatically"
+#~ msgstr "Sin una verificación, el programa se ejecutará automáticamente"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:775
-msgid "Host"
-msgstr "Host"
+#~ msgid "It should be a number"
+#~ msgstr "Debe ser un número"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:776
-msgid "Exchange hostname"
-msgstr "Nombre de host del exchange"
+#~ msgid "It should be a safe integer"
+#~ msgstr "Debe ser un entero seguro"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:777
-msgid "exchange.taler.net"
-msgstr "exchange.taler.net"
+#~ msgid "Server measures"
+#~ msgstr "Medidas del servidor"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:782
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:829
-msgid "Remove last '/'"
-msgstr "Quitar el último '/'"
+#~ msgid "New measures"
+#~ msgstr "Nuevas medidas"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:784
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:801
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:332
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:376
-msgid "Invalid value"
-msgstr "Valor inválido"
+#~ msgid ""
+#~ "Measures that are available/executed directly after the decision is "
+#~ "confirmed."
+#~ msgstr ""
+#~ "Medidas disponibles/ejecutadas directamente después de confirmar la "
+#~ "decisión."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:792
-msgid "ID"
-msgstr "ID"
+#, fuzzy
+#~ msgid ""
+#~ "The session is disabled or a more recent decision was already submitted."
+#~ msgstr ""
+#~ "El oficial está deshabilitado o ya se envió una decisión más reciente."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:793
-msgid "Wallet reserve public key"
-msgstr "Clave pública de reserva de la cartera"
+#, fuzzy
+#~ msgid ""
+#~ "This decision declares that the MROS report has concluded. Please make "
+#~ "sure that this is the case"
+#~ msgstr ""
+#~ "Esta decisión declara que el informe MROS ha concluido. Asegúrate de que "
+#~ "este sea el caso"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:794
-msgid "abcdef1235"
-msgstr "abcdef1235"
+#~ msgid "I want to check first!"
+#~ msgstr "¡Quiero verificar primero!"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:799
-msgid "Should be 52 characters"
-msgstr "Debe tener 52 caracteres"
+#~ msgid ""
+#~ "Deadline should specify when this rules ends and what is the next "
+#~ "measures to apply after expiration."
+#~ msgstr ""
+#~ "El plazo debe especificar cuándo terminan estas reglas y cuáles son las "
+#~ "siguientes medidas a aplicar tras el vencimiento."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:814
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:268
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:338
-msgid "Account"
-msgstr "Cuenta"
+#~ msgid "Can't make a decision without rules."
+#~ msgstr "No se puede tomar una decisión sin reglas."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:815
-msgid "Bank account identification"
-msgstr "Identificación de la cuenta bancaria"
+#~ msgid "Missing active measure"
+#~ msgstr "Falta la medida activa"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:816
-msgid "DE123123123"
-msgstr "DE123123123"
+#~ msgid "You should specify in the measure section."
+#~ msgstr "Debes especificarlo en la sección de medidas."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:822
-msgid "Hostname"
-msgstr "Nombre de host"
+#~ msgid "You should specify in the properties section."
+#~ msgstr "Debes especificarlo en la sección de propiedades."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:823
-msgid "Without the scheme, may include subpath: bank.com, bank.com/path/"
-msgstr "Sin el esquema, puede incluir subruta: bank.com, bank.com/path/"
+#~ msgid "You should specify in the events section."
+#~ msgstr "Debes especificarlo en la sección de eventos."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:824
-msgid "bank.demo.taler.net"
-msgstr "bank.demo.taler.net"
+#~ msgid "Missing justification"
+#~ msgstr "Falta la justificación"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:831
-msgid "Invalid hostname"
-msgstr "Nombre de host inválido"
+#~ msgid ""
+#~ "You should check form errors or submit a decision without attributes."
+#~ msgstr ""
+#~ "Debes revisar los errores del formulario o enviar una decisión sin "
+#~ "atributos."
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:71
-msgid "Failed to load the account information."
-msgstr ""
+#~ msgid "Clear"
+#~ msgstr "Limpiar"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:198
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:204
-msgid "Different form version"
-msgstr "Versión de formulario diferente"
+#~ msgid "Attributes"
+#~ msgstr "Atributos"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:199
-msgid "The collected information don't have the form version used."
-msgstr "La información recopilada no tiene la versión de formulario utilizada."
+#~ msgid "Add more information about the customer"
+#~ msgstr "Añadir más información sobre el cliente"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:205
-msgid ""
-"The collected information used the form version \"%1$s \" but is not "
-"available."
-msgstr ""
-"La información recopilada usó la versión de formulario \"%1$s \", pero no "
-"está disponible."
+#~ msgid "Rules"
+#~ msgstr "Reglas"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:217
-msgid "Case details"
-msgstr "Detalles del caso"
+#~ msgid "Set the limit of the operations"
+#~ msgstr "Establecer el límite de las operaciones"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:231
-msgid "Next event"
-msgstr "Próximo evento"
+#~ msgid "Trigger notifications."
+#~ msgstr "Activar notificaciones."
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:245
-msgid "Previous event"
-msgstr "Evento anterior"
+#~ msgid "Ask the customer to take action."
+#~ msgstr "Pedir al cliente que tome una acción."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:66
-msgid "Direction"
-msgstr "Dirección"
+#~ msgid "Flag the current account state."
+#~ msgstr "Marcar el estado actual de la cuenta."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:69
-msgid "Credit"
-msgstr "Crédito"
+#~ msgid "loading..."
+#~ msgstr "cargando..."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:73
-msgid "Debit"
-msgstr "Débito"
+#~ msgid "Decision for wallet:"
+#~ msgstr "Decisión para la cartera:"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:77
-msgid "KYC Auth"
-msgstr "Autenticación KYC"
+#~ msgid "Check account details"
+#~ msgstr "Verificar detalles de la cuenta"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:85
-msgid "Minimum amount"
-msgstr "Monto mínimo"
+#~ msgid "Account most recent decisions"
+#~ msgstr "Decisiones más recientes de la cuenta"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:86
-msgid "All amounts below the given threshold will be filtered."
-msgstr "Se filtrarán todos los montos por debajo del umbral indicado."
+#~ msgid "When"
+#~ msgstr "Cuándo"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:114
-#, fuzzy
-msgid "Failed to load transfer list."
-msgstr "No se pudo interpretar: %1$s"
+#~ msgid "LATEST"
+#~ msgstr "MÁS RECIENTE"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:123
-msgid "Failed to load the transfer list."
-msgstr ""
+#~ msgid "ACTIVE"
+#~ msgstr "ACTIVA"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:160
-msgid "Select transaction type"
-msgstr "Selecciona el tipo de transacción"
+#~ msgid "Requires investigation"
+#~ msgstr "Requiere investigación"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:161
-msgid "Please select a transaction type to show transactions."
-msgstr "Selecciona un tipo de transacción para mostrar las transacciones."
+#~ msgid "The collected information don't have the form version used."
+#~ msgstr ""
+#~ "La información recopilada no tiene la versión de formulario utilizada."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:176
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:234
-msgid "Transfers history for account"
-msgstr "Historial de transferencias de la cuenta"
+#~ msgid ""
+#~ "The collected information used the form version \"%1$s \" but is not "
+#~ "available."
+#~ msgstr ""
+#~ "La información recopilada usó la versión de formulario \"%1$s \", pero no "
+#~ "está disponible."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:188
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:246
-msgid "Transfers history"
-msgstr "Historial de transferencias"
+#~ msgid "Case details"
+#~ msgstr "Detalles del caso"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:195
-msgid "No transfers yet."
-msgstr "Aún no hay transferencias."
+#~ msgid "Previous event"
+#~ msgstr "Evento anterior"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:197
-msgid "There are no transfers for this account."
-msgstr "No hay transferencias para esta cuenta."
+#~ msgid "Direction"
+#~ msgstr "Dirección"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:201
-msgid ""
-"There are no transfers reported to the exchange with the current threshold."
-msgstr "No hay transferencias informadas al exchange con el umbral actual."
+#~ msgid "Debit"
+#~ msgstr "Débito"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:260
-msgid "Date"
-msgstr "Fecha"
+#~ msgid "KYC Auth"
+#~ msgstr "Autenticación KYC"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:264
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:310
-msgid "Amount"
-msgstr "Monto"
+#~ msgid "Previous AML decisions that are no longer active."
+#~ msgstr "Decisiones AML anteriores que ya no están activas."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:314
-msgid "sent"
-msgstr "enviado"
+#~ msgid "The account has no KYC information."
+#~ msgstr "La cuenta no tiene información KYC."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:315
-msgid "received"
-msgstr "recibido"
+#~ msgid "Download KYC report"
+#~ msgstr "Descargar informe KYC"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:348
-msgid "to"
-msgstr "a"
+#~ msgid "KYC report ready"
+#~ msgstr "Informe KYC listo"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:349
-msgid "from"
-msgstr "de"
+#~ msgid "Use testing dialect"
+#~ msgstr "Usar dialecto de prueba"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:92
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:101
-msgid "Welcome to the exchange configuration"
-msgstr "Bienvenido a la configuración del exchange"
+#~ msgid "Since"
+#~ msgstr "Desde"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:372
-msgid "Transfers"
-msgstr "Transferencias"
+#~ msgid "Already completed."
+#~ msgstr "Ya completado."
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:379
-msgid "Profile"
-msgstr "Perfil"
+#~ msgid "Case history for selected account"
+#~ msgstr "Historial del caso para la cuenta seleccionada"
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:49
-#, fuzzy
-msgid "Failed to load server measures."
-msgstr "Medidas del servidor"
+#~ msgid "ID:"
+#~ msgstr "ID:"
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:61
-#, fuzzy
-msgid "Failed to load the measures"
-msgstr "Medidas activas actuales"
+#~ msgid "Payto:"
+#~ msgstr "Payto:"
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:105
-#, fuzzy
-msgid "A list of all the predefined measures you can use."
-msgstr "Una lista de todas las medidas predefinidas disponibles para usar."
+#~ msgid "Export as PDF"
+#~ msgstr "Exportar como PDF"
-#. screenid: 122
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:165
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:174
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:214
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:222
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:90
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:99
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:62
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:71
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:191
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:200
-msgid "Failed to load available measures."
-msgstr "No se pudieron cargar las medidas disponibles."
+#~ msgid "Click here to save the file in your computer."
+#~ msgstr "Haz clic aquí para guardar el archivo en tu computadora."
-#. screenid: 122
-#. screenid: 102
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:179
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:104
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:76
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:205
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:403
-msgid "The officer session is invalid."
-msgstr "La sesión del responsable de AML no es válida."
+#~ msgid "Every attribute collection event (via form upload or KYC provider)."
+#~ msgstr ""
+#~ "Cada evento de recopilación de atributos (mediante carga de formulario o "
+#~ "proveedor KYC)."
-#. screenid: 122
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:183
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:80
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:209
-msgid "The measures endpoint was not found."
-msgstr "No se encontró el punto de acceso de las medidas."
+#~ msgid ""
+#~ "There is no decision for this account yet. The account is limited by the "
+#~ "default rules."
+#~ msgstr ""
+#~ "Aún no hay ninguna decisión para esta cuenta. La cuenta está limitada por "
+#~ "las reglas predeterminadas."
-#. screenid: 122
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:189
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:114
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:86
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:215
-msgid "The officer session is disabled."
-msgstr "La sesión del responsable de AML está deshabilitada."
+#~ msgid "No AML history found"
+#~ msgstr "No se encontró historial de AML"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:182
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:190
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:389
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:398
-msgid "Failed to load the active AML decision."
-msgstr "No se pudo cargar la decisión AML activa."
+#~ msgid "Current active measures"
+#~ msgstr "Medidas activas actuales"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:488
-msgid "The officer session signature is invalid."
-msgstr "La firma de la sesión del responsable de AML no es válida."
+#, fuzzy
+#~ msgid "There are no accounts in the resultset."
+#~ msgstr "Aún no hay reglas para esta cuenta."
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:491
-msgid "The requested AML account or session was not found."
-msgstr "No se encontró la cuenta AML o la sesión solicitada."
+#, fuzzy
+#~ msgid "Failed to load the accounts"
+#~ msgstr "Historial del caso para la cuenta seleccionada"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:495
-msgid "The officer session is disabled or the account state changed."
-msgstr ""
-"La sesión del responsable de AML está deshabilitada o cambió el estado de la "
-"cuenta."
+#~ msgid "High risk accounts. Only with custom rules."
+#~ msgstr "Cuentas de alto riesgo. Solo con reglas personalizadas."
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:192
-msgid "Invalid expiration"
-msgstr "Caducidad no válida"
+#~ msgid "Account with custom rules."
+#~ msgstr "Cuenta con reglas personalizadas."
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:193
-msgid "Attributes require an expiration date in the future."
-msgstr "Los atributos requieren una fecha de caducidad futura."
+#~ msgid "High risk accounts under investigation. Only with custom rules."
+#~ msgstr ""
+#~ "Cuentas de alto riesgo bajo investigación. Solo con reglas personalizadas."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:288
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:273
-msgid "Too many SKIP measures"
-msgstr "Demasiadas medidas SKIP"
+#~ msgid "Accounts under investigation. Only with custom rules."
+#~ msgstr "Cuentas bajo investigación. Solo con reglas personalizadas."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:289
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:274
-msgid "At most one immediate measure may use the SKIP check."
-msgstr "Como máximo una medida inmediata puede usar la comprobación SKIP."
+#~ msgid "High risk accounts under investigation."
+#~ msgstr "Cuentas de alto riesgo bajo investigación."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:491
-msgid "Require all measures"
-msgstr "Exigir todas las medidas"
+#~ msgid "Accounts under investigation."
+#~ msgstr "Cuentas bajo investigación."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:492
-msgid ""
-"Run all selected measures together instead of accepting any one of them."
-msgstr ""
-"Ejecutar juntas todas las medidas seleccionadas en lugar de aceptar "
-"cualquiera de ellas."
+#~ msgid "High risk accounts without investigation. Only with custom rules."
+#~ msgstr ""
+#~ "Cuentas de alto riesgo sin investigación. Solo con reglas personalizadas."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:172
-msgid "Invalid custom properties"
-msgstr "Propiedades personalizadas no válidas"
+#~ msgid "Accounts without investigation. Only with custom rules."
+#~ msgstr "Cuentas sin investigación. Solo con reglas personalizadas."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:173
-msgid ""
-"Custom property names and values must be non-empty and names must be unique "
-"and different from built-in properties."
-msgstr ""
-"Los nombres y valores de las propiedades personalizadas no pueden estar "
-"vacíos; los nombres deben ser únicos y diferentes de las propiedades "
-"integradas."
+#~ msgid "High risk accounts without investigation."
+#~ msgstr "Cuentas de alto riesgo sin investigación."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:265
-msgid "Unknown measure"
-msgstr "Medida desconocida"
+#~ msgid "Accounts without investigation."
+#~ msgstr "Cuentas sin investigación."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:266
-msgid ""
-"A rule or immediate action references a measure that is not available. "
-"Review the rules and measures before submitting."
-msgstr ""
-"Una regla o acción inmediata hace referencia a una medida que no está "
-"disponible. Revise las reglas y las medidas antes de enviar."
+#~ msgid "No results"
+#~ msgstr "Sin resultados"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:274
-msgid "Requires investigation"
-msgstr "Requiere investigación"
+#~ msgid "#"
+#~ msgstr "#"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:106
-msgid "Collection event not found"
-msgstr "No se encontró el evento de recopilación"
+#~ msgid "Account Identification"
+#~ msgstr "Identificación de la cuenta"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:107
-msgid "There is no collection event with ID %1$s for this account."
-msgstr "No hay ningún evento de recopilación con el ID %1$s para esta cuenta."
+#~ msgid "From %1$s %2$s To %3$s"
+#~ msgstr "Desde %1$s %2$s Hasta %3$s"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:116
-msgid "Attributes unavailable"
-msgstr "Atributos no disponibles"
+#~ msgid "With custom rules"
+#~ msgstr "Con reglas personalizadas"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:117
-msgid "The collection event does not contain readable attributes."
-msgstr "El evento de recopilación no contiene atributos legibles."
+#~ msgid "Search by ID"
+#~ msgstr "Buscar por ID"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:131
-msgid "Form identifier missing"
-msgstr "Falta el identificador del formulario"
+#~ msgid "Under investigation: "
+#~ msgstr "Bajo investigación: "
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:132
-msgid "The collected information does not identify the form used to create it."
-msgstr ""
-"La información recopilada no identifica el formulario utilizado para crearla."
+#~ msgid "High risk:"
+#~ msgstr "Alto riesgo:"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:144
-msgid "Form not available"
-msgstr "Formulario no disponible"
+#~ msgid "Case queue"
+#~ msgstr "Cola de casos"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:145
-msgid "Form %1$s is not configured in this AML Web UI."
-msgstr "El formulario %1$s no está configurado en esta interfaz web de AML."
+#~ msgid "Access"
+#~ msgstr "Acceso"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:407
-msgid "The account was not found."
-msgstr "No se encontró la cuenta."
+#~ msgid "Unlocked until"
+#~ msgstr "Desbloqueada hasta"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:411
-msgid "The account state changed. Reload it and try again."
-msgstr ""
-"El estado de la cuenta ha cambiado. Vuelva a cargarla e inténtelo de nuevo."
+#~ msgid "Confirm forgetting this session"
+#~ msgstr "Confirmar que se olvide esta sesión"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:436
-msgid ""
-"The payto URI does not belong to this account. Return to the account search "
-"and start the decision again."
-msgstr ""
-"El URI payto no pertenece a esta cuenta. Vuelva a la búsqueda de cuentas e "
-"inicie de nuevo la decisión."
+#, fuzzy
+#~ msgid "Request session activation"
+#~ msgstr "Solicitar activación de cuenta"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:448
-msgid ""
-"This account has no active decision and its payto URI is unknown. Start the "
-"decision from the account search so the account type can be determined "
-"safely."
-msgstr ""
-"Esta cuenta no tiene una decisión activa y se desconoce su URI payto. Inicie "
-"la decisión desde la búsqueda de cuentas para poder determinar de forma "
-"segura el tipo de cuenta."
+#~ msgid "Prev"
+#~ msgstr "Anterior"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:458
-msgid "Return to account"
-msgstr "Volver a la cuenta"
+#~ msgid "Next"
+#~ msgstr "Siguiente"
+
+#~ msgid ""
+#~ "This account has no active decision and its payto URI is unknown. Start "
+#~ "the decision from the account search so the account type can be "
+#~ "determined safely."
+#~ msgstr ""
+#~ "Esta cuenta no tiene una decisión activa y se desconoce su URI payto. "
+#~ "Inicie la decisión desde la búsqueda de cuentas para poder determinar de "
+#~ "forma segura el tipo de cuenta."
#, c-format
#~ msgid "Internal error, please report."
@@ -2389,10 +5239,6 @@ msgstr "Volver a la cuenta"
#~ "incorrecta."
#, c-format
-#~ msgid "Lock account"
-#~ msgstr "Bloquear cuenta"
-
-#, c-format
#~ msgid "Operation denied"
#~ msgstr "Operación denegada"
@@ -2609,10 +5455,6 @@ msgstr "Volver a la cuenta"
#~ "iniciará sesión."
#, c-format
-#~ msgid "Account information could not be retrieved."
-#~ msgstr "La información de la cuenta no pudo ser accedida."
-
-#, c-format
#~ msgid "Welcome, %1$s !"
#~ msgstr "Bienvenido/a, %1$s!"
@@ -2645,14 +5487,6 @@ msgstr "Volver a la cuenta"
#~ msgstr "Nuevo registro dió una respuesta errónea"
#, c-format
-#~ msgid "Bank menu"
-#~ msgstr "Menu del banco"
-
-#, c-format
-#~ msgid "Select option2"
-#~ msgstr "Seleccione opción 2"
-
-#, c-format
#~ msgid "days"
#~ msgstr "días"
diff --git a/packages/taler-exchange-aml-webui/src/i18n/fr.po b/packages/taler-exchange-aml-webui/src/i18n/fr.po
@@ -1,3 +1,4 @@
+#
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: taler@gnu.org\n"
@@ -5,2396 +6,5239 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
#. screenid: 118
-#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:103
-msgid "Use testing dialect"
-msgstr "Utiliser le dialecte de test"
-
-#. screenid: 118
-#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:105
+#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:114
msgid "Allow Insecure password"
msgstr "Autoriser un mot de passe non sécurisé"
#. screenid: 118
-#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:107
+#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:116
msgid "Keep session after reload"
msgstr "Conserver la session après rechargement"
#. screenid: 118
-#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:109
+#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:118
msgid "Don't compress request"
msgstr "Ne pas compresser la requête"
#. screenid: 101
-#: packages/taler-exchange-aml-webui/src/ExchangeAmlFrame.tsx:75
-msgid "Preferences"
-msgstr "Préférences"
+#: packages/taler-exchange-aml-webui/src/ExchangeAmlFrame.tsx:85
+msgid "Lock session"
+msgstr "Verrouiller la session"
#. screenid: 101
-#: packages/taler-exchange-aml-webui/src/ExchangeAmlFrame.tsx:120
-#, fuzzy
-msgid "Show debug information"
-msgstr "Afficher les informations de débogage"
+#: packages/taler-exchange-aml-webui/src/ExchangeAmlFrame.tsx:90
+msgid "Lock"
+msgstr "Verrouiller"
#. screenid: 125
#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:46
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:45
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:94
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:47
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:47
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:115
msgid "Password"
msgstr "Mot de passe"
#. screenid: 125
#. screenid: 122
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:50
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:71
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:555
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:996
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:749
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:780
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:797
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:827
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:841
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:51
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:72
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:629
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1108
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:794
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:825
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:842
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:872
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:886
msgid "Required"
msgstr "Requis"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:54
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:55
msgid "should have at least 12 characters"
msgstr "doit comporter au moins 12 caractères"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:56
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:57
msgid "should have lowercase and uppercase characters"
msgstr "doit comporter des minuscules et des majuscules"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:58
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:59
msgid "should have numbers"
msgstr "doit comporter des chiffres"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:60
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:61
msgid "should have at least one character which is not a number or letter"
msgstr ""
"doit comporter au moins un caractère qui n'est ni un chiffre ni une lettre"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:67
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:68
msgid "Repeat password"
msgstr "Répéter le mot de passe"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:73
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:74
msgid "doesn't match"
msgstr "ne correspond pas"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:105
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:112
#, fuzzy
msgid "Create session"
msgstr "Créer un compte"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:117
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:139
msgid "Create"
msgstr "Créer"
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:66
-msgid "Failed to unlock the session."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountBadges.tsx:28
+msgid "Wallet account"
+msgstr "Compte de portefeuille"
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:69
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:243
-msgid "Authorization denied for this session. Contact the administrator."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountBadges.tsx:28
+msgid "Bank account"
+msgstr "Compte bancaire"
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:80
-#, fuzzy
-msgid "Session locked"
-msgstr "Compte verrouillé"
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/components/AccountBadges.tsx:40
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:93
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:245
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:296
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:100
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:130
+msgid "Under investigation"
+msgstr "Sous enquête"
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:83
-#, fuzzy
-msgid ""
-"Your session is normally locked anytime you reload. To unlock type your "
-"password again."
-msgstr ""
-"Votre compte est normalement verrouillé à chaque rechargement. Pour le "
-"déverrouiller, saisissez à nouveau votre mot de passe."
+#: packages/taler-exchange-aml-webui/src/components/AccountBadges.tsx:89
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:101
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:254
+msgid "High risk"
+msgstr "Risque élevé"
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:108
-msgid "Unlock"
-msgstr "Déverrouiller"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:51
+msgid "Payment target type"
+msgstr ""
-#. screenid: 119
-#. screenid: 112
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:116
-#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:81
-#, fuzzy
-msgid "Forget session"
-msgstr "Oublier le compte"
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:81
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:199
+msgid "Account holder"
+msgstr "Titulaire du compte"
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:55
-msgid "There are no rules for operations"
-msgstr "Il n'y a aucune règle pour les opérations"
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:107
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:110
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:571
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:806
+msgid "IBAN"
+msgstr "IBAN"
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:58
-#, fuzzy
-msgid "This means that no operation has any limit."
-msgstr "Cela signifie que toutes les opérations n'ont aucune limite."
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:109
+msgid "BIC"
+msgstr ""
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:69
-msgid "Add custom rule"
-msgstr "Ajouter une règle personnalisée"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:114
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:119
+msgid "Bank"
+msgstr ""
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:94
-msgid "Operation"
-msgstr "Opération"
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:115
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:120
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:154
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:160
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:295
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:859
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:364
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:435
+msgid "Account"
+msgstr "Compte"
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:100
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:625
-msgid "Threshold"
-msgstr "Seuil"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:116
+msgid "Taler bank"
+msgstr "Banque Taler"
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:106
-msgid "Escalation"
-msgstr "Escalade"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:121
+msgid "Cyclos"
+msgstr ""
-#. screenid: 121
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:120
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:243
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:800
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:844
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:902
-msgid "%1$s"
-msgstr "%1$s"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:124
+msgid "Bitcoin address"
+msgstr ""
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:195
-msgctxt "threshold"
-msgid "%1$s every %2$s"
-msgstr "%1$s tous les %2$s"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:129
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:144
+msgid "Reserve public key"
+msgstr ""
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:213
-msgid "(all)"
-msgstr "(tous)"
-
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:59
-#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:69
-msgid "Since"
-msgstr "Depuis"
-
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:70
-msgid "Expired"
-msgstr "Expiré"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:133
+msgid "Bitcoin"
+msgstr ""
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:72
-msgid "Expires"
-msgstr "Expire"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:136
+msgid "Ethereum address"
+msgstr ""
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:82
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:724
-msgid "Successor measure"
-msgstr "Mesure suivante"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:139
+msgid "Ethereum"
+msgstr ""
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:140
-msgid "AML officer justification"
-msgstr "Justification de l'agent AML"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:142
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:70
+msgid "Exchange"
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/components/ShowDefaultRules.tsx:11
-msgid "Default rules"
-msgstr "Règles par défaut"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:149
+msgid "Taler reserve"
+msgstr "Réserve Taler"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:42
-msgid "Forms"
-msgstr "Formulaires"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:150
+msgid "Taler reserve (HTTP)"
+msgstr ""
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:45
-#, fuzzy
-msgid "Measures used to gather information about the customer."
-msgstr "Mesures utilisées pour recueillir des informations sur le client."
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:157
+msgid "Test account"
+msgstr "Compte de test"
-#. screenid: 123
-#. screenid: 108
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:69
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:162
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:248
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:153
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:552
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:992
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:192
-msgid "Name"
-msgstr "Nom"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:180
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:225
+msgid "Account details unavailable"
+msgstr ""
-#. screenid: 123
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:76
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:169
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:584
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:837
-msgid "Check"
-msgstr "Vérifier"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:54
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:96
+msgid "Not opened"
+msgstr "Non ouvert"
-#. screenid: 123
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:82
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:255
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:564
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:791
-msgid "Program"
-msgstr "Programme"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:59
+msgid "Opened:"
+msgstr "Ouvert :"
-#. screenid: 123
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:88
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:175
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:267
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:607
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:805
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:893
-msgid "Context"
-msgstr "Contexte"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:68
+msgid "Closed:"
+msgstr "Fermé :"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:102
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:189
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:281
-msgid "Modify"
-msgstr "Modifier"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:94
+msgid "Closed"
+msgstr "Fermé"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:135
-msgid "Info"
-msgstr "Info"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:95
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:263
+msgid "Open"
+msgstr "Ouvert"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:138
-msgid "Will show information to the user."
-msgstr "Affichera des informations à l'utilisateur."
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:125
+msgid "No note"
+msgstr "Aucune note"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:221
-msgid "Instant measures"
-msgstr "Mesures instantanées"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:136
+msgid "Show full note"
+msgstr "Afficher la note complète"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:224
-msgid "Triggered immediately without customer interaction."
-msgstr "Déclenchées immédiatement sans interaction du client."
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:146
+msgid "System information"
+msgstr "Information système"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:261
-msgid "Input requirement"
-msgstr "Exigence de saisie"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:149
+msgid "Transactions remain below the threshold that opens an AML file."
+msgstr "Les transactions restent sous le seuil d’ouverture d’un dossier AML."
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:78
-msgid "Already completed."
-msgstr "Déjà complété."
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:122
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:202
+msgid "Account case"
+msgstr "Dossier du compte"
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:80
-msgid "Waiting to be completed."
-msgstr "En attente d'être complété."
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:149
+msgid "Failed to download AML file."
+msgstr "Échec du téléchargement du dossier AML."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:183
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:365
-msgid "Current active rules"
-msgstr "Règles actives actuelles"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:152
+msgid "No AML file is available for this account."
+msgstr "Aucun dossier AML n’est disponible pour ce compte."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:188
-msgid "There are no rules for this account yet."
-msgstr "Il n'y a pas encore de règles pour ce compte."
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:154
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:72
+msgid "Authorization denied for this session. Contact the administrator."
+msgstr "Autorisation refusée pour cette session. Contactez l’administrateur."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:238
-msgid "New rule form"
-msgstr "Nouveau formulaire de règle"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:156
+msgid "The account or session was not found."
+msgstr "Le compte ou la session est introuvable."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:250
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:230
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:412
-msgid "Add"
-msgstr "Ajouter"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:158
+msgid "The session is disabled. Contact the administrator."
+msgstr "La session est désactivée. Contactez l’administrateur."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:258
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:221
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:403
-msgid "Cancel"
-msgstr "Annuler"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:160
+msgid "The exchange does not support PDF reports."
+msgstr "L’Exchange ne prend pas en charge les rapports PDF."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:356
-msgid "Basic plan"
-msgstr "Forfait de base"
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:175
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:354
+msgid "Read-only officers cannot create AML decisions."
+msgstr "Les agents en lecture seule ne peuvent pas créer de décisions AML."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:367
-msgid "Premium"
-msgstr "Premium"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:177
+msgid "A payto URI is required to create a new decision."
+msgstr "Une URI payto est nécessaire pour créer une nouvelle décision."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:378
-msgid "E-commerce"
-msgstr "Commerce électronique"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:194
+msgid "Back to accounts"
+msgstr "Retour aux comptes"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:389
-msgid "Point of Sale"
-msgstr "Point de vente"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:224
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:505
+msgid "File no. %1$s"
+msgstr "Dossier nº %1$s"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:408
-msgid "Check rules"
-msgstr "Vérifier les règles"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:253
+msgid "New decision"
+msgstr "Nouvelle décision"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:428
-msgid ""
-"The account is a wallet and there are bank account operation's limits which "
-"may trigger actions that are not required: %1$s"
-msgstr ""
-"Le compte est un portefeuille numérique et il existe des limites "
-"d'opérations de compte bancaire susceptibles de déclencher des actions non "
-"requises : %1$s"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:265
+msgid "Download AML file (PDF)"
+msgstr "Télécharger le dossier AML (PDF)"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:437
-msgid ""
-"The account isn't a wallet and there are wallet operation's limits which may "
-"trigger actions that are not required: %1$s"
-msgstr ""
-"Le compte n'est pas un portefeuille numérique et il existe des limites "
-"d'opérations de portefeuille susceptibles de déclencher des actions non "
-"requises : %1$s"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:278
+msgid "AML file download started."
+msgstr "Le téléchargement du dossier AML a commencé."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:446
-msgid ""
-"The account is a wallet and there are wallet operation's limits which are "
-"not limited: %1$s"
-msgstr ""
-"Le compte est un portefeuille numérique et il existe des limites "
-"d'opérations de portefeuille qui ne sont pas limitées : %1$s"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:284
+#, fuzzy
+#| msgid "Account open"
+msgid "Account notes"
+msgstr "Compte ouvert"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:454
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:293
#, fuzzy
-msgid ""
-"The AML account is a bank account, but not all account-related operations "
-"are limited ( %1$s)."
+#| msgid "Account assessment could not be loaded"
+msgid "Current account status and notes could not be loaded."
+msgstr "Impossible de charger l’évaluation du compte"
+
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:302
+msgid "Try again"
msgstr ""
-"Le compte AML est un compte bancaire, mais toutes les opérations liées au "
-"compte ne sont pas limitées (%1$s)."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:482
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:269
-msgid "New rules"
-msgstr "Nouvelles règles"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:316
+msgid "Account identifiers"
+msgstr "Identifiants du compte"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:503
-msgid "Reset rules to current state"
-msgstr "Réinitialiser les règles à l'état actuel"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:325
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:509
+msgid "Technical identifiers"
+msgstr "Identifiants techniques"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:511
-msgid "Set rules to default"
-msgstr "Rétablir les règles par défaut"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:329
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:513
+msgid "Full payto URI"
+msgstr "URI payto complète"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:519
-msgid "Freeze account"
-msgstr "Geler le compte"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:331
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:144
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:155
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:173
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:190
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:390
+msgid "Unavailable"
+msgstr "Indisponible"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:535
-msgid "Behavior on rule expiration"
-msgstr "Comportement à l'expiration de la règle"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:332
+msgid "Copy payto URI"
+msgstr "Copier l’URI payto"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:546
-msgid "Reset measure"
-msgstr "Réinitialiser la mesure"
+#. screenid: 113
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:335
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:517
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:188
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:157
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:289
+msgid "Normalized payto hash"
+msgstr "Empreinte payto normalisée"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:558
-msgid "Reset expiration"
-msgstr "Réinitialiser l'expiration"
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:337
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:194
+msgid "Copy normalized payto hash"
+msgstr "Copier l’empreinte payto normalisée"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:583
-msgctxt "operation type"
-msgid "Withdraw"
-msgstr "Retrait"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:341
+#, fuzzy
+#| msgid "number"
+msgid "File number"
+msgstr "nombre"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:585
-msgctxt "operation type"
-msgid "Deposit"
-msgstr "Dépôt"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:343
+#, fuzzy
+#| msgid "Not a number"
+msgid "Copy file number"
+msgstr "Pas un nombre"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:587
-msgctxt "operation type"
-msgid "Merge"
-msgstr "Fusion"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:351
+msgid "Account case views"
+msgstr "Vues du dossier du compte"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:589
-msgctxt "operation type"
-msgid "Aggregate"
-msgstr "Agrégation"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:355
+msgid "Overview"
+msgstr "Vue d’ensemble"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:591
-msgctxt "operation type"
-msgid "Balance"
-msgstr "Solde"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:360
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:565
+msgid "Transfers"
+msgstr "Transferts"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:593
-msgctxt "operation type"
-msgid "Refund"
-msgstr "Remboursement"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:365
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:67
+msgid "Decision history"
+msgstr "Historique des décisions"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:595
-msgctxt "operation type"
+#: packages/taler-exchange-aml-webui/src/components/ConfirmationModal.tsx:73
msgid "Close"
msgstr "Fermer"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:597
-msgctxt "operation type"
-msgid "Transaction"
-msgstr "Transaction"
-
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:612
-msgid "Operation type"
-msgstr "Type d'opération"
-
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:633
-msgid "Timeframe"
-msgstr "Période"
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/ConfirmationModal.tsx:91
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:207
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:534
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:280
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:469
+msgid "Cancel"
+msgstr "Annuler"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:639
-msgid "Exposed"
-msgstr "Exposé"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:36
+msgid "AML officer enrollment request"
+msgstr "Demande d’enregistrement d’un agent AML"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:640
-msgid "Is this limit communicated to the customer?"
-msgstr "Cette limite est-elle communiquée au client ?"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:37
+msgid ""
+"Please enroll this AML officer public key:\n"
+"\n"
+"%1$s"
+msgstr ""
+"Veuillez enregistrer cette clé publique d’agent AML :\n"
+"\n"
+"%1$s"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:652
-msgid "Escalation measure"
-msgstr "Mesure d'escalade"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:59
+msgid "Officer key awaiting enrollment"
+msgstr "Clé de l’agent AML en attente d’enregistrement"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:653
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:62
msgid ""
-"Measures that the customer will need to satisfy to apply for a new threshold."
-msgstr "Mesures que le client devra satisfaire pour demander un nouveau seuil."
+"This browser has created an AML officer key, but the exchange has not "
+"granted it access. Ask the exchange operator or administrator to enroll the "
+"public key below."
+msgstr ""
+"Ce navigateur a créé une clé d’agent AML, mais l’exchange ne lui a pas "
+"accordé l’accès. Demandez à l’opérateur ou à l’administrateur de l’exchange "
+"d’enregistrer la clé publique ci-dessous."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:658
-msgid "All measures"
-msgstr "Toutes les mesures"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:70
+msgid "AML officer public key"
+msgstr "Clé publique de l’agent AML"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:659
-msgid "Hint the customer that all measures should be completed"
-msgstr "Indiquer au client que toutes les mesures doivent être complétées"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:76
+msgid "Copy AML officer public key"
+msgstr "Copier la clé publique de l’agent AML"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:672
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:157
-msgid "Expiration"
-msgstr "Expiration"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:82
+msgid "After the operator confirms enrollment, retry the access check."
+msgstr ""
+"Une fois l’enregistrement confirmé par l’opérateur, relancez la vérification "
+"de l’accès."
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:92
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:69
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:212
+msgid "Retry access check"
+msgstr "Vérifier à nouveau l’accès"
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:101
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:188
+msgid "Checking officer access"
+msgstr "Vérification de l’accès de l’agent AML"
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:104
+msgid "Last checked at %1$s"
+msgstr "Dernière vérification à %1$s"
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:114
+msgid "Request enrollment"
+msgstr "Demander l’enregistrement"
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:121
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:128
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:77
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:85
+msgid "Discard this key"
+msgstr "Supprimer cette clé"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:673
-msgid "Predefined shortcuts"
-msgstr "Raccourcis prédéfinis"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:127
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:84
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:250
+msgid "Confirmation required"
+msgstr "Confirmation requise"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:677
-msgid "In a week"
-msgstr "Dans une semaine"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:135
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:92
+msgid ""
+"Discarding this key removes the officer session from this browser. You will "
+"need to create a new key to use the AML WebUI again."
+msgstr ""
+"La suppression de cette clé retire la session de l’agent de ce navigateur. "
+"Vous devrez créer une nouvelle clé pour utiliser à nouveau l’interface web "
+"AML."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:685
-msgid "In a month"
-msgstr "Dans un mois"
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:41
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:205
+msgid "Failed to check AML officer access."
+msgstr "Échec de la vérification de l’accès de l’agent AML."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:693
-msgid "In a year"
-msgstr "Dans un an"
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:45
+msgid ""
+"This officer key cannot authenticate with the exchange. Retry the check or "
+"discard the key and create a new session."
+msgstr ""
+"Cette clé d’agent ne permet pas de s’authentifier auprès de l’exchange. "
+"Réessayez la vérification ou supprimez la clé et créez une nouvelle session."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:701
-msgid "Never"
-msgstr "Jamais"
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:50
+msgid "The exchange rejected the officer access check."
+msgstr "L’exchange a refusé la vérification de l’accès de l’agent."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:712
-msgid "Expiration date"
-msgstr "Date d'expiration"
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:57
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:211
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:522
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:101
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:612
+msgid "Technical details"
+msgstr "Détails techniques"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:713
-msgid "Until when are the new rules active."
-msgstr "Jusqu'à quand les nouvelles règles sont actives."
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:69
+msgid "Failed to unlock the session."
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:725
-msgid "Measure taken automatically upon expiration of the current decision."
-msgstr "Mesure prise automatiquement à l'expiration de la décision actuelle."
-
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:107
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:62
-msgid "Failed to load account information."
-msgstr ""
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:95
+#, fuzzy
+msgid "Session locked"
+msgstr "Compte verrouillé"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:125
-msgid "Failed to load decision history."
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:98
+#, fuzzy
+msgid ""
+"Your session is normally locked anytime you reload. To unlock type your "
+"password again."
msgstr ""
+"Votre compte est normalement verrouillé à chaque rechargement. Pour le "
+"déverrouiller, saisissez à nouveau votre mot de passe."
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:143
-msgid "Failed to load current legitimizations."
-msgstr ""
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:136
+msgid "Unlock"
+msgstr "Déverrouiller"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:188
-msgid "New decision"
-msgstr "Nouvelle décision"
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:144
+msgid "Forget session"
+msgstr "Supprimer la session"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:196
-msgid "Show transfers"
-msgstr "Afficher les transferts"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:162
+#, fuzzy
+#| msgid "No account properties"
+msgid "Review derived account properties"
+msgstr "Aucune propriété de compte"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:236
-msgid "Failed to download report."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:165
+msgid ""
+"Values may be derived from the selected AML/KYC form. Confirm them against "
+"the case record and change only values that require an officer override."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:241
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:187
#, fuzzy
-msgid "The account has no KYC info."
-msgstr "Le compte est introuvable"
+#| msgid "Reset to default"
+msgid "Reset to derived values"
+msgstr "Réinitialiser par défaut"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:245
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:183
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:195
-msgid "Session not found. Contact the administrator."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:192
+msgid "Invalid custom properties"
+msgstr "Propriétés personnalisées non valides"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:247
-msgid "The session is disabled. Contact the administrator."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:193
+msgid ""
+"Custom property names and values must be non-empty and names must be unique "
+"and different from built-in properties."
msgstr ""
+"Les noms et les valeurs des propriétés personnalisées ne doivent pas être "
+"vides ; les noms doivent être uniques et différents des propriétés intégrées."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:216
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:466
+msgid "Properties"
+msgstr "Propriétés"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:249
-msgid "The server doesn't support PDF download. Contact the administrator."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:217
+msgid "Built-in property names are preserved when the decision is submitted."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:260
-msgid "Case history for selected account"
-msgstr "Historique des dossiers pour le compte sélectionné"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:223
+msgid "Custom properties"
+msgstr "Propriétés personnalisées"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:224
+msgid "Add more properties that are not listed above."
+msgstr "Ajoutez d'autres propriétés qui ne sont pas listées ci-dessus."
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:265
-msgid "ID:"
-msgstr "ID :"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:229
+msgid "New properties"
+msgstr "Nouvelles propriétés"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:271
-msgid "Payto:"
-msgstr "Payto :"
+#. screenid: 123
+#. screenid: 108
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:234
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:73
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:171
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:261
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:204
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:626
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1104
+msgid "Name"
+msgstr "Nom"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:282
-msgid "Export as PDF"
-msgstr "Exporter en PDF"
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:240
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:720
+msgid "Value"
+msgstr "Valeur"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:298
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:279
-msgid "Export completed"
-msgstr "Exportation terminée"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:262
+msgid "Current note on the GwG file"
+msgstr "Note actuelle sur le dossier GwG"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:301
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:282
-msgid "Click here to save the file in your computer."
-msgstr "Cliquez ici pour enregistrer le fichier sur votre ordinateur."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:267
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:63
+msgid "Customer name or internal alias."
+msgstr "Nom du client ou alias interne."
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:310
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:411
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:208
-msgid "Under investigation"
-msgstr "Sous enquête"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:272
+msgid "Is the account active for deposit and payments?"
+msgstr "Le compte est-il actif pour les dépôts et les paiements ?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:311
-msgid ""
-"This account requires a manual review and is waiting for a decision to be "
-"made."
-msgstr "Ce compte nécessite un examen manuel et est en attente d'une décision."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:277
+msgid "Is the account idle?"
+msgstr "Le compte est-il inactif ?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:322
-msgid "Collected information"
-msgstr "Informations collectées"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:278
+msgid "No operation for a period of time"
+msgstr "Aucune opération pendant une période donnée"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:325
-msgid "Every attribute collection event (via form upload or KYC provider)."
-msgstr ""
-"Chaque événement de collecte d'attributs (via téléversement de formulaire ou "
-"prestataire KYC)."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:283
+msgid "Does account belong to a domestic PEP?"
+msgstr "Le compte appartient-il à une PPE nationale ?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:333
-msgid "No collected attributes for this account."
-msgstr "Aucun attribut collecté pour ce compte."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:288
+msgid "Does account belong to a foreign PEP?"
+msgstr "Le compte appartient-il à une PPE étrangère ?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:347
-msgid "Current account properties"
-msgstr "Propriétés actuelles du compte"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:293
+msgid "Does account belong to an international-organization PEP?"
+msgstr "Le compte appartient-il à une PPE d'organisation internationale ?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:354
-msgid "No active decision found"
-msgstr "Aucune décision active trouvée"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:298
+msgid "Does account belong to a high risk customer?"
+msgstr "Le compte appartient-il à un client à haut risque ?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:355
-msgid ""
-"There is no decision for this account yet. The account is limited by the "
-"default rules."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:303
+msgid "Does account belong to a person from a high risk country?"
msgstr ""
-"Aucune décision n'a encore été prise pour ce compte. Le compte est limité "
-"par les règles par défaut."
+"Le compte appartient-il à une personne originaire d'un pays à haut risque ?"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:308
+msgid "The MROS reporting state for the account."
+msgstr "L'état de déclaration MROS du compte."
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:384
-msgid "Previous AML decisions"
-msgstr "Décisions AML précédentes"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:313
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:307
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:175
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:199
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:497
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:630
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:653
+msgid "None"
+msgstr "Aucun"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:403
-msgid "No AML history found"
-msgstr "Aucun historique AML trouvé"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:317
+msgid "Pending investigation"
+msgstr "Enquête en attente"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:409
-msgid "Current active measures"
-msgstr "Mesures actives actuelles"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:321
+msgid "Investigated without suspicion"
+msgstr "Enquêté sans soupçon"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:537
-msgid "Now"
-msgstr "Maintenant"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:325
+msgid "Reported simple suspicion"
+msgstr "Soupçon simple signalé"
-#. screenid: 112
-#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:43
-#, fuzzy
-msgid "Session public key"
-msgstr "Clé publique"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:329
+msgid "Reported substantiated suspicion"
+msgstr "Soupçon fondé signalé"
-#. screenid: 112
-#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:59
-#, fuzzy
-msgid "Request session activation"
-msgstr "Demander l'activation du compte"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:336
+msgid "Informal reason why the AML investigation was triggered"
+msgstr "Raison informelle du déclenchement de l'enquête AML"
-#. screenid: 112
-#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:70
-msgid "Lock session"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:341
+msgid "Identifies the sanction list entry that the account matched against"
msgstr ""
+"Identifie l'entrée de la liste de sanctions à laquelle le compte correspond"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:73
-msgid "Failed to load accounts"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:343
+msgid "Best match, does not mean it was a good match."
msgstr ""
+"Meilleure correspondance, ne signifie pas que c'était une bonne "
+"correspondance."
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:83
-#, fuzzy
-msgid "Failed to load the accounts"
-msgstr "Historique des dossiers pour le compte sélectionné"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:347
+msgid "Score for how good the sanction list match was"
+msgstr "Score de la qualité de la correspondance avec la liste de sanctions"
-#. screenid: 111
-#. screenid: 110
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:88
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:168
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:76
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:128
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:66
-#, fuzzy
-msgid ""
-"This session signature is invalid, contact administrator or create a new one."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:349
+msgid "Integer score from 0 (no match) to 1,000,000,000 (best match)."
msgstr ""
-"La signature de ce compte est invalide, contactez l'administrateur ou créez-"
-"en une nouvelle."
-#. screenid: 111
-#. screenid: 110
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:95
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:175
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:83
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:135
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:73
-#, fuzzy
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:353
+msgid "Score for how much supporting data we had for the sanction list match"
+msgstr ""
+"Score de la quantité de données justificatives disponibles pour la "
+"correspondance avec la liste de sanctions"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:355
msgid ""
-"The designated AML session is not known, contact administrator or create a "
-"new one."
+"Integer score from 0 (no supporting data) to 1,000,000,000 (highest "
+"confidence)."
msgstr ""
-"Le compte AML désigné est inconnu, contactez l'administrateur ou créez-en un "
-"nouveau."
-#. screenid: 111
-#. screenid: 110
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:102
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:182
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:90
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:142
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:80
-#, fuzzy
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:359
msgid ""
-"The designated AML session is not enabled, contact administrator or create a "
-"new one."
+"Suppress flagging this account when it creates a hit on a sanctions list, "
+"this is a false-positive"
msgstr ""
-"Le compte AML désigné n'est pas activé, contactez l'administrateur ou créez-"
-"en un nouveau."
+"Supprimer le signalement de ce compte lorsqu'il correspond à une liste de "
+"sanctions ; il s'agit d'un faux positif"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:122
-msgid "High risk accounts. Only with custom rules."
-msgstr "Comptes à haut risque. Uniquement avec des règles personnalisées."
+#: packages/taler-exchange-aml-webui/src/components/DecisionProperties.tsx:46
+#, fuzzy
+#| msgid "No account properties"
+msgid "No account properties were recorded."
+msgstr "Aucune propriété de compte"
+
+#: packages/taler-exchange-aml-webui/src/components/DecisionProperties.tsx:91
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:317
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:509
+msgid "Yes"
+msgstr "Oui"
+
+#: packages/taler-exchange-aml-webui/src/components/DecisionProperties.tsx:91
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:317
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:509
+msgid "No"
+msgstr "Non"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:123
-msgid "Account with custom rules."
-msgstr "Compte avec des règles personnalisées."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:59
+msgid "There are no rules for operations"
+msgstr "Il n'y a aucune règle pour les opérations"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:125
-msgid "High risk accounts"
-msgstr "Comptes à haut risque"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:62
+msgid "This means that no operation has any limit."
+msgstr "Cela signifie qu’aucune opération n’est limitée."
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:126
-msgid "All known accounts."
-msgstr "Tous les comptes connus."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:90
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:312
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:500
+msgid "Operation"
+msgstr "Opération"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:130
-msgid "High risk accounts under investigation. Only with custom rules."
-msgstr ""
-"Comptes à haut risque sous enquête. Uniquement avec des règles "
-"personnalisées."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:96
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:695
+msgid "Threshold"
+msgstr "Seuil"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:131
-msgid "Accounts under investigation. Only with custom rules."
-msgstr "Comptes sous enquête. Uniquement avec des règles personnalisées."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:102
+msgid "Escalation"
+msgstr "Escalade"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:133
-msgid "High risk accounts under investigation."
-msgstr "Comptes à haut risque sous enquête."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:108
+msgid "Visibility"
+msgstr "Visibilité"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:134
-msgid "Accounts under investigation."
-msgstr "Comptes sous enquête."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:114
+msgid "Priority"
+msgstr "Priorité"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:137
-msgid "High risk accounts without investigation. Only with custom rules."
-msgstr ""
-"Comptes à haut risque sans enquête. Uniquement avec des règles "
-"personnalisées."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:121
+msgid "Actions"
+msgstr "Actions"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:138
-msgid "Accounts without investigation. Only with custom rules."
-msgstr "Comptes sans enquête. Uniquement avec des règles personnalisées."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:142
+msgctxt "threshold"
+msgid "%1$s every %2$s"
+msgstr "%1$s tous les %2$s"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:140
-msgid "High risk accounts without investigation."
-msgstr "Comptes à haut risque sans enquête."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:161
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:725
+msgid "Block operation"
+msgstr "Bloquer l’opération"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:141
-msgid "Accounts without investigation."
-msgstr "Comptes sans enquête."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:163
+msgid "All required:"
+msgstr "Toutes requises :"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:174
-msgid "Failed to download"
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:165
+msgid "Any one:"
+msgstr "Une au choix :"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:177
-#, fuzzy
-msgid "There are no accounts in the resultset."
-msgstr "Il n'y a pas encore de règles pour ce compte."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:182
+msgid "Customer-visible"
+msgstr "Visible par le client"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:179
-msgid "The format requested is not acceptable from the service provider."
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:184
+msgid "Internal"
+msgstr "Interne"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:181
-msgid "Authorization denied for this session."
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:197
+msgid "Move %1$s rule up"
+msgstr "Déplacer la règle %1$s vers le haut"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:185
-msgid "The session is disabled. Contact the administrator"
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:206
+msgid "Move %1$s rule down"
+msgstr "Déplacer la règle %1$s vers le bas"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:240
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:368
-msgid "Accounts"
-msgstr "Comptes"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:217
+msgid "Edit %1$s rule"
+msgstr "Modifier la règle %1$s"
+
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:240
+msgid "Remove %1$s rule"
+msgstr "Supprimer la règle %1$s"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:247
-msgid "Export as file"
-msgstr "Exporter sous forme de fichier"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:282
+msgctxt "operation type"
+msgid "Withdraw"
+msgstr "Retrait"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:318
-msgid "No results"
-msgstr "Aucun résultat"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:284
+msgctxt "operation type"
+msgid "Deposit"
+msgstr "Dépôt"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:329
-msgid "#"
-msgstr "#"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:286
+msgctxt "operation type"
+msgid "Merge"
+msgstr "Fusion"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:335
-msgid "Account Identification"
-msgstr "Identification du compte"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:288
+msgctxt "operation type"
+msgid "Aggregate"
+msgstr "Agrégation"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:341
-msgid "Open time"
-msgstr "Heure d'ouverture"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:290
+msgctxt "operation type"
+msgid "Balance"
+msgstr "Solde"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:347
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:243
-msgid "Status"
-msgstr "Statut"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:292
+msgctxt "operation type"
+msgid "Refund"
+msgstr "Remboursement"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:365
-msgid "From %1$s %2$s To %3$s"
-msgstr "De %1$s %2$s à %3$s"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:294
+msgctxt "operation type"
+msgid "Close"
+msgstr "Fermer"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:371
-msgid "Since %1$s"
-msgstr "Depuis %1$s"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:296
+msgctxt "operation type"
+msgid "Transaction"
+msgstr "Transaction"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:374
-msgid "Not opened"
-msgstr "Non ouvert"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:83
+#, fuzzy
+#| msgid "Decision date"
+msgid "Decision provenance"
+msgstr "Date de la décision"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:419
-msgid "High risk"
-msgstr "Haut risque"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:85
+#, fuzzy
+#| msgid "Decision date"
+msgid "Decision made by"
+msgstr "Date de la décision"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:427
-msgid "With custom rules"
-msgstr "Avec des règles personnalisées"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:88
+#, fuzzy
+#| msgid "AML officer public key"
+msgid "AML officer (name unavailable)"
+msgstr "Clé publique de l’agent AML"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:642
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:673
-msgid "Invalid account"
-msgstr "Compte invalide"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:89
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:369
+msgid "Automated outcome"
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:657
-msgid "Search by ID"
-msgstr "Rechercher par ID"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:91
+msgid "Resulting case disposition"
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:687
-msgid "Under investigation: "
-msgstr "Sous enquête : "
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:94
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:246
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:105
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:132
+msgid "Not under investigation"
+msgstr "Pas sous enquête"
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:99
+#, fuzzy
+#| msgid "Justification"
+msgid "Justification:"
+msgstr "Justification"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:696
-msgid "High risk:"
-msgstr "Haut risque :"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:101
+msgid "No justification was recorded."
+msgstr "Aucune justification n’a été enregistrée."
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:705
-msgid "Custom rules:"
-msgstr "Règles personnalisées :"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:112
+#, fuzzy
+#| msgid "System information"
+msgid "View submitted customer information"
+msgstr "Information système"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:47
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:366
-msgid "Dashboard"
-msgstr "Tableau de bord"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:120
+#, fuzzy
+#| msgid "Instant measures"
+msgid "Immediate measures requested"
+msgstr "Mesures instantanées"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:88
-msgid "Failed to load TOPS statistics."
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:123
+msgid "This decision did not request an immediate measure."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:99
-msgid "Statistics"
-msgstr "Statistiques"
-
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:187
-msgid "Accounts open"
-msgstr "Comptes ouverts"
-
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:190
-msgid "New files last year"
-msgstr "Nouveaux dossiers l'année dernière"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:131
+#, fuzzy
+#| msgid "All listed measures must be completed."
+msgid "All listed measures were requested (AND)."
+msgstr "Toutes les mesures indiquées doivent être accomplies."
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:193
-msgid "Closed files last year"
-msgstr "Dossiers fermés l'année dernière"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:132
+#, fuzzy
+#| msgid "Any one listed measure may be completed."
+msgid "Any listed measure may satisfy the request (OR)."
+msgstr "Une seule des mesures indiquées peut être accomplie."
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:196
-msgid "MROS substantiated"
-msgstr "MROS motivés"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:151
+msgid "Operation rules"
+msgstr "Règles d’opération"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:199
-msgid "MROS simple"
-msgstr "MROS simples"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:156
+msgid "No operation-specific rules were stored."
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:202
-msgid "High risk files"
-msgstr "Dossiers à haut risque"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:163
+#, fuzzy
+#| msgid "Select transaction type"
+msgid "Policy transition"
+msgstr "Sélectionner le type de transaction"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:205
-msgid "PEP files"
-msgstr "Dossiers PPE"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:165
+msgid "Policy expires"
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:267
-msgid "Number of accounts that are opened"
-msgstr "Nombre de comptes ouverts"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:173
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:796
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:362
+msgid "Successor measure"
+msgstr "Mesure suivante"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:270
-msgid "Number of new GwG files in the last year"
-msgstr "Nombre de nouveaux dossiers GwG au cours de la dernière année"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:174
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:479
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:163
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:365
+msgid "Exchange defaults"
+msgstr "Règles par défaut de l’Exchange"
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:179
+#, fuzzy
+#| msgid "Custom measures"
+msgid "Custom measure definitions"
+msgstr "Mesures personnalisées"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:273
-msgid "Number of GwG files closed in the last year"
-msgstr "Nombre de dossiers GwG fermés au cours de la dernière année"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:182
+#, fuzzy
+#| msgid "No active measure has been selected."
+msgid "No custom measures were stored."
+msgstr "Aucune mesure active n'a été sélectionnée."
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:276
-msgid "Number of MROS reports based on Art 9 Abs. 1 GwG (per year)"
-msgstr "Nombre de déclarations MROS fondées sur l'art. 9 al. 1 GwG (par an)"
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:202
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:278
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:128
+msgid "Account properties"
+msgstr "Propriétés du compte"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:279
-msgid "Number of MROS reports based on Art 305ter Abs. 2 StGB (per year)"
-msgstr ""
-"Nombre de déclarations MROS fondées sur l'art. 305ter al. 2 StGB (par an)"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:214
+#, fuzzy
+#| msgid "Decision date"
+msgid "Decision row"
+msgstr "Date de la décision"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:282
-msgid "Number of GwG files of high-risk customers"
-msgstr "Nombre de dossiers GwG de clients à haut risque"
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:217
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:174
+msgid "Officer public key"
+msgstr "Clé publique de l’agent"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:285
-msgid "Number of GwG files managed with “increased risk” due to PEP status"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:219
+msgid "Not applicable"
msgstr ""
-"Nombre de dossiers GwG gérés avec un « risque accru » en raison du statut de "
-"PPE"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:288
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:277
#, fuzzy
-msgid "Number of customers with open proceeding."
-msgstr "Nombre de comptes ouverts"
-
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:343
-msgid "previous"
-msgstr "précédent"
-
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:386
-msgid "Decreased by"
-msgstr "Diminué de"
+#| msgid "System information"
+msgid "Stored custom definition"
+msgstr "Information système"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:390
-msgid "Increased by"
-msgstr "Augmenté de"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:284
+msgid ""
+"Current measure metadata is still loading; the stored machine name is shown."
+msgstr ""
-#. screenid: 108
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:115
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:217
-msgid "Events"
-msgstr "Événements"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:286
+msgid ""
+"The current measure configuration could not be loaded; the stored machine "
+"name is shown."
+msgstr ""
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:116
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:287
msgid ""
-"The events will be triggered only after the decision has been confirmed."
+"No stored or currently configured definition is available for this reference."
msgstr ""
-"Les événements ne seront déclenchés qu'après la confirmation de la décision."
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:121
-msgid "Calculated"
-msgstr "Calculé"
+#. screenid: 123
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:291
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:80
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:178
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:659
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:938
+msgid "Check"
+msgstr "Vérifier"
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:122
-msgid "Events based on properties and new attributes that should be triggered"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:295
+msgid "Built-in check that requires no customer interaction."
msgstr ""
-"Événements basés sur des propriétés et de nouveaux attributs qui doivent "
-"être déclenchés"
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:134
-msgid "Others"
-msgstr "Autres"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:296
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:304
+#, fuzzy
+#| msgid "Attributes unavailable"
+msgid "Description unavailable"
+msgstr "Attributs indisponibles"
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:135
-msgid "Events that can be triggered manually"
-msgstr "Événements pouvant être déclenchés manuellement"
+#. screenid: 123
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:299
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:86
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:268
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:639
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:891
+msgid "Program"
+msgstr "Programme"
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:147
-msgid "Custom list"
-msgstr "Liste personnalisée"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:316
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:508
+msgid "Voluntary"
+msgstr ""
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:148
-msgid "Events without built-in support."
-msgstr "Événements sans prise en charge intégrée."
+#. screenid: 123
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:320
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:92
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:184
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:280
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:682
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:907
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:644
+msgid "Context"
+msgstr "Contexte"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:132
-msgid "Complete the form"
-msgstr "Compléter le formulaire"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:349
+msgid "Decision date"
+msgstr "Date de la décision"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:135
-msgid "These measures will ask the customer for information."
-msgstr "Ces mesures demanderont des informations au client."
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:357
+msgid "Expired"
+msgstr "Expiré"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:153
-msgid "change form"
-msgstr "modifier le formulaire"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:357
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:419
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:354
+msgid "Expires"
+msgstr "Expire"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:158
-msgid "Expiration date of the information filled in this form."
-msgstr "Date d'expiration des informations saisies dans ce formulaire."
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:362
+#, fuzzy
+#| msgid "Decision date"
+msgid "Decision status"
+msgstr "Date de la décision"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:217
-msgid "Include new information"
-msgstr "Inclure de nouvelles informations"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:363
+#, fuzzy
+#| msgid "Send decision"
+msgid "Current"
+msgstr "Envoyer la décision"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:218
-msgid ""
-"Select a form to submit new information about the customer or continue to "
-"the next step"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:363
+msgid "Historical"
msgstr ""
-"Sélectionnez un formulaire pour soumettre de nouvelles informations sur le "
-"client ou passez à l'étape suivante"
-
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:223
-msgid "Form:"
-msgstr "Formulaire :"
-#. screenid: 106
-#. screenid: 113
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:81
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:227
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:237
-msgid "Justification"
-msgstr "Justification"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:365
+msgid "Made by"
+msgstr ""
-#. screenid: 106
-#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:86
-msgid "Keep investigation?"
-msgstr "Conserver l'enquête ?"
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:368
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:272
+#, fuzzy
+#| msgid "AML officer public key"
+msgid "AML officer"
+msgstr "Clé publique de l’agent AML"
-#. screenid: 106
-#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:91
-msgid "Account holder"
-msgstr "Titulaire du compte"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:44
+msgid "Forms"
+msgstr "Formulaires"
-#. screenid: 106
-#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:93
-msgid "Full name of the account holder"
-msgstr "Nom complet du titulaire du compte"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:47
+msgid "Measures used to gather information about the customer."
+msgstr "Mesures utilisées pour recueillir des informations sur le client."
-#. screenid: 122
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:90
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:394
-msgid "loading..."
-msgstr "chargement..."
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:62
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:160
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:250
+msgid "Select"
+msgstr "Sélectionner"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:239
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:421
-msgid "Update"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:107
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:199
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:295
+msgid "Modify"
msgstr "Modifier"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:246
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:428
-msgid "Remove"
-msgstr "Supprimer"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:141
+#, fuzzy
+#| msgid "System information"
+msgid "Information"
+msgstr "Information système"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:473
-msgid "Configure verification type: %1$s"
-msgstr "Configurer le type de vérification : %1$s"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:144
+#, fuzzy
+#| msgid "KYC information filed by the customer or an AML officer."
+msgid "Shows information to the customer without running an AML program."
+msgstr "Informations KYC déposées par le client ou un agent AML."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:484
-msgid "Show complete form"
-msgstr "Afficher le formulaire complet"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:232
+msgid "Instant measures"
+msgstr "Mesures instantanées"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:505
-msgid "Configure measure"
-msgstr "Configurer la mesure"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:235
+msgid "Triggered immediately without customer interaction."
+msgstr "Déclenchées immédiatement sans interaction du client."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:515
-msgid "Show as verification"
-msgstr "Afficher comme vérification"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:274
+msgid "Input requirement"
+msgstr "Exigence de saisie"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:557
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:998
-msgid "There is already a measure with that name"
-msgstr "Il existe déjà une mesure portant ce nom"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:56
+msgid "Started"
+msgstr "Commencée"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:571
-msgid "Only required when no check is specified"
-msgstr "Requis uniquement lorsqu'aucune vérification n'est spécifiée"
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:64
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:301
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:140
+msgid "Status"
+msgstr "Statut"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:575
-msgid "Missing check or program"
-msgstr "Vérification ou programme manquant"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:76
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:447
+msgid "Forbidden"
+msgstr "Interdite"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:585
-msgid "Without a check the program will run automatically"
-msgstr "Sans vérification, le programme s'exécutera automatiquement"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:78
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:443
+msgid "Completed"
+msgstr "Terminée"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:614
-msgid "Field name"
-msgstr "Nom du champ"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:79
+msgid "Waiting for customer"
+msgstr "En attente du client"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:619
-msgid "Type"
-msgstr "Type"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:92
+msgid "The operation is categorically forbidden by this requirement."
+msgstr "Cette exigence interdit catégoriquement l’opération."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:623
-msgid "string"
-msgstr "chaîne"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:100
+msgid "All listed measures must be completed."
+msgstr "Toutes les mesures indiquées doivent être accomplies."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:627
-msgid "number"
-msgstr "nombre"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:104
+msgid "Any one listed measure may be completed."
+msgstr "Une seule des mesures indiquées peut être accomplie."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:631
-msgid "boolean"
-msgstr "booléen"
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:24
+msgid "Expiration shortcuts"
+msgstr "Raccourcis d’expiration"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:635
-msgid "json"
-msgstr "json"
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:29
+msgid "In a week"
+msgstr "Dans une semaine"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:644
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:197
-msgid "Value"
-msgstr "Valeur"
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:30
+msgid "In a month"
+msgstr "Dans un mois"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:663
-msgid "There are unsatisfied inputs: %1$s"
-msgstr "Il y a des entrées non satisfaites : %1$s"
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:31
+msgid "In a year"
+msgstr "Dans un an"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:674
-msgid "There are missing inputs: %1$s"
-msgstr "Il manque des entrées : %1$s"
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:50
+msgid "Never"
+msgstr "Jamais"
#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:694
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:711
-msgid "There are missing requirements: %1$s"
-msgstr "Il manque des exigences : %1$s"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:115
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:98
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:63
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:72
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:209
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:218
+msgid "Failed to load available measures."
+msgstr "Impossible de charger les mesures disponibles."
#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:751
-msgid "Can't be empty"
-msgstr "Ne peut pas être vide"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:120
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:112
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:77
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:223
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:294
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:480
+msgid "The officer session is invalid."
+msgstr "La session de l’agent AML n’est pas valide."
#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:755
-msgid "It should be a number"
-msgstr "Cela doit être un nombre"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:124
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:116
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:81
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:227
+msgid "The measures endpoint was not found."
+msgstr "Le point de terminaison des mesures est introuvable."
#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:757
-msgid "Not a number"
-msgstr "Pas un nombre"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:130
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:122
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:87
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:233
+msgid "The officer session is disabled."
+msgstr "La session de l’agent AML est désactivée."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:759
-msgid "It should be finite"
-msgstr "Cela doit être fini"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:195
+msgid "Edit proposed rule"
+msgstr "Modifier la règle proposée"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:761
-msgid "It should be a safe integer"
-msgstr "Cela doit être un entier sûr"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:197
+msgid "Add proposed rule"
+msgstr "Ajouter une règle proposée"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:766
-msgid "It should be either \"true\" or \"false\""
-msgstr "Cela doit être soit « true » soit « false »"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:216
+msgid "Save rule"
+msgstr "Enregistrer la règle"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:771
-msgid "Couldn't parse as json string: %1$s"
-msgstr "Impossible d'analyser comme chaîne json : %1$s"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:218
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:372
+msgid "Add rule"
+msgstr "Ajouter une règle"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:797
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:940
-msgid "Description"
-msgstr "Description"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:356
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:348
+#, fuzzy
+#| msgid "Properties"
+msgid "Proposed rules"
+msgstr "Propriétés"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:813
-msgid "Inputs"
-msgstr "Entrées"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:359
+msgid ""
+"This complete rule set replaces the currently applied rules and exchange "
+"defaults until it expires. Higher rows take precedence."
+msgstr ""
+"Cet ensemble complet remplace les règles actuellement appliquées et les "
+"règles par défaut de l’échange jusqu’à son expiration. Les lignes "
+"supérieures sont prioritaires."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:849
-msgid "Output"
-msgstr "Sortie"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:390
+msgid "Rules for another account type"
+msgstr "Règles pour un autre type de compte"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:859
-msgid "Requires"
-msgstr "Nécessite"
-
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:867
-msgid "Fallback"
-msgstr "Repli"
-
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:993
-msgid "Name of the verification measure"
-msgstr "Nom de la mesure de vérification"
-
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1005
-msgid "Read only"
-msgstr "Lecture seule"
-
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1006
-msgid "Prevent the customer from changing the address"
-msgstr "Empêcher le client de modifier l'adresse"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:393
+msgid "These operations do not apply to this account type: %1$s."
+msgstr "Ces opérations ne s’appliquent pas à ce type de compte : %1$s."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:256
-msgid "Configure verification measure: \"%1$s\""
-msgstr "Configurer la mesure de vérification : « %1$s »"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:400
+msgid "Operations without limits"
+msgstr "Opérations sans limites"
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:294
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:115
-msgid "Add custom measure"
-msgstr "Ajouter une mesure personnalisée"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:401
+msgid "No proposed rule limits these operations: %1$s."
+msgstr "Aucune règle proposée ne limite ces opérations : %1$s."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:300
-msgid "Custom measures"
-msgstr "Mesures personnalisées"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:408
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:336
+msgid "Invalid proposed rules"
+msgstr "Règles proposées non valides"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:329
-msgid "Server measures"
-msgstr "Mesures serveur"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:409
+msgid ""
+"Edit the highlighted rule set before continuing. Hard blocks cannot be "
+"combined with measures, and Balance and Refund rules must use an instant "
+"timeframe."
+msgstr ""
+"Modifiez l’ensemble de règles signalé avant de continuer. Les blocages "
+"stricts ne peuvent pas être combinés avec des mesures, et les règles de "
+"solde et de remboursement doivent utiliser une période instantanée."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:426
-msgid "New measures"
-msgstr "Nouvelles mesures"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:432
+msgid "Remove proposed rule?"
+msgstr "Supprimer la règle proposée ?"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:427
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:434
msgid ""
-"Measures that are available/executed directly after the decision is "
-"confirmed."
+"This is the final rule. Removing it leaves every applicable operation "
+"unlimited."
msgstr ""
-"Mesures disponibles/exécutées directement après la confirmation de la "
-"décision."
-
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:154
-msgid "Reset to default"
-msgstr "Réinitialiser par défaut"
+"Il s’agit de la dernière règle. Sa suppression laisse toutes les opérations "
+"applicables sans limite."
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:175
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:234
-msgid "Properties"
-msgstr "Propriétés"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:439
+msgid "The rule will be removed from the proposed set."
+msgstr "La règle sera supprimée de l’ensemble proposé."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:181
-msgid "Custom properties"
-msgstr "Propriétés personnalisées"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:449
+msgid "Keep rule"
+msgstr "Conserver la règle"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:182
-msgid "Add more properties that are not listed above."
-msgstr "Ajoutez d'autres propriétés qui ne sont pas listées ci-dessus."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:459
+msgid "Remove rule"
+msgstr "Supprimer la règle"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:187
-msgid "New properties"
-msgstr "Nouvelles propriétés"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:467
+msgid "Replace proposed rules"
+msgstr "Remplacer les règles proposées"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:218
-msgid "Current note on the GwG file"
-msgstr "Note actuelle sur le dossier GwG"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:470
+msgid "Preview a complete replacement before applying it."
+msgstr "Prévisualisez le remplacement complet avant de l’appliquer."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:223
-msgid "Customer name or internal alias."
-msgstr "Nom du client ou alias interne."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:476
+msgid "Currently applied"
+msgstr "Actuellement appliquées"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:228
-msgid "Is the account active for deposit and payments?"
-msgstr "Le compte est-il actif pour les dépôts et les paiements ?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:486
+msgid "E-commerce"
+msgstr "Commerce électronique"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:233
-msgid "Is the account idle?"
-msgstr "Le compte est-il inactif ?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:489
+msgid "Point of Sale"
+msgstr "Point de vente"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:234
-msgid "No operation for a period of time"
-msgstr "Aucune opération pendant une période donnée"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:496
+msgid "Basic plan"
+msgstr "Forfait de base"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:239
-msgid "Does account belong to a domestic PEP?"
-msgstr "Le compte appartient-il à une PPE nationale ?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:501
+msgid "Premium"
+msgstr "Premium"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:244
-msgid "Does account belong to a foreign PEP?"
-msgstr "Le compte appartient-il à une PPE étrangère ?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:510
+msgid "Freeze account"
+msgstr "Geler le compte"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:249
-msgid "Does account belong to an international-organization PEP?"
-msgstr "Le compte appartient-il à une PPE d'organisation internationale ?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:518
+msgid "Replacement preview"
+msgstr "Aperçu du remplacement"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:254
-msgid "Does account belong to a high risk customer?"
-msgstr "Le compte appartient-il à un client à haut risque ?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:521
+msgid "Confirm account freeze"
+msgstr "Confirmer le gel du compte"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:259
-msgid "Does account belong to a person from a high risk country?"
-msgstr ""
-"Le compte appartient-il à une personne originaire d'un pays à haut risque ?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:522
+msgid "Every applicable operation will receive a zero hard limit."
+msgstr "Chaque opération applicable recevra une limite stricte de zéro."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:264
-msgid "The MROS reporting state for the account."
-msgstr "L'état de déclaration MROS du compte."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:548
+msgid "Apply replacement"
+msgstr "Appliquer le remplacement"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:269
-msgid "None"
-msgstr "Aucun"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:556
+#, fuzzy
+#| msgid "Reset expiration"
+msgid "Rule expiration"
+msgstr "Réinitialiser l'expiration"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:273
-msgid "Pending investigation"
-msgstr "Enquête en attente"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:559
+msgid "Choose how long the proposed rules apply and what happens afterwards."
+msgstr ""
+"Choisissez la durée d’application des règles proposées et ce qui se passe "
+"ensuite."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:277
-msgid "Investigated without suspicion"
-msgstr "Enquêté sans soupçon"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:578
+msgid "The proposed rules never expire, so no successor action will run."
+msgstr ""
+"Les règles proposées n’expirent jamais ; aucune action ultérieure ne sera "
+"donc exécutée."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:281
-msgid "Reported simple suspicion"
-msgstr "Soupçon simple signalé"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:598
+msgid "Restore currently applied expiration"
+msgstr "Rétablir l’expiration actuellement appliquée"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:285
-msgid "Reported substantiated suspicion"
-msgstr "Soupçon fondé signalé"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:682
+msgid "Operation type"
+msgstr "Type d'opération"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:292
-msgid "Informal reason why the AML investigation was triggered"
-msgstr "Raison informelle du déclenchement de l'enquête AML"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:704
+msgid "Timeframe"
+msgstr "Période"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:297
-msgid "Identifies the sanction list entry that the account matched against"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:705
+msgid ""
+"Use Y, M, D, h, m or s after each number. Forever accumulates over the "
+"account's full history."
msgstr ""
-"Identifie l'entrée de la liste de sanctions à laquelle le compte correspond"
+"Utilisez Y, M, D, h, m ou s après chaque nombre. « Toujours » cumule sur "
+"tout l’historique du compte."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:299
-msgid "Best match, does not mean it was a good match."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:709
+msgid "Instant timeframe"
+msgstr "Période instantanée"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:710
+msgid ""
+"Balance and Refund limits apply to one balance or transaction, so their "
+"timeframe is fixed to zero."
msgstr ""
-"Meilleure correspondance, ne signifie pas que c'était une bonne "
-"correspondance."
+"Les limites de solde et de remboursement s’appliquent à un solde ou à une "
+"transaction ; leur période est donc fixée à zéro."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:303
-msgid "Score for how good the sanction list match was"
-msgstr "Score de la qualité de la correspondance avec la liste de sanctions"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:716
+msgid "Exposed"
+msgstr "Exposé"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:308
-msgid "Score for how much supporting data we had for the sanction list match"
-msgstr ""
-"Score de la quantité de données justificatives disponibles pour la "
-"correspondance avec la liste de sanctions"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:717
+msgid "Is this limit communicated to the customer?"
+msgstr "Cette limite est-elle communiquée au client ?"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:313
-msgid ""
-"Suppress flagging this account when it creates a hit on a sanctions list, "
-"this is a false-positive"
-msgstr ""
-"Supprimer le signalement de ce compte lorsqu'il correspond à une liste de "
-"sanctions ; il s'agit d'un faux positif"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:723
+msgid "When the threshold is crossed"
+msgstr "Lorsque le seuil est franchi"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:190
-#, fuzzy
-msgid "Failed to make the decision."
-msgstr "Décrire la décision."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:726
+msgid "Require measures"
+msgstr "Exiger des mesures"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:193
-#, fuzzy
-msgid "Invalid credentials."
-msgstr "Compte invalide"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:740
+msgid "Required measures"
+msgstr "Mesures requises"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:197
-#, fuzzy
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:741
msgid ""
-"The session is disabled or a more recent decision was already submitted."
-msgstr "Agent désactivé ou décision plus récente déjà soumise."
+"Measures that the customer will need to satisfy to apply for a new threshold."
+msgstr "Mesures que le client devra satisfaire pour demander un nouveau seuil."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:208
-msgid "Confirmation required"
-msgstr "Confirmation requise"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:747
+msgid "All measures"
+msgstr "Toutes les mesures"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:209
-#, fuzzy
-msgid ""
-"This decision declares that the MROS report has concluded. Please make sure "
-"that this is the case"
-msgstr ""
-"Cette décision déclare que le rapport MROS est conclu. Veuillez vous assurer "
-"que c'est bien le cas"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:748
+msgid "Hint the customer that all measures should be completed"
+msgstr "Indiquer au client que toutes les mesures doivent être complétées"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:222
-msgid "I want to check first!"
-msgstr "Je veux d'abord vérifier !"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:767
+msgid "Expiration date"
+msgstr "Date d'expiration"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:229
-msgid "Confirm decision"
-msgstr "Confirmer la décision"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:768
+msgid "Until when are the new rules active."
+msgstr "Jusqu'à quand les nouvelles règles sont actives."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:245
-msgid "Missing deadline"
-msgstr "Échéance manquante"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:773
+msgid "Choose a future expiration date or Never."
+msgstr "Choisissez une date d’expiration future ou « Jamais »."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:248
-msgid ""
-"Deadline should specify when this rules ends and what is the next measures "
-"to apply after expiration."
-msgstr ""
-"L'échéance doit préciser quand cette règle se termine et quelles sont les "
-"prochaines mesures à appliquer après expiration."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:779
+msgid "After expiration"
+msgstr "Après l’expiration"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:257
-msgid "Missing rules"
-msgstr "Règles manquantes"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:781
+msgid "Return to exchange defaults"
+msgstr "Revenir aux valeurs par défaut de l’échange"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:260
-msgid "Can't make a decision without rules."
-msgstr "Impossible de prendre une décision sans règles."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:782
+msgid "Trigger a successor measure"
+msgstr "Déclencher une mesure ultérieure"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:284
-msgid "Missing active measure"
-msgstr "Mesure active manquante"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:797
+msgid "Measure taken automatically upon expiration of the current decision."
+msgstr "Mesure prise automatiquement à l'expiration de la décision actuelle."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:287
-msgid "You should specify in the measure section."
-msgstr "Vous devez le préciser dans la section des mesures."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:805
+msgid "This successor measure is no longer available."
+msgstr "Cette mesure ultérieure n’est plus disponible."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:294
-msgid "No customer action required."
-msgstr "Aucune action du client requise."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:133
+msgid "Case summary"
+msgstr "Résumé du dossier"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:297
-msgid "No active measure has been selected."
-msgstr "Aucune mesure active n'a été sélectionnée."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:134
+msgid "Current review state and the latest account activity."
+msgstr "État actuel de l’examen et activité la plus récente du compte."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:305
-msgid "Missing properties"
-msgstr "Propriétés manquantes"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:138
+msgid "Review status"
+msgstr "État de l’examen"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:308
-msgid "You should specify in the properties section."
-msgstr "Vous devez le préciser dans la section des propriétés."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:142
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:153
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:171
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:188
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:492
+msgid "Loading…"
+msgstr "Chargement…"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:318
-msgid "Missing events"
-msgstr "Événements manquants"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:146
+msgid "Manual review required — waiting for an AML decision."
+msgstr "Examen manuel requis — en attente d’une décision AML."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:321
-msgid "You should specify in the events section."
-msgstr "Vous devez le préciser dans la section des événements."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:147
+msgid "No manual review"
+msgstr "Aucun examen manuel"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:331
-msgid "Missing justification"
-msgstr "Justification manquante"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:150
+msgid "Effective decision"
+msgstr "Décision en vigueur"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:334
-msgid "You must complete the justification section."
-msgstr "Vous devez compléter la section de justification."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:168
+msgid "Requirements"
+msgstr "Exigences"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:344
-msgid "Invalid attributes"
-msgstr "Attributs invalides"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:185
+msgid "Latest collected information"
+msgstr "Dernières informations recueillies"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:347
-msgid "You should check form errors or submit a decision without attributes."
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:208
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:305
+#, fuzzy
+#| msgid "Send decision"
+msgid "Current decision"
+msgstr "Envoyer la décision"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:209
+#, fuzzy
+#| msgid ""
+#| "The AML decision and operation rules currently applied to this account."
+msgid "The complete AML decision currently applied to this account."
msgstr ""
-"Vous devez vérifier les erreurs du formulaire ou soumettre une décision sans "
-"attributs."
+"La décision AML et les règles d’opération actuellement appliquées à ce "
+"compte."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:361
-msgid "Clear"
-msgstr "Effacer"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:216
+msgid "Effective policy could not be loaded"
+msgstr "Impossible de charger la politique en vigueur"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:368
-msgid "Send decision"
-msgstr "Envoyer la décision"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:234
+msgid "Exchange defaults apply"
+msgstr "Les règles par défaut de l’Exchange s’appliquent"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:173
-msgid "Prev"
-msgstr "Précédent"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:235
+msgid "No AML officer decision is active for this account."
+msgstr "Aucune décision d’un agent AML n’est active pour ce compte."
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:182
-msgid "Next"
-msgstr "Suivant"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:238
+msgid "Account type unavailable"
+msgstr "Type de compte indisponible"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:207
-msgid "Attributes"
-msgstr "Attributs"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:239
+msgid ""
+"Open this case from the account directory or payto search to see the "
+"applicable default rules."
+msgstr ""
+"Ouvrez ce dossier depuis le répertoire des comptes ou la recherche payto "
+"pour afficher les règles par défaut applicables."
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:208
-msgid "Add more information about the customer"
-msgstr "Ajouter des informations supplémentaires sur le client"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:248
+msgid "Default rules could not be loaded"
+msgstr "Impossible de charger les règles par défaut"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:212
-msgid "Rules"
-msgstr "Règles"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:255
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:419
+#: packages/taler-exchange-aml-webui/src/components/ShowDefaultRules.tsx:11
+msgid "Default rules"
+msgstr "Règles par défaut"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:213
-msgid "Set the limit of the operations"
-msgstr "Définir la limite des opérations"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:266
+msgid "Collected information"
+msgstr "Informations collectées"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:218
-msgid "Trigger notifications."
-msgstr "Déclencher des notifications."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:267
+msgid "KYC information filed by the customer or an AML officer."
+msgstr "Informations KYC déposées par le client ou un agent AML."
-#. screenid: 113
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:222
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:102
-msgid "Measures"
-msgstr "Mesures"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:273
+msgid "Collected information could not be loaded"
+msgstr "Impossible de charger les informations recueillies"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:223
-msgid "Ask the customer to take action."
-msgstr "Demander au client de prendre une mesure."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:279
+msgid "No collected information"
+msgstr "Aucune information recueillie"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:228
-msgid "Describe the decision."
-msgstr "Décrire la décision."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:280
+msgid "No KYC information has been collected for this account."
+msgstr "Aucune information KYC n’a été recueillie pour ce compte."
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:235
-msgid "Flag the current account state."
-msgstr "Signaler l'état actuel du compte."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:302
+msgid "Active requirements"
+msgstr "Exigences actives"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:239
-msgid "Summary"
-msgstr "Résumé"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:303
+msgid "Measures the customer must complete under the current policy."
+msgstr "Mesures que le client doit accomplir selon la politique actuelle."
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:240
-msgid "Review and submit."
-msgstr "Vérifier et soumettre."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:309
+msgid "Active requirements could not be loaded"
+msgstr "Impossible de charger les exigences actives"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:404
-msgid "Decision for account:"
-msgstr "Décision pour le compte :"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:315
+msgid "No active requirements"
+msgstr "Aucune exigence active"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:411
-msgid "Decision for wallet:"
-msgstr "Décision pour le portefeuille :"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:316
+msgid "The customer has no active legitimization measures to complete."
+msgstr "Le client n’a aucune mesure de légitimation active à accomplir."
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:417
-msgid "Decision for bank account:"
-msgstr "Décision pour le compte bancaire :"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:413
+msgid "Officer decision"
+msgstr "Décision de l’agent"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:88
-msgid "Search account"
-msgstr "Rechercher un compte"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:416
+msgid "Does not expire"
+msgstr "N’expire pas"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:154
-msgid "Failed to load account decisions."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:439
+msgid "Waiting"
+msgstr "En attente"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:163
-#, fuzzy
-msgid "Failed to load the account history."
-msgstr "Nom complet du titulaire du compte"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:451
+msgid "More on later pages"
+msgstr "Autres éléments sur les pages suivantes"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:205
-msgid "Check account details"
-msgstr "Vérifier les détails du compte"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:510
+msgid "Try loading this section again."
+msgstr "Essayez de recharger cette section."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:212
-msgid "Account most recent decisions"
-msgstr "Décisions les plus récentes du compte"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:518
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:97
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:633
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:205
+msgid "Retry"
+msgstr "Réessayer"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:231
-msgid "When"
-msgstr "Quand"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:566
+msgid "Unconfigured form"
+msgstr "Formulaire non configuré"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:265
-msgid "LATEST"
-msgstr "DERNIÈRE"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:567
+msgid "Form not identified"
+msgstr "Formulaire non identifié"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:270
-msgid "ACTIVE"
-msgstr "ACTIVE"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:576
+msgid "Filed by an AML officer"
+msgstr "Déposé par un agent AML"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:297
-msgid "Account not found"
-msgstr "Compte introuvable"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:577
+msgid "Provided by the customer"
+msgstr "Fourni par le client"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:298
-msgid "There is no history known for this account yet."
-msgstr "Aucun historique connu pour ce compte pour l'instant."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:581
+msgid "Attribute data is unavailable."
+msgstr "Les données d’attributs sont indisponibles."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:308
-msgid "You can make a decision for this account anyway."
-msgstr "Vous pouvez tout de même prendre une décision pour ce compte."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:595
+msgid "View details"
+msgstr "Voir les détails"
-#. screenid: 111
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:357
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:400
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:449
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:490
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:377
-msgid "Search"
-msgstr "Rechercher"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:70
+msgid ""
+"Review superseded AML decisions for this account, from newest to oldest."
+msgstr ""
+"Examiner les décisions AML remplacées pour ce compte, de la plus récente à "
+"la plus ancienne."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:528
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:761
-msgid "IBAN"
-msgstr "IBAN"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:79
+msgid "Loading decision history…"
+msgstr "Chargement de l’historique des décisions…"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:532
-msgid "Taler Bank"
-msgstr "Banque Taler"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:84
+msgid "Decision history could not be loaded"
+msgstr "Impossible de charger l’historique des décisions"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:536
-msgid "Wallet"
-msgstr "Portefeuille numérique"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:87
+msgid "Try loading the decision history again."
+msgstr "Essayez de charger à nouveau l’historique des décisions."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:540
-msgid "Generic Payto:// URI"
-msgstr "URI Payto:// générique"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:111
+msgid "No previous decisions"
+msgstr "Aucune décision antérieure"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:543
-msgid "Account type"
-msgstr "Type de compte"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:114
+msgid "No superseded AML decisions have been recorded for this account."
+msgstr "Aucune décision AML remplacée n’a été enregistrée pour ce compte."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:553
-msgid "Should be 52 characters."
-msgstr "Doit comporter 52 caractères."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:125
+msgid "Previous decisions"
+msgstr "Décisions antérieures"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:555
-msgid "Failed to parse: %1$s"
-msgstr "Échec de l'analyse : %1$s"
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:153
+msgid "The export could not be prepared. Try again."
+msgstr "L’exportation n’a pas pu être préparée. Réessayez."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:567
-msgid "Address contains invalid characters."
-msgstr "L'adresse contient des caractères invalides."
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:164
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:173
+msgid "Failed to load accounts"
+msgstr "Impossible de charger les comptes"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:569
-msgid "Can't mix uppercased and lowercased characters."
-msgstr "Impossible de mélanger majuscules et minuscules."
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:193
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:552
+msgid "Accounts"
+msgstr "Comptes"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:571
-msgid "The addr checksum doesn't match."
-msgstr "La somme de contrôle de l'adresse ne correspond pas."
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:196
+msgid "Review accounts known to the exchange for AML and KYC handling."
+msgstr ""
+"Consultez les comptes connus de l’exchange pour leur traitement AML et KYC."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:573
-msgid "Missing separator or address type."
-msgstr "Séparateur ou type d'adresse manquant."
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:203
+msgid "Export filtered accounts"
+msgstr "Exporter les comptes filtrés"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:575
-msgid "Address should have less than 90 characters."
-msgstr "L'adresse doit comporter moins de 90 caractères."
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:211
+msgid "Download CSV"
+msgstr "Télécharger le CSV"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:577
-msgid "Address should have more than 6 characters."
-msgstr "L'adresse doit comporter plus de 6 caractères."
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:218
+msgid "Download Excel"
+msgstr "Télécharger le fichier Excel"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:579
-msgid "Decoding issue."
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:226
+msgid "Preparing export…"
+msgstr "Préparation de l’exportation…"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:230
+msgid "Export failed"
+msgstr "Échec de l’exportation"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:236
+msgid "Account filters"
+msgstr "Filtres des comptes"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:242
+msgid "Investigation"
+msgstr "Enquête"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:244
+msgid "All accounts"
+msgstr "Tous les comptes"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:251
+msgid "Risk"
+msgstr "Risque"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:253
+msgid "All risk levels"
+msgstr "Tous les niveaux de risque"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:255
+msgid "Not high risk"
+msgstr "Sans risque élevé"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:260
+msgid "File status"
+msgstr "État du dossier"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:262
+msgid "All file statuses"
+msgstr "Tous les états du dossier"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:264
+msgid "Not open"
+msgstr "Non ouvert"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:273
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:589
+msgid "Clear filters"
+msgstr "Effacer les filtres"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:283
+msgid "Showing %1$s accounts · newest first"
+msgstr "%1$s comptes affichés · les plus récents en premier"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:290
+msgid "AML and KYC accounts"
+msgstr "Comptes AML et KYC"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:298
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:458
+msgid "Account lifecycle"
+msgstr "Cycle de vie du dossier"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:304
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:467
+msgid "Latest note"
+msgstr "Note la plus récente"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:550
+msgid "Copied"
+msgstr "Copié"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:550
+msgid "Copy"
+msgstr "Copier"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:576
+msgid "No matching accounts"
+msgstr "Aucun compte correspondant"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:576
+msgid "No accounts yet"
+msgstr "Aucun compte pour le moment"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:580
+msgid "No accounts match the selected filters."
+msgstr "Aucun compte ne correspond aux filtres sélectionnés."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:581
+msgid "The exchange has not recorded any AML or KYC accounts yet."
+msgstr "L’exchange n’a encore enregistré aucun compte AML ou KYC."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:647
+msgid "This officer session is not authorized to list accounts."
+msgstr "Cette session d’agent n’est pas autorisée à répertorier les comptes."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:649
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:674
+msgid "The exchange does not recognize this officer session."
+msgstr "L’exchange ne reconnaît pas cette session d’agent."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:651
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:676
+msgid "This officer session is currently disabled."
+msgstr "Cette session d’agent est actuellement désactivée."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:668
+msgid "There are no matching accounts to export."
+msgstr "Aucun compte correspondant ne peut être exporté."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:670
+msgid "The exchange does not support the selected export format."
+msgstr "L’exchange ne prend pas en charge le format d’exportation sélectionné."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:672
+msgid "This officer session is not authorized to export accounts."
+msgstr "Cette session d’agent n’est pas autorisée à exporter les comptes."
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:52
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:546
+msgid "Dashboard"
+msgstr "Tableau de bord"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:55
+msgid ""
+"Review cases requiring attention, investigate accounts, and monitor AML "
+"reporting indicators."
msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:581
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:77
+msgid "Review case queue"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:80
#, fuzzy
-msgid "Invalid data"
-msgstr "Hôte invalide"
+#| msgid "Accounts under investigation."
+msgid "Review accounts currently under investigation."
+msgstr "Comptes sous enquête."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:591
-msgid "Unsupported country."
-msgstr "Pays non pris en charge."
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:94
+#, fuzzy
+#| msgid "Show transfers"
+msgid "Inspect transfers"
+msgstr "Afficher les transferts"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:593
-msgid "IBANs have fewer than 34 characters."
-msgstr "Les IBAN comportent moins de 34 caractères."
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:97
+msgid "Find credit, debit, and KYC authorization activity."
+msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:595
-msgid "IBANs have more than 4 characters."
-msgstr "Les IBAN comportent plus de 4 caractères."
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:128
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:165
+msgid "Statistics"
+msgstr "Statistiques"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:597
-msgid "IBAN length is invalid for this country."
-msgstr "La longueur de l’IBAN n’est pas valide pour ce pays."
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:132
+msgid "No reporting profile for this dialect"
+msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:597
-msgid "It should only contain numbers and letters."
-msgstr "Il ne doit contenir que des chiffres et des lettres."
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:137
+msgid ""
+"The testing dialect does not define dashboard statistics. Select TOPS in "
+"development settings to inspect the TOPS reporting profile."
+msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:599
-msgid "The checksum is wrong."
-msgstr "La somme de contrôle est incorrecte."
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:154
+msgid "Failed to load TOPS statistics."
+msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:617
-msgid "The string should start with payto://"
-msgstr "La chaîne doit commencer par payto://"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:192
+#, fuzzy
+#| msgid "Attributes unavailable"
+msgid "Some statistics are unavailable."
+msgstr "Attributs indisponibles"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:619
-msgid "After the target type it should follow a '/' with more information."
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:195
+msgid "The available values are shown below. Missing values are not zero."
msgstr ""
-"Après le type de cible, un « / » doit être suivi d'informations "
-"supplémentaires."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:621
-msgid ""
-"The target type is not supported, only x-taler-bank, taler-reserve or iban"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:275
+msgid "Accounts open"
+msgstr "Comptes ouverts"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:278
+msgid "New files last year"
+msgstr "Nouveaux dossiers l'année dernière"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:281
+msgid "Closed files last year"
+msgstr "Dossiers fermés l'année dernière"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:284
+msgid "MROS substantiated"
+msgstr "MROS motivés"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:287
+msgid "MROS simple"
+msgstr "MROS simples"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:290
+msgid "High risk files"
+msgstr "Dossiers à haut risque"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:293
+msgid "PEP files"
+msgstr "Dossiers PPE"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:333
+msgid "Number of accounts that are opened"
+msgstr "Nombre de comptes ouverts"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:336
+msgid "Number of new GwG files in the last year"
+msgstr "Nombre de nouveaux dossiers GwG au cours de la dernière année"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:339
+msgid "Number of GwG files closed in the last year"
+msgstr "Nombre de dossiers GwG fermés au cours de la dernière année"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:342
+msgid "Number of MROS reports based on Art 9 Abs. 1 GwG (per year)"
+msgstr "Nombre de déclarations MROS fondées sur l'art. 9 al. 1 GwG (par an)"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:345
+msgid "Number of MROS reports based on Art 305ter Abs. 2 StGB (per year)"
msgstr ""
-"Le type de cible n'est pas pris en charge, seuls x-taler-bank, taler-reserve "
-"ou iban le sont"
+"Nombre de déclarations MROS fondées sur l'art. 305ter al. 2 StGB (par an)"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:626
-msgid "IBAN is missing"
-msgstr "L'IBAN est manquant"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:348
+msgid "Number of GwG files of high-risk customers"
+msgstr "Nombre de dossiers GwG de clients à haut risque"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:628
-msgid "Bitcoin address is missing"
-msgstr "L'adresse Bitcoin est manquante"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:351
+msgid "Number of GwG files managed with “increased risk” due to PEP status"
+msgstr ""
+"Nombre de dossiers GwG gérés avec un « risque accru » en raison du statut de "
+"PPE"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:630
-msgid "Bank host and account is missing"
-msgstr "L'hôte bancaire et le compte sont manquants"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:354
+#, fuzzy
+msgid "Number of customers with open proceeding."
+msgstr "Nombre de comptes ouverts"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:632
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:634
-msgid "Exchange host and account is missing"
-msgstr "L'hôte de l'exchange et le compte sont manquants"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:400
+msgid "previous"
+msgstr "précédent"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:636
-msgid "Ethereum address is missing"
-msgstr "L'adresse Ethereum est manquante"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:443
+msgid "Decreased by"
+msgstr "Diminué de"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:638
-msgid "Cyclos address is missing"
-msgstr "L'adresse Cyclos est manquante"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:447
+msgid "Increased by"
+msgstr "Augmenté de"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:640
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:114
+msgid ""
+"The built-in event selection differs from the events derived from the "
+"proposed account state."
+msgstr ""
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:119
+msgid ""
+"Built-in events are derived from changes to the proposed account properties. "
+"They are stored for reporting and statistics; they do not notify the "
+"customer."
+msgstr ""
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:138
#, fuzzy
-msgid "Void address is missing"
-msgstr "L'adresse Bitcoin est manquante"
+#| msgid "Reset to default"
+msgid "Reset to derived events"
+msgstr "Réinitialiser par défaut"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:648
-msgid "Invalid IBAN: %1$s"
-msgstr "IBAN invalide : %1$s"
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:169
+msgid "Calculated"
+msgstr "Calculé"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:655
-msgid "Invalid BTC: %1$s"
-msgstr "BTC invalide : %1$s"
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:170
+msgid ""
+"Events derived from proposed property changes and submitted information."
+msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:660
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:683
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:696
-msgid "Invalid reserve: %1$s"
-msgstr "Réserve invalide : %1$s"
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:184
+msgid "Other built-in events"
+msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:671
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:681
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:694
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:715
-msgid "Invalid host"
-msgstr "Hôte invalide"
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:185
+#, fuzzy
+#| msgid "Events that can be triggered manually"
+msgid "Additional events that may be recorded manually."
+msgstr "Événements pouvant être déclenchés manuellement"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:707
-msgid "Invalid address"
-msgstr "Adresse invalide"
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:198
+#, fuzzy
+#| msgid "Next event"
+msgid "Custom events"
+msgstr "Événement suivant"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:745
-msgid "Payto URI"
-msgstr "URI Payto"
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:199
+msgid "Operator-defined event names that are not part of the selected dialect."
+msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:746
-msgid "As defined by RFC 8905"
-msgstr "Tel que défini par la RFC 8905"
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:213
+#, fuzzy
+#| msgid "Describe the decision."
+msgid "Events recorded with this decision"
+msgstr "Décrire la décision."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:747
-msgid "payto://"
-msgstr "payto://"
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:214
+#, fuzzy
+#| msgid ""
+#| "The events will be triggered only after the decision has been confirmed."
+msgid "Events are added only after the decision is successfully submitted."
+msgstr ""
+"Les événements ne seront déclenchés qu'après la confirmation de la décision."
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:209
+#, fuzzy
+#| msgid "System information"
+msgid "Add customer information"
+msgstr "Information système"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:212
+msgid ""
+"The completed form is attached to this AML decision as reviewed account "
+"information. It does not create a customer-facing measure."
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:223
+#, fuzzy
+#| msgid "Collected information"
+msgid "Selected form"
+msgstr "Informations collectées"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:233
+#, fuzzy
+#| msgid "Complete the form"
+msgid "Choose another form"
+msgstr "Compléter le formulaire"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:242
+msgid "Expiration"
+msgstr "Expiration"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:243
+msgid "Expiration date of the information filled in this form."
+msgstr "Date d'expiration des informations saisies dans ce formulaire."
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:254
+#, fuzzy
+#| msgid "Context"
+msgid "Form context"
+msgstr "Contexte"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:261
+#, fuzzy
+#| msgid "Context"
+msgid "Advanced form context"
+msgstr "Contexte"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:264
+msgid ""
+"Only change this operator-defined JSON when the form documentation requires "
+"additional context."
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:270
+#, fuzzy
+#| msgid "Context"
+msgid "Context as JSON"
+msgstr "Contexte"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:291
+#, fuzzy
+msgid "Invalid JSON"
+msgstr "Hôte invalide"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:296
+msgid "Invalid expiration"
+msgstr "Expiration non valide"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:297
+msgid "Attributes require an expiration date in the future or set to Never."
+msgstr ""
+"Les attributs nécessitent une date d’expiration future ou doivent être "
+"définis sur « Jamais »."
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:355
+msgid "Include new information"
+msgstr "Inclure de nouvelles informations"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:356
+msgid ""
+"This step is optional. Select a form to attach newly reviewed AML/KYC "
+"information, or continue without one."
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:361
+msgid "AML/KYC form"
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:362
+msgid "Search AML/KYC forms"
+msgstr "Rechercher des formulaires AML/KYC"
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:101
+#, fuzzy
+#| msgid "Accounts under investigation."
+msgid "The account will be included in the AML investigation queue."
+msgstr "Comptes sous enquête."
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:106
+#, fuzzy
+#| msgid "Accounts under investigation."
+msgid "The account will not be included in the AML investigation queue."
+msgstr "Comptes sous enquête."
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:114
+#, fuzzy
+#| msgid "Investigation"
+msgid "Current investigation status"
+msgstr "Enquête"
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:128
+#, fuzzy
+#| msgid "No previous decisions"
+msgid "No previous decision"
+msgstr "Aucune décision antérieure"
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:140
+#, fuzzy
+#| msgid "Investigation"
+msgid "Investigation status after this decision"
+msgstr "Enquête"
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:145
+#, fuzzy
+#| msgid "Measures the customer must complete under the current policy."
+msgid ""
+"Choose whether the account should remain in the AML investigation queue "
+"after this decision is submitted."
+msgstr "Mesures que le client doit accomplir selon la politique actuelle."
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:201
+msgid ""
+"Full name used in the payto URI when creating this previously unknown "
+"account."
+msgstr ""
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:208
+#, fuzzy
+#| msgid "Decision date"
+msgid "Decision rationale"
+msgstr "Date de la décision"
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:209
+msgid ""
+"Record the facts and reasoning needed to understand this decision in a later "
+"audit or review."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:264
+#, fuzzy
+#| msgid "Custom measures"
+msgid "Create custom measure"
+msgstr "Mesures personnalisées"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:266
+#, fuzzy
+#| msgid "Add custom measure"
+msgid "Edit custom measure"
+msgstr "Ajouter une mesure personnalisée"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:270
+msgid ""
+"Combine a customer check with an AML program, or use SKIP to run a program "
+"immediately. Context values must satisfy the selected check and program "
+"requirements."
+msgstr ""
+
+#. screenid: 122
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:289
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:478
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:366
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:115
+msgid "Add custom measure"
+msgstr "Ajouter une mesure personnalisée"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:299
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:488
+msgid "Save changes"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:306
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:495
+#, fuzzy
+#| msgid "Add custom measure"
+msgid "Remove custom measure"
+msgstr "Ajouter une mesure personnalisée"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:547
+#, fuzzy
+#| msgid "Configure verification type: %1$s"
+msgid "Configure %1$s verification"
+msgstr "Configurer le type de vérification : %1$s"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:558
+msgid "Use advanced measure editor"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:587
+#, fuzzy
+#| msgid "Name of the verification measure"
+msgid "Use guided verification editor"
+msgstr "Nom de la mesure de vérification"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:632
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1111
+msgid "There is already a measure with that name"
+msgstr "Il existe déjà une mesure portant ce nom"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:646
+msgid ""
+"Runs immediately for SKIP measures, or after a successful check. It may be "
+"omitted for a check that only presents or collects information."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:650
+msgid "Missing check or program"
+msgstr "Vérification ou programme manquant"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:660
+msgid ""
+"The customer-facing check to perform before the program. Leave empty to use "
+"SKIP and run the program immediately."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:683
+msgid ""
+"Configuration values required by the selected check or program. Property "
+"names and value types must match the exchange configuration."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:690
+msgid "Field name"
+msgstr "Nom du champ"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:695
+msgid "Type"
+msgstr "Type"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:699
+msgid "string"
+msgstr "chaîne"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:703
+msgid "number"
+msgstr "nombre"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:707
+msgid "boolean"
+msgstr "booléen"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:711
+msgid "json"
+msgstr "json"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:738
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:792
+#, fuzzy
+#| msgid "Form not available"
+msgid "Program \"%1$s\" is not available"
+msgstr "Formulaire indisponible"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:742
+msgid "There are unsatisfied inputs: %1$s"
+msgstr "Il y a des entrées non satisfaites : %1$s"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:750
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:772
+msgid "Check \"%1$s\" is not available"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:756
+msgid "There are missing inputs: %1$s"
+msgstr "Il manque des entrées : %1$s"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:779
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:799
+msgid "There are missing requirements: %1$s"
+msgstr "Il manque des exigences : %1$s"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:855
+msgid "Can't be empty"
+msgstr "Ne peut pas être vide"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:859
+msgid "Not a number"
+msgstr "Pas un nombre"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:861
+msgid "It should be finite"
+msgstr "Cela doit être fini"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:866
+msgid "It should be either \"true\" or \"false\""
+msgstr "Cela doit être soit « true » soit « false »"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:871
+msgid "Couldn't parse as json string: %1$s"
+msgstr "Impossible d'analyser comme chaîne json : %1$s"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:899
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:946
+msgid "Description"
+msgstr "Description"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:915
+msgid "Inputs"
+msgstr "Entrées"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:954
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:534
+#, fuzzy
+#| msgid "Output"
+msgid "Outputs"
+msgstr "Sortie"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:962
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:401
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:533
+#, fuzzy
+#| msgid "Required"
+msgid "Required context"
+msgstr "Requis"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:970
+msgid "Fallback"
+msgstr "Repli"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:993
+#, fuzzy
+#| msgid "Context"
+msgid "Context values"
+msgstr "Contexte"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1045
+msgid "Selected pipeline"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1048
+msgid "Review how the exchange will execute this measure."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1105
+msgid "Name of the verification measure"
+msgstr "Nom de la mesure de vérification"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1118
+msgid "Read only"
+msgstr "Lecture seule"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1119
+msgid "Prevent the customer from changing the address"
+msgstr "Empêcher le client de modifier l'adresse"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:154
+msgid "Customer actions after submission"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:157
+msgid ""
+"Immediate measures start as soon as this decision is accepted. A measure may "
+"show information, collect customer data, or run an AML program. Leave the "
+"selection empty when no immediate customer action is required."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:302
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:301
+msgid "Too many SKIP measures"
+msgstr "Trop de mesures SKIP"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:303
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:302
+msgid "At most one immediate measure may use the SKIP check."
+msgstr "Une seule mesure immédiate au maximum peut utiliser le contrôle SKIP."
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:332
+#, fuzzy
+#| msgid "Configure verification measure: \"%1$s\""
+msgid "Configure verification measure “%1$s”"
+msgstr "Configurer la mesure de vérification : « %1$s »"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:372
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:522
+msgid "Custom measures"
+msgstr "Mesures personnalisées"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:375
+msgid "Measures defined only for this proposed decision."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:399
+msgid "Edit"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:407
+#, fuzzy
+#| msgid "All measures"
+msgid "Available exchange measures"
+msgstr "Toutes les mesures"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:410
+msgid "Reusable templates configured by the exchange operator"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:432
+msgid "Use as template"
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:512
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:288
+#, fuzzy
+#| msgid "Instant measures"
+msgid "Immediate measures"
+msgstr "Mesures instantanées"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:513
+msgid ""
+"Selected measures begin immediately after the decision is accepted by the "
+"exchange."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:518
+#, fuzzy
+#| msgid "Require all measures"
+msgid "Require every selected measure"
+msgstr "Exiger toutes les mesures"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:519
+#, fuzzy
+#| msgid ""
+#| "Run all selected measures together instead of accepting any one of them."
+msgid ""
+"When enabled, all selected measures must be completed. Otherwise, completing "
+"any one of them is sufficient."
+msgstr ""
+"Exécuter ensemble toutes les mesures sélectionnées au lieu d’accepter "
+"n’importe laquelle d’entre elles."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:190
+#, fuzzy
+msgid "Failed to make the decision."
+msgstr "Décrire la décision."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:193
+#, fuzzy
+msgid "Invalid credentials."
+msgstr "Compte invalide"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:195
+msgid "Session not found. Contact the administrator."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:197
+msgid ""
+"The exchange rejected the decision because the officer session is disabled "
+"or the account has a newer decision. Reload the account before trying again."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:251
+msgid ""
+"This decision records that an MROS report was filed. Confirm that the report "
+"has actually been submitted before continuing."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:264
+#, fuzzy
+#| msgid "No manual review"
+msgid "Go back and review"
+msgstr "Aucun examen manuel"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:271
+msgid "Confirm decision"
+msgstr "Confirmer la décision"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:283
+msgid "Unknown measure"
+msgstr "Mesure inconnue"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:284
+msgid ""
+"A rule or immediate action references a measure that is not available. "
+"Review the rules and measures before submitting."
+msgstr ""
+"Une règle ou une action immédiate fait référence à une mesure indisponible. "
+"Vérifiez les règles et les mesures avant l’envoi."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:291
+#, fuzzy
+#| msgid "Add custom measure"
+msgid "Invalid custom measure"
+msgstr "Ajouter une mesure personnalisée"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:292
+msgid ""
+"A custom measure references an unavailable check or program, lacks required "
+"context, or cannot provide the selected program inputs. Review the immediate "
+"measures before submitting."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:310
+msgid "Missing deadline"
+msgstr "Échéance manquante"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:311
+msgid "Set when the proposed rules expire and what should happen afterward."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:319
+msgid "Invalid rule expiration"
+msgstr "Expiration des règles non valide"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:320
+msgid "Rule expiration must be in the future or set to Never."
+msgstr "L’expiration des règles doit être future ou définie sur « Jamais »."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:327
+msgid "Missing rules"
+msgstr "Règles manquantes"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:328
+msgid ""
+"A decision must contain the complete rule set that will apply to the account."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:337
+msgid ""
+"Review the proposed rules. Hard blocks must be explicit, and Balance and "
+"Refund rules must use an instant timeframe."
+msgstr ""
+"Vérifiez les règles proposées. Les blocages stricts doivent être explicites, "
+"et les règles de solde et de remboursement doivent utiliser une période "
+"instantanée."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:376
+msgid "Immediate measures not reviewed"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:378
+#, fuzzy
+#| msgid "Measures the customer must complete under the current policy."
+msgid "Review whether the customer must complete any immediate measures."
+msgstr "Mesures que le client doit accomplir selon la politique actuelle."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:384
+#, fuzzy
+#| msgid "Triggered immediately without customer interaction."
+msgid "No immediate customer action"
+msgstr "Déclenchées immédiatement sans interaction du client."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:385
+msgid "No measure will start when this decision is submitted."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:396
+#, fuzzy
+#| msgid "Account properties"
+msgid "Account properties not reviewed"
+msgstr "Propriétés du compte"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:398
+msgid "Review the account properties before submitting the decision."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:409
+msgid "Reporting events not reviewed"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:411
+msgid "Review which statistical events will be recorded with the decision."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:420
+msgid "Case disposition incomplete"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:421
+msgid "You must complete the justification section."
+msgstr "Vous devez compléter la section de justification."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:430
+msgid "Invalid attributes"
+msgstr "Attributs invalides"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:431
+msgid ""
+"Correct the selected form or continue without attaching new customer "
+"information."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:443
+#, fuzzy
+#| msgid "Check account details"
+msgid "Decision details"
+msgstr "Vérifier les détails du compte"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:447
+msgid "Justification"
+msgstr "Justification"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:450
+#, fuzzy
+#| msgid "Not opened"
+msgid "Not provided"
+msgstr "Non ouvert"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:454
+#, fuzzy
+#| msgid "Accounts under investigation."
+msgid "The account remains under investigation."
+msgstr "Comptes sous enquête."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:458
+#, fuzzy
+#| msgid "Accounts under investigation."
+msgid "The account will not remain under investigation."
+msgstr "Comptes sous enquête."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:487
+msgid "No account properties"
+msgstr "Aucune propriété de compte"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:493
+msgid "Events"
+msgstr "Événements"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:496
+#, fuzzy
+#| msgid "Next event"
+msgid "No events"
+msgstr "Événement suivant"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:501
+#, fuzzy
+#| msgid "Invalid attributes"
+msgid "Submitted attributes"
+msgstr "Attributs invalides"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:509
+#, fuzzy
+#| msgid "Expiration date"
+msgid "expiration set"
+msgstr "Date d'expiration"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:515
+#, fuzzy
+#| msgid "Invalid attributes"
+msgid "No new attributes"
+msgstr "Attributs invalides"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:537
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:550
+#, fuzzy
+#| msgid "Officer decision"
+msgid "Discard decision"
+msgstr "Décision de l’agent"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:544
+#, fuzzy
+#| msgid "Send decision"
+msgid "Submit AML decision"
+msgstr "Envoyer la décision"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:549
+#, fuzzy
+#| msgid "Discard this key"
+msgid "Discard this decision?"
+msgstr "Supprimer cette clé"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:554
+msgid ""
+"All entries made in this decision wizard will be lost. No change will be "
+"submitted to the exchange."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:571
+#, fuzzy
+#| msgid "Review status"
+msgid "Review this step"
+msgstr "État de l’examen"
+
+#. screenid: 113
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:172
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:250
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:507
+#, fuzzy
+#| msgid "Back to accounts"
+msgid "Back to account"
+msgstr "Retour aux comptes"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:177
+#, fuzzy
+#| msgid "New decision"
+msgid "New AML decision"
+msgstr "Nouvelle décision"
+
+#. screenid: 113
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:201
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:297
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:790
+msgid "Payto URI"
+msgstr "URI Payto"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:218
+#, fuzzy
+#| msgctxt "threshold"
+#| msgid "%1$s every %2$s"
+msgid "Step %1$s of %2$s"
+msgstr "%1$s tous les %2$s"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:236
+msgid "Decision steps"
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:245
+#, fuzzy
+#| msgid "Previous event"
+msgid "Previous step"
+msgstr "Événement précédent"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:254
+#, fuzzy
+#| msgid "Next event"
+msgid "Next step"
+msgstr "Événement suivant"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:273
+#, fuzzy
+#| msgid "System information"
+msgid "Customer information"
+msgstr "Information système"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:274
+#, fuzzy
+#| msgid ""
+#| "You can review AML information, but this officer key cannot submit "
+#| "decisions."
+msgid "Optionally add reviewed AML/KYC information to this decision."
+msgstr ""
+"Vous pouvez consulter les informations AML, mais cette clé d’agent ne peut "
+"pas soumettre de décisions."
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:279
+msgid "Review the account state derived from the available information."
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:283
+#, fuzzy
+#| msgid "Missing events"
+msgid "Reporting events"
+msgstr "Événements manquants"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:284
+msgid "Review the statistical events recorded with this decision."
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:289
+#, fuzzy
+#| msgid "Measures the customer must complete under the current policy."
+msgid ""
+"Choose actions the customer must complete after the decision is submitted."
+msgstr "Mesures que le client doit accomplir selon la politique actuelle."
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:293
+#, fuzzy
+#| msgctxt "operation type"
+#| msgid "Transaction"
+msgid "Transaction rules"
+msgstr "Transaction"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:294
+msgid "Set operation thresholds, escalation measures, and expiration behavior."
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:298
+msgid "Case disposition"
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:299
+#, fuzzy
+#| msgid "Accounts under investigation."
+msgid "Record the rationale and whether the case remains under investigation."
+msgstr "Comptes sous enquête."
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:305
+#, fuzzy
+#| msgid "Review and submit."
+msgid "Review and submit"
+msgstr "Vérifier et soumettre."
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:306
+msgid "Check the complete decision before signing and submitting it."
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:326
+#, fuzzy
+#| msgid "Decision date"
+msgid "Decision progress"
+msgstr "Date de la décision"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:407
+#, fuzzy
+#| msgid "Failed to load account decisions."
+msgid "Loading account decision"
+msgstr "Impossible de charger les décisions du compte."
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:418
+#, fuzzy
+#| msgid "Decision for account:"
+msgid "Decision for account"
+msgstr "Décision pour le compte :"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:425
+#, fuzzy
+#| msgid "Decision for account:"
+msgid "Decision for wallet account"
+msgstr "Décision pour le compte :"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:431
+#, fuzzy
+#| msgid "Decision for bank account:"
+msgid "Decision for bank account"
+msgstr "Décision pour le compte bancaire :"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:107
+msgid "Enter a valid HTTP or HTTPS URL."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:114
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:176
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:218
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:259
+msgid "Development settings"
+msgstr "Paramètres de développement"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:117
+msgid ""
+"These browser-local settings are intended for development and "
+"troubleshooting."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:132
+#, fuzzy
+#| msgid "Exchange hostname"
+msgid "Exchange connection"
+msgstr "Nom d'hôte de l'exchange"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:135
+msgid ""
+"Changing the exchange reloads the application. The override is stored only "
+"in this browser."
+msgstr ""
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:147
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:97
+msgid "Exchange base URL"
+msgstr "URL de base de l’exchange"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:166
+msgid "Leave empty to use the configured URL: %1$s"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:170
+msgid "Leave empty to derive the exchange URL from this page."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:184
+msgid "Currently connected to"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:196
+msgid "Apply and reload"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:207
+msgid "Use configured URL"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:214
+msgid "Preferences"
+msgstr "Préférences"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:221
+msgid "AML SPA dialect"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:236
+#, fuzzy
+#| msgid "Welcome to the exchange configuration"
+msgid "Use exchange configuration"
+msgstr "Bienvenue dans la configuration de l'exchange"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:240
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:44
+msgid "Testing"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:244
+msgid ""
+"Override how this web interface presents dialect-specific AML rules and "
+"properties. The override is stored only in this browser."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:262
+#, fuzzy
+msgid "Show debug information"
+msgstr "Afficher les informations de débogage"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:45
+msgid "Fallback dialect for development and testing."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:52
+msgid "TOPS"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:53
+msgid "Taler Operations deployment for Swiss AML processes."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:56
+msgid "File note"
+msgstr "Note au dossier"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:57
+#, fuzzy
+#| msgid "Current note on the GwG file"
+msgid "Current note on the GwG file."
+msgstr "Note actuelle sur le dossier GwG"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:58
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:64
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:112
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:124
+msgid "Text"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:62
+msgid "Customer label"
+msgstr "Libellé du client"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:68
+msgid "Account open"
+msgstr "Compte ouvert"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:69
+#, fuzzy
+#| msgid "Is the account active for deposit and payments?"
+msgid "Whether the account is active for deposits and payments."
+msgstr "Le compte est-il actif pour les dépôts et les paiements ?"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:70
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:76
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:82
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:88
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:94
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:100
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:106
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:142
+#, fuzzy
+#| msgid "boolean"
+msgid "Boolean"
+msgstr "booléen"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:74
+msgid "Domestic PEP"
+msgstr "PPE nationale"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:75
+msgid "Whether the customer is a domestic politically exposed person."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:80
+msgid "Foreign PEP"
+msgstr "PPE étrangère"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:81
+msgid "Whether the customer is a foreign politically exposed person."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:86
+msgid "International-organization PEP"
+msgstr "PPE d’une organisation internationale"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:87
+msgid ""
+"Whether the customer is a politically exposed person associated with an "
+"international organization."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:92
+msgid "High-risk customer"
+msgstr "Client à haut risque"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:93
+#, fuzzy
+#| msgid "Measures the customer must complete under the current policy."
+msgid "Whether the customer is classified as high risk."
+msgstr "Mesures que le client doit accomplir selon la politique actuelle."
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:98
+msgid "High-risk country"
+msgstr "Pays à haut risque"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:99
+msgid "Whether the customer is associated with a high-risk country."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:104
+msgid "Account idle"
+msgstr "Compte inactif"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:105
+msgid "Whether the account has been marked as idle."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:110
+#, fuzzy
+#| msgid "Investigation trigger"
+msgid "Investigation trigger"
+msgstr "Déclencheur de l’enquête"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:111
+#, fuzzy
+#| msgid "Informal reason why the AML investigation was triggered"
+msgid "Informal reason why the AML investigation was triggered."
+msgstr "Raison informelle du déclenchement de l'enquête AML"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:116
+#, fuzzy
+#| msgid "Investigation"
+msgid "Investigation state"
+msgstr "Enquête"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:117
+#, fuzzy
+#| msgid "The MROS reporting state for the account."
+msgid "Special-clarification and MROS reporting state for the account."
+msgstr "L'état de déclaration MROS du compte."
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:118
+#, fuzzy
+#| msgid "Operation"
+msgid "Enumeration"
+msgstr "Opération"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:122
+#, fuzzy
+#| msgid "Sanctions-list best match"
+msgid "Sanction-list best match"
+msgstr "Meilleure correspondance dans la liste de sanctions"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:123
+#, fuzzy
+#| msgid "Identifies the sanction list entry that the account matched against"
+msgid ""
+"Sanction-list entry that best matched the account, regardless of match "
+"quality."
+msgstr ""
+"Identifie l'entrée de la liste de sanctions à laquelle le compte correspond"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:128
+#, fuzzy
+#| msgid "Sanctions-list rating"
+msgid "Sanction-list rating"
+msgstr "Évaluation de la correspondance dans la liste de sanctions"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:129
+msgid "Score from 0 (no match) to 1,000,000,000 (best match)."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:130
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:136
+#, fuzzy
+#| msgid "Internal"
+msgid "Integer"
+msgstr "Interne"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:134
+#, fuzzy
+#| msgid "Sanctions-list confidence"
+msgid "Sanction-list confidence"
+msgstr "Confiance de la correspondance dans la liste de sanctions"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:135
+msgid ""
+"Score from 0 (no supporting data) to 1,000,000,000 (highest confidence)."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:140
+#, fuzzy
+#| msgid "Suppress sanctions-list match"
+msgid "Suppress sanction-list match"
+msgstr "Masquer la correspondance dans la liste de sanctions"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:141
+msgid ""
+"Whether this account's sanction-list hit is treated as a false positive."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:148
+#, fuzzy
+#| msgid "Account open"
+msgid "Account opened"
+msgstr "Compte ouvert"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:149
+msgid "Recorded when an account changes to open."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:153
+#, fuzzy
+#| msgid "Account case"
+msgid "Account closed"
+msgstr "Dossier du compte"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:154
+msgid "Recorded when an account changes from open to closed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:158
+#, fuzzy
+#| msgid "High-risk customer"
+msgid "High-risk customer classification added"
+msgstr "Client à haut risque"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:159
+msgid ""
+"Recorded when an open account becomes classified as a high-risk customer."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:163
+#, fuzzy
+#| msgid "High-risk customer"
+msgid "High-risk customer classification removed"
+msgstr "Client à haut risque"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:164
+msgid "Recorded when the high-risk customer classification is removed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:168
+#, fuzzy
+#| msgid "High-risk country"
+msgid "High-risk country classification added"
+msgstr "Pays à haut risque"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:169
+msgid ""
+"Recorded when an open account becomes associated with a high-risk country."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:173
+msgid "High-risk country classification removed"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:174
+msgid "Recorded when the high-risk country classification is removed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:178
+msgid "PEP classification added"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:179
+msgid "Recorded when an open account becomes associated with any PEP category."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:183
+#, fuzzy
+#| msgid "No justification was recorded."
+msgid "PEP classification removed"
+msgstr "Aucune justification n’a été enregistrée."
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:184
+msgid ""
+"Recorded when the account is no longer associated with any PEP category."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:188
+msgid "Foreign PEP classification added"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:189
+msgid "Recorded when an open account becomes associated with a foreign PEP."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:193
+msgid "Foreign PEP classification removed"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:194
+msgid "Recorded when the foreign PEP classification is removed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:198
+msgid "Domestic PEP classification added"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:199
+msgid "Recorded when an open account becomes associated with a domestic PEP."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:203
+msgid "Domestic PEP classification removed"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:204
+msgid "Recorded when the domestic PEP classification is removed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:208
+#, fuzzy
+#| msgid "International-organization PEP"
+msgid "International-organization PEP classification added"
+msgstr "PPE d’une organisation internationale"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:209
+#, fuzzy
+#| msgid "Does account belong to an international-organization PEP?"
+msgid ""
+"Recorded when an open account becomes associated with an international-"
+"organization PEP."
+msgstr "Le compte appartient-il à une PPE d'organisation internationale ?"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:213
+#, fuzzy
+#| msgid "International-organization PEP"
+msgid "International-organization PEP classification removed"
+msgstr "PPE d’une organisation internationale"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:214
+msgid ""
+"Recorded when the international-organization PEP classification is removed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:218
+msgid "Simple suspicion reported to MROS"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:219
+msgid "Recorded when a report is filed under Article 305ter paragraph 2 StGB."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:223
+#, fuzzy
+#| msgid "Reported substantiated suspicion"
+msgid "Substantiated suspicion reported to MROS"
+msgstr "Soupçon fondé signalé"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:224
+msgid "Recorded when a report is filed under Article 9 GwG."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:228
+#, fuzzy
+#| msgid "Investigation trigger"
+msgid "Investigation concluded"
+msgstr "Déclencheur de l’enquête"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:229
+msgid "Recorded when a pending special clarification is concluded."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:233
+#, fuzzy
+#| msgid "Investigation trigger"
+msgid "Investigation conclusion reversed"
+msgstr "Déclencheur de l’enquête"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:234
+msgid ""
+"Recorded when a previously concluded investigation returns to a non-"
+"concluded state."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:50
+msgid "Browser override"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:52
+#, fuzzy
+#| msgid "Welcome to the exchange configuration"
+msgid "Exchange configuration"
+msgstr "Bienvenue dans la configuration de l'exchange"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:53
+#, fuzzy
+#| msgid "Default rules"
+msgid "Default fallback"
+msgstr "Règles par défaut"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:59
+#, fuzzy
+#| msgid "Welcome to the exchange configuration"
+msgid "Exchange and AML configuration"
+msgstr "Bienvenue dans la configuration de l'exchange"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:62
+msgid ""
+"Exchange identity, the active AML dialect, and the checks and programs "
+"available to AML decisions."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:71
+msgid "Public information reported by this exchange."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:75
+msgid "Base URL"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:76
+msgid "Protocol"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:77
+msgid "Protocol version"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:78
+#, fuzzy
+#| msgid "Operation"
+msgid "Implementation"
+msgstr "Opération"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:80
+#, fuzzy
+#| msgid "Not opened"
+msgid "Not reported"
+msgstr "Non ouvert"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:82
+msgid "Currency"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:88
+msgid "AML dialect"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:95
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:119
+#, fuzzy
+#| msgid "Effective decision"
+msgid "Effective dialect"
+msgstr "Décision en vigueur"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:111
+#, fuzzy
+#| msgid "Configure measure"
+msgid "Configured dialect"
+msgstr "Configurer la mesure"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:114
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:504
+#, fuzzy
+#| msgid "Not opened"
+msgid "Not specified"
+msgstr "Non ouvert"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:129
+msgid "Canonical properties defined by the effective dialect."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:130
+#, fuzzy
+#| msgid "No account properties"
+msgid "This dialect does not define account properties."
+msgstr "Aucune propriété de compte"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:136
+#, fuzzy
+#| msgid "Reset to default"
+msgid "Derived events"
+msgstr "Réinitialiser par défaut"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:137
+#, fuzzy
+#| msgid "No account properties"
+msgid "Canonical events derived from account property changes."
+msgstr "Aucune propriété de compte"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:138
+msgid "This dialect does not define derived events."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:144
+#, fuzzy
+#| msgid "All measures"
+msgid "AML measures"
+msgstr "Toutes les mesures"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:145
+msgid ""
+"Checks, programs, root measures, and default rules reported by the exchange."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:213
+#, fuzzy
+#| msgctxt "threshold"
+#| msgid "%1$s every %2$s"
+msgid "%1$s entry"
+msgstr "%1$s tous les %2$s"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:214
+msgid "%1$s entries"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:277
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:289
+#, fuzzy
+msgid "Failed to load the exchange AML measures."
+msgstr "Mesures actives actuelles"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:300
+#, fuzzy
+#| msgid "The measures endpoint was not found."
+msgid "The measures endpoint is not available."
+msgstr "Le point de terminaison des mesures est introuvable."
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:306
+#, fuzzy
+#| msgid "The account state changed. Reload it and try again."
+msgid "The exchange configuration changed. Reload it and try again."
+msgstr "L’état du compte a changé. Rechargez-le et réessayez."
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:332
+#, fuzzy
+#| msgid "Required measures"
+msgid "Retry loading measures"
+msgstr "Mesures requises"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:351
+#, fuzzy
+#| msgid "Reset measure"
+msgid "Root measures"
+msgstr "Réinitialiser la mesure"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:366
+msgid "No root measures are configured."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:371
+#, fuzzy
+#| msgid "Check"
+msgid "KYC checks"
+msgstr "Vérifier"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:386
+msgid "No KYC checks are configured."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:391
+#, fuzzy
+#| msgid "Program"
+msgid "AML programs"
+msgstr "Programme"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:405
+#, fuzzy
+#| msgid "Requirements"
+msgid "Required inputs"
+msgstr "Exigences"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:413
+msgid "No AML programs are configured."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:428
+msgid "No default AML rules are configured."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:480
+#, fuzzy
+#| msgid "Check"
+msgid "KYC check"
+msgstr "Vérifier"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:484
+msgid "Built-in check that proceeds without collecting customer data."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:491
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:497
+#, fuzzy
+#| msgid "Program"
+msgid "AML program"
+msgstr "Programme"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:536
+#, fuzzy
+#| msgid "All measures"
+msgid "Fallback measure"
+msgstr "Toutes les mesures"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:602
+#, fuzzy
+#| msgid "Unavailable"
+msgid "Unavailable reference"
+msgstr "Indisponible"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:48
+msgid "Session and access"
+msgstr "Session et accès"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:51
+msgid ""
+"Review this officer's exchange access and manage the unlocked key in this "
+"browser."
+msgstr ""
+"Vérifiez l’accès de cet agent à l’exchange et gérez la clé déverrouillée "
+"dans ce navigateur."
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:66
+msgid "Officer access"
+msgstr "Accès de l’agent"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:71
+msgid "Officer name"
+msgstr "Nom de l’agent"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:77
+msgid "Permissions"
+msgstr "Autorisations"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:88
+msgid "Read-only"
+msgstr "Lecture seule"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:90
+msgid "Read and write"
+msgstr "Lecture et écriture"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:118
+msgid "Session security"
+msgstr "Sécurité de la session"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:121
+msgid "Lock the session when you leave this device unattended."
+msgstr ""
+"Verrouillez la session lorsque vous laissez cet appareil sans surveillance."
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:133
+msgid "Lock now"
+msgstr "Verrouiller maintenant"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:148
+msgid "Unlocked"
+msgstr "Déverrouillée"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:154
+msgid "Locks automatically"
+msgstr "Verrouillage automatique"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:165
+msgid "Exact time"
+msgstr "Heure exacte"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:185
+msgid "Copy public key"
+msgstr "Copier la clé publique"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:200
+msgid "Remove key from this browser"
+msgstr "Supprimer la clé de ce navigateur"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:203
+msgid ""
+"Removing this key deletes the officer key from this browser. It does not "
+"revoke or change the officer's access at the exchange. Ask the exchange "
+"operator to revoke access if needed."
+msgstr ""
+"La suppression de cette clé efface la clé de l’agent de ce navigateur. Elle "
+"ne révoque ni ne modifie l’accès de l’agent auprès de l’exchange. Demandez à "
+"l’opérateur de l’exchange de révoquer l’accès si nécessaire."
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:214
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:222
+msgid "Remove key"
+msgstr "Supprimer la clé"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:221
+msgid "Remove officer key?"
+msgstr "Supprimer la clé de l’agent ?"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:231
+msgid ""
+"This deletes the officer key from this browser. You will need to create and "
+"enroll a new key to use the AML WebUI here again."
+msgstr ""
+"Ceci efface la clé de l’agent de ce navigateur. Vous devrez créer et faire "
+"inscrire une nouvelle clé pour réutiliser l’interface web AML ici."
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:237
+msgid ""
+"This does not revoke the officer at the exchange. Ask the exchange operator "
+"to revoke its access if the key may be compromised."
+msgstr ""
+"Ceci ne révoque pas l’agent auprès de l’exchange. Demandez à l’opérateur de "
+"l’exchange de révoquer son accès si la clé est susceptible d’être compromise."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:86
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:559
+msgid "Find account"
+msgstr "Rechercher un compte"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:89
+msgid "Look up an account by its payto information or normalized payto hash."
+msgstr ""
+"Recherchez un compte à partir de ses informations payto ou de son empreinte "
+"payto normalisée."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:100
+msgid "Find by payto"
+msgstr "Rechercher par payto"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:146
+msgid "Find by normalized payto hash"
+msgstr "Rechercher par empreinte payto normalisée"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:169
+msgid "Enter a valid 52-character normalized payto hash."
+msgstr "Saisissez une empreinte payto normalisée valide de 52 caractères."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:179
+msgid "Open account"
+msgstr "Ouvrir le compte"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:214
+msgid "Failed to load account decisions."
+msgstr "Impossible de charger les décisions du compte."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:223
+msgid "Failed to load the account history."
+msgstr "Impossible de charger l’historique du compte."
+
+#. screenid: 111
+#. screenid: 110
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:228
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:82
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:268
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:66
+msgid ""
+"This session signature is invalid, contact administrator or create a new one."
+msgstr ""
+"La signature de cette session n’est pas valide. Contactez l’administrateur "
+"ou créez-en une nouvelle."
+
+#. screenid: 111
+#. screenid: 110
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:235
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:89
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:275
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:73
+msgid ""
+"The designated AML session is not known, contact administrator or create a "
+"new one."
+msgstr ""
+"La session AML indiquée est inconnue. Contactez l’administrateur ou créez-en "
+"une nouvelle."
+
+#. screenid: 111
+#. screenid: 110
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:242
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:96
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:282
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:80
+msgid ""
+"The designated AML session is not enabled, contact administrator or create a "
+"new one."
+msgstr ""
+"La session AML indiquée n’est pas activée. Contactez l’administrateur ou "
+"créez-en une nouvelle."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:268
+#, fuzzy
+#| msgid "Account not found"
+msgid "Account found"
+msgstr "Compte introuvable"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:271
+msgid ""
+"This account has an AML decision history. Open its case to review current "
+"rules, measures, attributes, and past decisions."
+msgstr ""
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:283
+#, fuzzy
+#| msgid "Open account"
+msgid "Open account case"
+msgstr "Ouvrir le compte"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:309
+msgid "Active"
+msgstr ""
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:311
+#, fuzzy
+#| msgid "Effective decision"
+msgid "No active decision"
+msgstr "Décision en vigueur"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:317
+#, fuzzy
+#| msgid "File status"
+msgid "Case status"
+msgstr "État du dossier"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:321
+#, fuzzy
+#| msgid "Investigation trigger"
+msgid "Investigation required"
+msgstr "Déclencheur de l’enquête"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:323
+#, fuzzy
+#| msgid "Investigation state"
+msgid "No investigation requested"
+msgstr "État de l’enquête"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:333
+msgid "Account not found"
+msgstr "Compte introuvable"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:335
+msgid "There is no history known for this account yet."
+msgstr "Aucun historique connu pour ce compte pour l'instant."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:350
+#, fuzzy
+#| msgid "You can make a decision for this account anyway."
+msgid "Start a decision for this account"
+msgstr "Vous pouvez tout de même prendre une décision pour ce compte."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:403
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:445
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:493
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:533
+msgid "Search"
+msgstr "Rechercher"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:575
+msgid "Taler Bank"
+msgstr "Banque Taler"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:579
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:364
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:433
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:441
+msgid "Wallet"
+msgstr "Portefeuille numérique"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:583
+msgid "Generic Payto:// URI"
+msgstr "URI Payto:// générique"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:586
+msgid "Account type"
+msgstr "Type de compte"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:596
+msgid "Should be 52 characters."
+msgstr "Doit comporter 52 caractères."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:598
+msgid "Failed to parse: %1$s"
+msgstr "Échec de l'analyse : %1$s"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:610
+msgid "Address contains invalid characters."
+msgstr "L'adresse contient des caractères invalides."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:612
+msgid "Can't mix uppercased and lowercased characters."
+msgstr "Impossible de mélanger majuscules et minuscules."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:614
+msgid "The addr checksum doesn't match."
+msgstr "La somme de contrôle de l'adresse ne correspond pas."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:616
+msgid "Missing separator or address type."
+msgstr "Séparateur ou type d'adresse manquant."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:618
+msgid "Address should have less than 90 characters."
+msgstr "L'adresse doit comporter moins de 90 caractères."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:620
+msgid "Address should have more than 6 characters."
+msgstr "L'adresse doit comporter plus de 6 caractères."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:622
+msgid "Decoding issue."
+msgstr "Problème de décodage."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:624
+msgid "Invalid data"
+msgstr "Données non valides"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:634
+msgid "Unsupported country."
+msgstr "Pays non pris en charge."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:636
+msgid "IBANs have fewer than 34 characters."
+msgstr "Les IBAN comportent moins de 34 caractères."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:638
+msgid "IBANs have more than 4 characters."
+msgstr "Les IBAN comportent plus de 4 caractères."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:640
+msgid "IBAN length is invalid for this country."
+msgstr "La longueur de l’IBAN n’est pas valide pour ce pays."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:642
+msgid "It should only contain numbers and letters."
+msgstr "Il ne doit contenir que des chiffres et des lettres."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:644
+msgid "The checksum is wrong."
+msgstr "La somme de contrôle est incorrecte."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:662
+msgid "The string should start with payto://"
+msgstr "La chaîne doit commencer par payto://"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:664
+msgid "After the target type it should follow a '/' with more information."
+msgstr ""
+"Après le type de cible, un « / » doit être suivi d'informations "
+"supplémentaires."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:666
+msgid ""
+"The target type is not supported, only x-taler-bank, taler-reserve or iban"
+msgstr ""
+"Le type de cible n'est pas pris en charge, seuls x-taler-bank, taler-reserve "
+"ou iban le sont"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:671
+msgid "IBAN is missing"
+msgstr "L'IBAN est manquant"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:673
+msgid "Bitcoin address is missing"
+msgstr "L'adresse Bitcoin est manquante"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:675
+msgid "Bank host and account is missing"
+msgstr "L'hôte bancaire et le compte sont manquants"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:677
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:679
+msgid "Exchange host and account is missing"
+msgstr "L'hôte de l'exchange et le compte sont manquants"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:681
+msgid "Ethereum address is missing"
+msgstr "L'adresse Ethereum est manquante"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:683
+msgid "Cyclos address is missing"
+msgstr "L'adresse Cyclos est manquante"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:685
+msgid "Void address is missing"
+msgstr "L’adresse void est manquante"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:693
+msgid "Invalid IBAN: %1$s"
+msgstr "IBAN invalide : %1$s"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:700
+msgid "Invalid BTC: %1$s"
+msgstr "BTC invalide : %1$s"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:705
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:728
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:741
+msgid "Invalid reserve: %1$s"
+msgstr "Réserve invalide : %1$s"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:716
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:726
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:739
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:760
+msgid "Invalid host"
+msgstr "Hôte invalide"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:718
+msgid "Invalid account"
+msgstr "Compte invalide"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:752
+msgid "Invalid address"
+msgstr "Adresse invalide"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:791
+msgid "As defined by RFC 8905"
+msgstr "Tel que défini par la RFC 8905"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:792
+msgid "payto://"
+msgstr "payto://"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:807
+msgid "International Bank Account Number"
+msgstr "Numéro de compte bancaire international"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:808
+msgid "DE1231231231"
+msgstr "DE1231231231"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:820
+msgid "Host"
+msgstr "Hôte"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:821
+msgid "Exchange hostname"
+msgstr "Nom d'hôte de l'exchange"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:822
+msgid "exchange.taler.net"
+msgstr "exchange.taler.net"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:827
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:874
+msgid "Remove last '/'"
+msgstr "Retirer le « / » final"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:829
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:846
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:426
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:472
+msgid "Invalid value"
+msgstr "Valeur invalide"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:837
+msgid "ID"
+msgstr "ID"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:838
+msgid "Wallet reserve public key"
+msgstr "Clé publique de réserve du portefeuille"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:839
+msgid "abcdef1235"
+msgstr "abcdef1235"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:844
+msgid "Should be 52 characters"
+msgstr "Doit comporter 52 caractères"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:860
+msgid "Bank account identification"
+msgstr "Identification du compte bancaire"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:861
+msgid "DE123123123"
+msgstr "DE123123123"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:867
+msgid "Hostname"
+msgstr "Nom d'hôte"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:868
+msgid "Without the scheme, may include subpath: bank.com, bank.com/path/"
+msgstr "Sans le schéma, peut inclure un sous-chemin : bank.com, bank.com/path/"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:869
+msgid "bank.demo.taler.net"
+msgstr "bank.demo.taler.net"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:876
+msgid "Invalid hostname"
+msgstr "Nom d'hôte invalide"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:68
+msgid "Failed to load account information."
+msgstr "Impossible de charger les informations du compte."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:77
+msgid "Failed to load the account information."
+msgstr ""
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:115
+msgid "Collection event not found"
+msgstr "Événement de collecte introuvable"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:117
+msgid "There is no collection event with ID %1$s for this account."
+msgstr ""
+"Il n’existe aucun événement de collecte portant l’identifiant %1$s pour ce "
+"compte."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:129
+msgid "Attributes unavailable"
+msgstr "Attributs indisponibles"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:131
+msgid "The collection event does not contain readable attributes."
+msgstr "L’événement de collecte ne contient aucun attribut lisible."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:148
+msgid "Form identifier missing"
+msgstr "Identifiant du formulaire manquant"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:150
+msgid "The collected information does not identify the form used to create it."
+msgstr ""
+"Les informations collectées n’indiquent pas le formulaire utilisé pour les "
+"créer."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:165
+msgid "Form not available"
+msgstr "Formulaire indisponible"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:167
+msgid "Form %1$s is not configured in this AML Web UI."
+msgstr "Le formulaire %1$s n’est pas configuré dans cette interface Web AML."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:255
+#, fuzzy
+#| msgid "Collected information"
+msgid "Collected AML/KYC information"
+msgstr "Informations collectées"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:262
+#, fuzzy
+#| msgid "Forms"
+msgid "Form"
+msgstr "Formulaires"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:267
+#, fuzzy
+#| msgid "Collected information"
+msgid "Collected"
+msgstr "Informations collectées"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:270
+msgid "Source"
+msgstr ""
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:274
+#, fuzzy
+#| msgid "Custom properties"
+msgid "Customer process"
+msgstr "Propriétés personnalisées"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:277
+#, fuzzy
+#| msgid "Events"
+msgid "Event ID"
+msgstr "Événements"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:284
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:292
+msgid "Different form version"
+msgstr "Version de formulaire différente"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:285
+msgid ""
+"The collected information does not identify the form version used. The "
+"latest configured version is shown and field labels may differ from those "
+"used at collection time."
+msgstr ""
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:293
+#, fuzzy
+#| msgid "Form %1$s is not configured in this AML Web UI."
+msgid ""
+"Form version %1$s is not configured in this AML Web UI. Version %2$s is "
+"shown and field labels may differ."
+msgstr "Le formulaire %1$s n’est pas configuré dans cette interface Web AML."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:301
+#, fuzzy
+#| msgid "Collected information"
+msgid "Collected information events"
+msgstr "Informations collectées"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:305
+#, fuzzy
+#| msgid "Next event"
+msgid "Older event"
+msgstr "Événement suivant"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:316
+#, fuzzy
+#| msgid "Next event"
+msgid "Newer event"
+msgstr "Événement suivant"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:329
+#, fuzzy
+#| msgid "Invalid attributes"
+msgid "Submitted values"
+msgstr "Attributs invalides"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:369
+#, fuzzy
+#| msgid "Officer name"
+msgid "Officer view"
+msgstr "Nom de l’agent"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:371
+#, fuzzy
+#| msgid "Customer-visible"
+msgid "Customer view"
+msgstr "Visible par le client"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:372
+msgid "JSON view"
+msgstr ""
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:403
+#, fuzzy
+#| msgid "System information"
+msgid "Submitted information view"
+msgstr "Information système"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:109
+msgid "Incoming"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:113
+msgid "Outgoing"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:117
+msgid "KYC authorization"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:127
+msgid "Wallet credits (P2P)"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:140
+#, fuzzy
+#| msgid "Transfers history"
+msgid "Transfer category"
+msgstr "Historique des transferts"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:147
+msgid "Minimum amount"
+msgstr "Montant minimum"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:148
+msgid "All amounts below the given threshold will be filtered."
+msgstr "Tous les montants inférieurs au seuil donné seront filtrés."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:182
+#, fuzzy
+#| msgid "Exchange hostname"
+msgid "Exchange transfer activity"
+msgstr "Nom d'hôte de l'exchange"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:188
+#, fuzzy
+#| msgid "Transfers history"
+msgid "Wallet credit activity"
+msgstr "Historique des transferts"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:190
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:198
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:241
+#, fuzzy
+#| msgid "Transfers history"
+msgid "Transfer activity"
+msgstr "Historique des transferts"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:196
+#, fuzzy
+#| msgid "Transfers history for account"
+msgid "Transfer activity for account"
+msgstr "Historique des transferts du compte"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:204
+msgid ""
+"Inspect successful P2P credits received by this wallet. Requests that were "
+"not paid are not shown."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:209
+msgid ""
+"Inspect effective bank transfers observed by the exchange. Credit transfers "
+"are incoming, debit transfers are outgoing, and bounced or drain transfers "
+"are not included."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:215
+msgid ""
+"Inspect effective transfers observed by the exchange. Incoming, outgoing, "
+"and KYC authorization entries are bank transfers. Wallet credits are "
+"successful P2P transfers into wallets."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:233
+#, fuzzy
+#| msgid "Transfers history"
+msgid "Transfer filters"
+msgstr "Historique des transferts"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:254
+#, fuzzy
+msgid "Failed to load transfer list."
+msgstr "Échec de l'analyse : %1$s"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:263
+msgid "Failed to load the transfer list."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:299
+msgid "Select transaction type"
+msgstr "Sélectionner le type de transaction"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:300
+msgid "Please select a transaction type to show transactions."
+msgstr ""
+"Veuillez sélectionner un type de transaction pour afficher les transactions."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:314
+#, fuzzy
+#| msgid "No transfers yet."
+msgid "No wallet credits yet."
+msgstr "Aucun transfert pour l'instant."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:315
+msgid "No transfers yet."
+msgstr "Aucun transfert pour l'instant."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:319
+#, fuzzy
+#| msgid "There are no transfers for this account."
+msgid "There are no P2P credits for this wallet."
+msgstr "Il n'y a aucun transfert pour ce compte."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:323
+#, fuzzy
+#| msgid ""
+#| "There are no transfers reported to the exchange with the current "
+#| "threshold."
+msgid ""
+"There are no wallet credits reported to the exchange with the current "
+"threshold."
+msgstr "Il n'y a aucun transfert signalé à l'exchange avec le seuil actuel."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:328
+msgid "There are no transfers for this account."
+msgstr "Il n'y a aucun transfert pour ce compte."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:332
+msgid ""
+"There are no transfers reported to the exchange with the current threshold."
+msgstr "Il n'y a aucun transfert signalé à l'exchange avec le seuil actuel."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:343
+msgid "Unknown date"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:355
+msgid "Time"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:359
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:406
+msgid "Amount"
+msgstr "Montant"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:393
+msgid "Unknown time"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:410
+#, fuzzy
+#| msgid "Credit"
+msgid "credited"
+msgstr "Crédit"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:412
+msgid "sent"
+msgstr "envoyé"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:413
+msgid "received"
+msgstr "reçu"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:443
+msgid "to"
+msgstr "à"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:444
+msgid "from"
+msgstr "de"
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:165
+msgid "This exchange is not compatible with the AML WebUI."
+msgstr "Cet exchange n’est pas compatible avec l’interface Web AML."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:167
+msgid ""
+"Officer identity and permissions require exchange protocol v40 or newer."
+msgstr ""
+"L’identité et les autorisations de l’agent nécessitent le protocole "
+"d’exchange v40 ou une version ultérieure."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:191
+msgid "Verifying that this public key is enrolled by the exchange."
+msgstr ""
+"Vérification de l’inscription de cette clé publique auprès de l’exchange."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:278
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:331
+msgid "Read-only officer access"
+msgstr "Accès d’agent en lecture seule"
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:279
+msgid ""
+"You can review AML information, but this officer key cannot submit decisions."
+msgstr ""
+"Vous pouvez consulter les informations AML, mais cette clé d’agent ne peut "
+"pas soumettre de décisions."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:332
+msgid "This officer key cannot create or submit AML decisions."
+msgstr "Cette clé d’agent ne peut pas créer ni soumettre de décisions AML."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:340
+msgid "Return to account"
+msgstr "Revenir au compte"
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:466
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:475
+msgid "Failed to load the active AML decision."
+msgstr "Impossible de charger la décision AML active."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:484
+msgid "The account was not found."
+msgstr "Le compte est introuvable."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:488
+msgid "The account state changed. Reload it and try again."
+msgstr "L’état du compte a changé. Rechargez-le et réessayez."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:511
+msgid ""
+"The payto URI does not belong to this account. Return to the account search "
+"and start the decision again."
+msgstr ""
+"L’URI payto n’appartient pas à ce compte. Revenez à la recherche de comptes "
+"et recommencez la décision."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:571
+#, fuzzy
+#| msgid "AML navigation"
+msgid "AML configuration"
+msgstr "Navigation AML"
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:577
+msgid "Session"
+msgstr "Session"
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:585
+msgid "AML navigation"
+msgstr "Navigation AML"
+
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:49
+#, fuzzy
+msgid "Failed to load server measures."
+msgstr "Mesures serveur"
+
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:61
+#, fuzzy
+msgid "Failed to load the measures"
+msgstr "Mesures actives actuelles"
+
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:102
+msgid "Measures"
+msgstr "Mesures"
+
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:105
+#, fuzzy
+msgid "A list of all the predefined measures you can use."
+msgstr ""
+"Une liste de toutes les mesures prédéfinies qui peuvent être utilisées."
+
+#~ msgid "AML officer justification"
+#~ msgstr "Justification de l'agent AML"
+
+#~ msgid "Effective policy"
+#~ msgstr "Politique en vigueur"
+
+#~ msgid "Account assessment"
+#~ msgstr "Évaluation du compte"
+
+#~ msgid "Properties recorded by AML officers for this account."
+#~ msgstr "Propriétés enregistrées par les agents AML pour ce compte."
+
+#~ msgid "Account assessment could not be loaded"
+#~ msgstr "Impossible de charger l’évaluation du compte"
+
+#~ msgid "No assessment properties have been recorded for this account."
+#~ msgstr "Aucune propriété d’évaluation n’a été enregistrée pour ce compte."
+
+#~ msgid "Currently applied rules"
+#~ msgstr "Règles actuellement appliquées"
+
+#~ msgid ""
+#~ "This account has no account-specific decision. The exchange default rules "
+#~ "currently apply."
+#~ msgstr ""
+#~ "Ce compte n’a pas de décision spécifique. Les règles par défaut de "
+#~ "l’échange s’appliquent actuellement."
+
+#, fuzzy
+#~ msgid "Keep case under investigation"
+#~ msgstr "Pas sous enquête"
+
+#~ msgid "Account views"
+#~ msgstr "Vues des comptes"
+
+#~ msgid "Date"
+#~ msgstr "Date"
+
+#~ msgid "Show transfers"
+#~ msgstr "Afficher les transferts"
+
+#, fuzzy
+#~ msgid "View decision history"
+#~ msgstr "Historique des décisions"
+
+#~ msgid "Save PDF"
+#~ msgstr "Enregistrer le PDF"
+
+#~ msgid "Manual review required"
+#~ msgstr "Examen manuel requis"
+
+#~ msgid "At a glance"
+#~ msgstr "Vue d’ensemble"
+
+#~ msgid "Requirements present"
+#~ msgstr "Exigences présentes"
+
+#~ msgid "Current assessment and policy"
+#~ msgstr "Évaluation et politique actuelles"
+
+#~ msgid "The current account properties and effective AML rules."
+#~ msgstr "Les propriétés actuelles du compte et les règles AML en vigueur."
+
+#, fuzzy
+#~ msgid "Property"
+#~ msgstr "Propriétés"
+
+#~ msgid "The officer session signature is invalid."
+#~ msgstr "La signature de la session de l’agent AML n’est pas valide."
+
+#~ msgid "The requested AML account was not found."
+#~ msgstr "Le compte AML demandé est introuvable."
+
+#~ msgid "The officer session is disabled or the account state changed."
+#~ msgstr ""
+#~ "La session de l’agent AML est désactivée ou l’état du compte a changé."
+
+#, fuzzy
+#~ msgid "Account audit trail"
+#~ msgstr "Filtres des comptes"
+
+#~ msgid "(all)"
+#~ msgstr "(tous)"
+
+#~ msgid "Info"
+#~ msgstr "Info"
+
+#~ msgid "Will show information to the user."
+#~ msgstr "Affichera des informations à l'utilisateur."
+
+#~ msgid ""
+#~ "The account isn't a wallet and there are wallet operation's limits which "
+#~ "may trigger actions that are not required: %1$s"
+#~ msgstr ""
+#~ "Le compte n'est pas un portefeuille numérique et il existe des limites "
+#~ "d'opérations de portefeuille susceptibles de déclencher des actions non "
+#~ "requises : %1$s"
+
+#~ msgid ""
+#~ "The account is a wallet and there are wallet operation's limits which are "
+#~ "not limited: %1$s"
+#~ msgstr ""
+#~ "Le compte est un portefeuille numérique et il existe des limites "
+#~ "d'opérations de portefeuille qui ne sont pas limitées : %1$s"
+
+#~ msgid "New rules"
+#~ msgstr "Nouvelles règles"
+
+#~ msgid "Set rules to default"
+#~ msgstr "Rétablir les règles par défaut"
+
+#~ msgid "Behavior on rule expiration"
+#~ msgstr "Comportement à l'expiration de la règle"
+
+#~ msgid ""
+#~ "Events based on properties and new attributes that should be triggered"
+#~ msgstr ""
+#~ "Événements basés sur des propriétés et de nouveaux attributs qui doivent "
+#~ "être déclenchés"
+
+#~ msgid "Others"
+#~ msgstr "Autres"
+
+#~ msgid "Custom list"
+#~ msgstr "Liste personnalisée"
+
+#~ msgid "Events without built-in support."
+#~ msgstr "Événements sans prise en charge intégrée."
+
+#~ msgid "These measures will ask the customer for information."
+#~ msgstr "Ces mesures demanderont des informations au client."
+
+#~ msgid ""
+#~ "Select a form to submit new information about the customer or continue to "
+#~ "the next step"
+#~ msgstr ""
+#~ "Sélectionnez un formulaire pour soumettre de nouvelles informations sur "
+#~ "le client ou passez à l'étape suivante"
+
+#~ msgid "Form:"
+#~ msgstr "Formulaire :"
+
+#~ msgid "Keep investigation?"
+#~ msgstr "Conserver l'enquête ?"
+
+#~ msgid "Full name of the account holder"
+#~ msgstr "Nom complet du titulaire du compte"
+
+#~ msgid "Update"
+#~ msgstr "Modifier"
+
+#~ msgid "Remove"
+#~ msgstr "Supprimer"
+
+#~ msgid "Show complete form"
+#~ msgstr "Afficher le formulaire complet"
+
+#~ msgid "Show as verification"
+#~ msgstr "Afficher comme vérification"
+
+#~ msgid "Only required when no check is specified"
+#~ msgstr "Requis uniquement lorsqu'aucune vérification n'est spécifiée"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:762
-msgid "International Bank Account Number"
-msgstr "Numéro de compte bancaire international"
+#~ msgid "Without a check the program will run automatically"
+#~ msgstr "Sans vérification, le programme s'exécutera automatiquement"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:763
-msgid "DE1231231231"
-msgstr "DE1231231231"
+#~ msgid "It should be a number"
+#~ msgstr "Cela doit être un nombre"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:775
-msgid "Host"
-msgstr "Hôte"
+#~ msgid "It should be a safe integer"
+#~ msgstr "Cela doit être un entier sûr"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:776
-msgid "Exchange hostname"
-msgstr "Nom d'hôte de l'exchange"
+#~ msgid "Server measures"
+#~ msgstr "Mesures serveur"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:777
-msgid "exchange.taler.net"
-msgstr "exchange.taler.net"
+#~ msgid "New measures"
+#~ msgstr "Nouvelles mesures"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:782
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:829
-msgid "Remove last '/'"
-msgstr "Retirer le « / » final"
+#~ msgid ""
+#~ "Measures that are available/executed directly after the decision is "
+#~ "confirmed."
+#~ msgstr ""
+#~ "Mesures disponibles/exécutées directement après la confirmation de la "
+#~ "décision."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:784
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:801
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:332
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:376
-msgid "Invalid value"
-msgstr "Valeur invalide"
+#, fuzzy
+#~ msgid ""
+#~ "The session is disabled or a more recent decision was already submitted."
+#~ msgstr "Agent désactivé ou décision plus récente déjà soumise."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:792
-msgid "ID"
-msgstr "ID"
+#, fuzzy
+#~ msgid ""
+#~ "This decision declares that the MROS report has concluded. Please make "
+#~ "sure that this is the case"
+#~ msgstr ""
+#~ "Cette décision déclare que le rapport MROS est conclu. Veuillez vous "
+#~ "assurer que c'est bien le cas"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:793
-msgid "Wallet reserve public key"
-msgstr "Clé publique de réserve du portefeuille"
+#~ msgid "I want to check first!"
+#~ msgstr "Je veux d'abord vérifier !"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:794
-msgid "abcdef1235"
-msgstr "abcdef1235"
+#~ msgid ""
+#~ "Deadline should specify when this rules ends and what is the next "
+#~ "measures to apply after expiration."
+#~ msgstr ""
+#~ "L'échéance doit préciser quand cette règle se termine et quelles sont les "
+#~ "prochaines mesures à appliquer après expiration."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:799
-msgid "Should be 52 characters"
-msgstr "Doit comporter 52 caractères"
+#~ msgid "Can't make a decision without rules."
+#~ msgstr "Impossible de prendre une décision sans règles."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:814
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:268
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:338
-msgid "Account"
-msgstr "Compte"
+#~ msgid "Missing active measure"
+#~ msgstr "Mesure active manquante"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:815
-msgid "Bank account identification"
-msgstr "Identification du compte bancaire"
+#~ msgid "You should specify in the measure section."
+#~ msgstr "Vous devez le préciser dans la section des mesures."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:816
-msgid "DE123123123"
-msgstr "DE123123123"
+#~ msgid "You should specify in the properties section."
+#~ msgstr "Vous devez le préciser dans la section des propriétés."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:822
-msgid "Hostname"
-msgstr "Nom d'hôte"
+#~ msgid "You should specify in the events section."
+#~ msgstr "Vous devez le préciser dans la section des événements."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:823
-msgid "Without the scheme, may include subpath: bank.com, bank.com/path/"
-msgstr "Sans le schéma, peut inclure un sous-chemin : bank.com, bank.com/path/"
+#~ msgid "Missing justification"
+#~ msgstr "Justification manquante"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:824
-msgid "bank.demo.taler.net"
-msgstr "bank.demo.taler.net"
+#~ msgid ""
+#~ "You should check form errors or submit a decision without attributes."
+#~ msgstr ""
+#~ "Vous devez vérifier les erreurs du formulaire ou soumettre une décision "
+#~ "sans attributs."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:831
-msgid "Invalid hostname"
-msgstr "Nom d'hôte invalide"
+#~ msgid "Clear"
+#~ msgstr "Effacer"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:71
-msgid "Failed to load the account information."
-msgstr ""
+#~ msgid "Attributes"
+#~ msgstr "Attributs"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:198
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:204
-msgid "Different form version"
-msgstr "Version de formulaire différente"
+#~ msgid "Add more information about the customer"
+#~ msgstr "Ajouter des informations supplémentaires sur le client"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:199
-msgid "The collected information don't have the form version used."
-msgstr ""
-"Les informations collectées n'indiquent pas la version du formulaire "
-"utilisée."
+#~ msgid "Rules"
+#~ msgstr "Règles"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:205
-msgid ""
-"The collected information used the form version \"%1$s \" but is not "
-"available."
-msgstr ""
-"Les informations collectées utilisaient la version de formulaire « %1$s » "
-"mais elle n'est pas disponible."
+#~ msgid "Set the limit of the operations"
+#~ msgstr "Définir la limite des opérations"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:217
-msgid "Case details"
-msgstr "Détails du dossier"
+#~ msgid "Trigger notifications."
+#~ msgstr "Déclencher des notifications."
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:231
-msgid "Next event"
-msgstr "Événement suivant"
+#~ msgid "Ask the customer to take action."
+#~ msgstr "Demander au client de prendre une mesure."
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:245
-msgid "Previous event"
-msgstr "Événement précédent"
+#~ msgid "Flag the current account state."
+#~ msgstr "Signaler l'état actuel du compte."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:66
-msgid "Direction"
-msgstr "Direction"
+#~ msgid "loading..."
+#~ msgstr "chargement..."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:69
-msgid "Credit"
-msgstr "Crédit"
+#~ msgid "Decision for wallet:"
+#~ msgstr "Décision pour le portefeuille :"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:73
-msgid "Debit"
-msgstr "Débit"
+#~ msgid "Check account details"
+#~ msgstr "Vérifier les détails du compte"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:77
-msgid "KYC Auth"
-msgstr "Authentification KYC"
+#~ msgid "Account most recent decisions"
+#~ msgstr "Décisions les plus récentes du compte"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:85
-msgid "Minimum amount"
-msgstr "Montant minimum"
+#~ msgid "When"
+#~ msgstr "Quand"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:86
-msgid "All amounts below the given threshold will be filtered."
-msgstr "Tous les montants inférieurs au seuil donné seront filtrés."
+#~ msgid "LATEST"
+#~ msgstr "DERNIÈRE"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:114
-#, fuzzy
-msgid "Failed to load transfer list."
-msgstr "Échec de l'analyse : %1$s"
+#~ msgid "ACTIVE"
+#~ msgstr "ACTIVE"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:123
-msgid "Failed to load the transfer list."
-msgstr ""
+#~ msgid "Requires investigation"
+#~ msgstr "Nécessite une enquête"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:160
-msgid "Select transaction type"
-msgstr "Sélectionner le type de transaction"
+#~ msgid "The collected information don't have the form version used."
+#~ msgstr ""
+#~ "Les informations collectées n'indiquent pas la version du formulaire "
+#~ "utilisée."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:161
-msgid "Please select a transaction type to show transactions."
-msgstr ""
-"Veuillez sélectionner un type de transaction pour afficher les transactions."
+#~ msgid ""
+#~ "The collected information used the form version \"%1$s \" but is not "
+#~ "available."
+#~ msgstr ""
+#~ "Les informations collectées utilisaient la version de formulaire « %1$s » "
+#~ "mais elle n'est pas disponible."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:176
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:234
-msgid "Transfers history for account"
-msgstr "Historique des transferts du compte"
+#~ msgid "Case details"
+#~ msgstr "Détails du dossier"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:188
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:246
-msgid "Transfers history"
-msgstr "Historique des transferts"
+#~ msgid "Previous event"
+#~ msgstr "Événement précédent"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:195
-msgid "No transfers yet."
-msgstr "Aucun transfert pour l'instant."
+#~ msgid "Direction"
+#~ msgstr "Direction"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:197
-msgid "There are no transfers for this account."
-msgstr "Il n'y a aucun transfert pour ce compte."
+#~ msgid "Debit"
+#~ msgstr "Débit"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:201
-msgid ""
-"There are no transfers reported to the exchange with the current threshold."
-msgstr "Il n'y a aucun transfert signalé à l'exchange avec le seuil actuel."
+#~ msgid "KYC Auth"
+#~ msgstr "Authentification KYC"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:260
-msgid "Date"
-msgstr "Date"
+#~ msgid "Previous AML decisions that are no longer active."
+#~ msgstr "Décisions AML antérieures qui ne sont plus actives."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:264
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:310
-msgid "Amount"
-msgstr "Montant"
+#~ msgid "The account has no KYC information."
+#~ msgstr "Le compte ne contient aucune information KYC."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:314
-msgid "sent"
-msgstr "envoyé"
+#~ msgid "Download KYC report"
+#~ msgstr "Télécharger le rapport KYC"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:315
-msgid "received"
-msgstr "reçu"
+#~ msgid "KYC report ready"
+#~ msgstr "Rapport KYC prêt"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:348
-msgid "to"
-msgstr "à"
+#~ msgid "Use testing dialect"
+#~ msgstr "Utiliser le dialecte de test"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:349
-msgid "from"
-msgstr "de"
+#~ msgid "Since"
+#~ msgstr "Depuis"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:92
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:101
-msgid "Welcome to the exchange configuration"
-msgstr "Bienvenue dans la configuration de l'exchange"
+#~ msgid "Already completed."
+#~ msgstr "Déjà complété."
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:372
-msgid "Transfers"
-msgstr "Transferts"
+#~ msgid "Case history for selected account"
+#~ msgstr "Historique des dossiers pour le compte sélectionné"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:379
-msgid "Profile"
-msgstr "Profil"
+#~ msgid "ID:"
+#~ msgstr "ID :"
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:49
-#, fuzzy
-msgid "Failed to load server measures."
-msgstr "Mesures serveur"
+#~ msgid "Payto:"
+#~ msgstr "Payto :"
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:61
-#, fuzzy
-msgid "Failed to load the measures"
-msgstr "Mesures actives actuelles"
+#~ msgid "Export as PDF"
+#~ msgstr "Exporter en PDF"
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:105
-#, fuzzy
-msgid "A list of all the predefined measures you can use."
-msgstr ""
-"Une liste de toutes les mesures prédéfinies qui peuvent être utilisées."
+#~ msgid "Click here to save the file in your computer."
+#~ msgstr "Cliquez ici pour enregistrer le fichier sur votre ordinateur."
-#. screenid: 122
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:165
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:174
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:214
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:222
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:90
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:99
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:62
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:71
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:191
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:200
-msgid "Failed to load available measures."
-msgstr "Impossible de charger les mesures disponibles."
+#~ msgid "Every attribute collection event (via form upload or KYC provider)."
+#~ msgstr ""
+#~ "Chaque événement de collecte d'attributs (via téléversement de formulaire "
+#~ "ou prestataire KYC)."
-#. screenid: 122
-#. screenid: 102
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:179
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:104
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:76
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:205
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:403
-msgid "The officer session is invalid."
-msgstr "La session de l’agent AML n’est pas valide."
+#~ msgid ""
+#~ "There is no decision for this account yet. The account is limited by the "
+#~ "default rules."
+#~ msgstr ""
+#~ "Aucune décision n'a encore été prise pour ce compte. Le compte est limité "
+#~ "par les règles par défaut."
-#. screenid: 122
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:183
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:80
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:209
-msgid "The measures endpoint was not found."
-msgstr "Le point de terminaison des mesures est introuvable."
+#~ msgid "No AML history found"
+#~ msgstr "Aucun historique AML trouvé"
-#. screenid: 122
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:189
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:114
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:86
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:215
-msgid "The officer session is disabled."
-msgstr "La session de l’agent AML est désactivée."
+#~ msgid "Current active measures"
+#~ msgstr "Mesures actives actuelles"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:182
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:190
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:389
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:398
-msgid "Failed to load the active AML decision."
-msgstr "Impossible de charger la décision AML active."
+#, fuzzy
+#~ msgid "There are no accounts in the resultset."
+#~ msgstr "Il n'y a pas encore de règles pour ce compte."
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:488
-msgid "The officer session signature is invalid."
-msgstr "La signature de la session de l’agent AML n’est pas valide."
+#, fuzzy
+#~ msgid "Failed to load the accounts"
+#~ msgstr "Historique des dossiers pour le compte sélectionné"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:491
-msgid "The requested AML account or session was not found."
-msgstr "Le compte AML ou la session demandée est introuvable."
+#~ msgid "High risk accounts. Only with custom rules."
+#~ msgstr "Comptes à haut risque. Uniquement avec des règles personnalisées."
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:495
-msgid "The officer session is disabled or the account state changed."
-msgstr "La session de l’agent AML est désactivée ou l’état du compte a changé."
+#~ msgid "Account with custom rules."
+#~ msgstr "Compte avec des règles personnalisées."
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:192
-msgid "Invalid expiration"
-msgstr "Expiration non valide"
+#~ msgid "High risk accounts under investigation. Only with custom rules."
+#~ msgstr ""
+#~ "Comptes à haut risque sous enquête. Uniquement avec des règles "
+#~ "personnalisées."
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:193
-msgid "Attributes require an expiration date in the future."
-msgstr "Les attributs nécessitent une date d’expiration future."
+#~ msgid "Accounts under investigation. Only with custom rules."
+#~ msgstr "Comptes sous enquête. Uniquement avec des règles personnalisées."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:288
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:273
-msgid "Too many SKIP measures"
-msgstr "Trop de mesures SKIP"
+#~ msgid "High risk accounts under investigation."
+#~ msgstr "Comptes à haut risque sous enquête."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:289
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:274
-msgid "At most one immediate measure may use the SKIP check."
-msgstr "Une seule mesure immédiate au maximum peut utiliser le contrôle SKIP."
+#~ msgid "Accounts under investigation."
+#~ msgstr "Comptes sous enquête."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:491
-msgid "Require all measures"
-msgstr "Exiger toutes les mesures"
+#~ msgid "High risk accounts without investigation. Only with custom rules."
+#~ msgstr ""
+#~ "Comptes à haut risque sans enquête. Uniquement avec des règles "
+#~ "personnalisées."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:492
-msgid ""
-"Run all selected measures together instead of accepting any one of them."
-msgstr ""
-"Exécuter ensemble toutes les mesures sélectionnées au lieu d’accepter "
-"n’importe laquelle d’entre elles."
+#~ msgid "Accounts without investigation. Only with custom rules."
+#~ msgstr "Comptes sans enquête. Uniquement avec des règles personnalisées."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:172
-msgid "Invalid custom properties"
-msgstr "Propriétés personnalisées non valides"
+#~ msgid "High risk accounts without investigation."
+#~ msgstr "Comptes à haut risque sans enquête."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:173
-msgid ""
-"Custom property names and values must be non-empty and names must be unique "
-"and different from built-in properties."
-msgstr ""
-"Les noms et les valeurs des propriétés personnalisées ne doivent pas être "
-"vides ; les noms doivent être uniques et différents des propriétés intégrées."
+#~ msgid "Accounts without investigation."
+#~ msgstr "Comptes sans enquête."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:265
-msgid "Unknown measure"
-msgstr "Mesure inconnue"
+#~ msgid "No results"
+#~ msgstr "Aucun résultat"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:266
-msgid ""
-"A rule or immediate action references a measure that is not available. "
-"Review the rules and measures before submitting."
-msgstr ""
-"Une règle ou une action immédiate fait référence à une mesure indisponible. "
-"Vérifiez les règles et les mesures avant l’envoi."
+#~ msgid "#"
+#~ msgstr "#"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:274
-msgid "Requires investigation"
-msgstr "Nécessite une enquête"
+#~ msgid "Account Identification"
+#~ msgstr "Identification du compte"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:106
-msgid "Collection event not found"
-msgstr "Événement de collecte introuvable"
+#~ msgid "From %1$s %2$s To %3$s"
+#~ msgstr "De %1$s %2$s à %3$s"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:107
-msgid "There is no collection event with ID %1$s for this account."
-msgstr ""
-"Il n’existe aucun événement de collecte portant l’identifiant %1$s pour ce "
-"compte."
+#~ msgid "With custom rules"
+#~ msgstr "Avec des règles personnalisées"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:116
-msgid "Attributes unavailable"
-msgstr "Attributs indisponibles"
+#~ msgid "Search by ID"
+#~ msgstr "Rechercher par ID"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:117
-msgid "The collection event does not contain readable attributes."
-msgstr "L’événement de collecte ne contient aucun attribut lisible."
+#~ msgid "Under investigation: "
+#~ msgstr "Sous enquête : "
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:131
-msgid "Form identifier missing"
-msgstr "Identifiant du formulaire manquant"
+#~ msgid "High risk:"
+#~ msgstr "Haut risque :"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:132
-msgid "The collected information does not identify the form used to create it."
-msgstr ""
-"Les informations collectées n’indiquent pas le formulaire utilisé pour les "
-"créer."
+#~ msgid "Case queue"
+#~ msgstr "File d’attente des dossiers"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:144
-msgid "Form not available"
-msgstr "Formulaire indisponible"
+#~ msgid "Access"
+#~ msgstr "Accès"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:145
-msgid "Form %1$s is not configured in this AML Web UI."
-msgstr "Le formulaire %1$s n’est pas configuré dans cette interface Web AML."
+#~ msgid "Unlocked until"
+#~ msgstr "Déverrouillée jusqu’au"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:407
-msgid "The account was not found."
-msgstr "Le compte est introuvable."
+#~ msgid "Confirm forgetting this session"
+#~ msgstr "Confirmer la suppression de cette session"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:411
-msgid "The account state changed. Reload it and try again."
-msgstr "L’état du compte a changé. Rechargez-le et réessayez."
+#, fuzzy
+#~ msgid "Request session activation"
+#~ msgstr "Demander l'activation du compte"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:436
-msgid ""
-"The payto URI does not belong to this account. Return to the account search "
-"and start the decision again."
-msgstr ""
-"L’URI payto n’appartient pas à ce compte. Revenez à la recherche de comptes "
-"et recommencez la décision."
+#~ msgid "Prev"
+#~ msgstr "Précédent"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:448
-msgid ""
-"This account has no active decision and its payto URI is unknown. Start the "
-"decision from the account search so the account type can be determined "
-"safely."
-msgstr ""
-"Ce compte n’a aucune décision active et son URI payto est inconnue. Lancez "
-"la décision depuis la recherche de comptes afin de déterminer le type de "
-"compte de manière sûre."
+#~ msgid "Next"
+#~ msgstr "Suivant"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:458
-msgid "Return to account"
-msgstr "Revenir au compte"
+#~ msgid ""
+#~ "This account has no active decision and its payto URI is unknown. Start "
+#~ "the decision from the account search so the account type can be "
+#~ "determined safely."
+#~ msgstr ""
+#~ "Ce compte n’a aucune décision active et son URI payto est inconnue. "
+#~ "Lancez la décision depuis la recherche de comptes afin de déterminer le "
+#~ "type de compte de manière sûre."
#, c-format
#~ msgid "Internal error, please report."
@@ -2407,10 +5251,6 @@ msgstr "Revenir au compte"
#~ "incorrect."
#, c-format
-#~ msgid "Lock account"
-#~ msgstr "Verrouiller le compte"
-
-#, c-format
#~ msgid "Operation denied"
#~ msgstr "Opération refusée"
diff --git a/packages/taler-exchange-aml-webui/src/i18n/it.po b/packages/taler-exchange-aml-webui/src/i18n/it.po
@@ -1,3 +1,4 @@
+#
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: taler@gnu.org\n"
@@ -5,2385 +6,5233 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
#. screenid: 118
-#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:103
-msgid "Use testing dialect"
-msgstr "Usa il dialetto di test"
-
-#. screenid: 118
-#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:105
+#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:114
msgid "Allow Insecure password"
msgstr "Consenti password non sicura"
#. screenid: 118
-#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:107
+#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:116
msgid "Keep session after reload"
msgstr "Mantieni la sessione dopo il ricaricamento"
#. screenid: 118
-#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:109
+#: packages/taler-exchange-aml-webui/src/hooks/preferences.ts:118
msgid "Don't compress request"
msgstr "Non comprimere la richiesta"
#. screenid: 101
-#: packages/taler-exchange-aml-webui/src/ExchangeAmlFrame.tsx:75
-msgid "Preferences"
-msgstr "Preferenze"
+#: packages/taler-exchange-aml-webui/src/ExchangeAmlFrame.tsx:85
+msgid "Lock session"
+msgstr "Blocca sessione"
#. screenid: 101
-#: packages/taler-exchange-aml-webui/src/ExchangeAmlFrame.tsx:120
-#, fuzzy
-msgid "Show debug information"
-msgstr "Mostra le informazioni di debug"
+#: packages/taler-exchange-aml-webui/src/ExchangeAmlFrame.tsx:90
+msgid "Lock"
+msgstr "Blocca"
#. screenid: 125
#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:46
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:45
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:94
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:47
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:47
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:115
msgid "Password"
msgstr "Password"
#. screenid: 125
#. screenid: 122
#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:50
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:71
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:555
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:996
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:749
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:780
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:797
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:827
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:841
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:51
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:72
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:629
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1108
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:794
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:825
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:842
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:872
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:886
msgid "Required"
msgstr "Obbligatorio"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:54
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:55
msgid "should have at least 12 characters"
msgstr "deve avere almeno 12 caratteri"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:56
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:57
msgid "should have lowercase and uppercase characters"
msgstr "deve avere caratteri minuscoli e maiuscoli"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:58
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:59
msgid "should have numbers"
msgstr "deve avere numeri"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:60
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:61
msgid "should have at least one character which is not a number or letter"
msgstr "deve avere almeno un carattere che non sia un numero o una lettera"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:67
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:68
msgid "Repeat password"
msgstr "Ripeti la password"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:73
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:74
msgid "doesn't match"
msgstr "non corrisponde"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:105
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:112
#, fuzzy
msgid "Create session"
msgstr "Crea conto"
#. screenid: 125
-#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:117
+#: packages/taler-exchange-aml-webui/src/components/CreateSession.tsx:139
msgid "Create"
msgstr "Crea"
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:66
-msgid "Failed to unlock the session."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountBadges.tsx:28
+msgid "Wallet account"
+msgstr "Conto del portafoglio"
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:69
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:243
-msgid "Authorization denied for this session. Contact the administrator."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/components/AccountBadges.tsx:28
+msgid "Bank account"
+msgstr "Conto bancario"
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:80
-#, fuzzy
-msgid "Session locked"
-msgstr "Conto bloccato"
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/components/AccountBadges.tsx:40
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:93
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:245
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:296
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:100
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:130
+msgid "Under investigation"
+msgstr "Sotto indagine"
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:83
-#, fuzzy
-msgid ""
-"Your session is normally locked anytime you reload. To unlock type your "
-"password again."
-msgstr ""
-"Il tuo conto viene normalmente bloccato ogni volta che ricarichi la pagina. "
-"Per sbloccarlo digita di nuovo la password."
+#: packages/taler-exchange-aml-webui/src/components/AccountBadges.tsx:89
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:101
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:254
+msgid "High risk"
+msgstr "Rischio elevato"
-#. screenid: 119
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:108
-msgid "Unlock"
-msgstr "Sblocca"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:51
+msgid "Payment target type"
+msgstr ""
-#. screenid: 119
-#. screenid: 112
-#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:116
-#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:81
-#, fuzzy
-msgid "Forget session"
-msgstr "Dimentica conto"
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:81
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:199
+msgid "Account holder"
+msgstr "Titolare del conto"
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:55
-msgid "There are no rules for operations"
-msgstr "Non ci sono regole per le operazioni"
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:107
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:110
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:571
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:806
+msgid "IBAN"
+msgstr "IBAN"
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:58
-#, fuzzy
-msgid "This means that no operation has any limit."
-msgstr "Questo significa che tutte le operazioni non hanno limiti."
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:109
+msgid "BIC"
+msgstr ""
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:69
-msgid "Add custom rule"
-msgstr "Aggiungi regola personalizzata"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:114
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:119
+msgid "Bank"
+msgstr ""
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:94
-msgid "Operation"
-msgstr "Operazione"
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:115
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:120
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:154
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:160
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:295
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:859
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:364
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:435
+msgid "Account"
+msgstr "Conto"
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:100
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:625
-msgid "Threshold"
-msgstr "Soglia"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:116
+msgid "Taler bank"
+msgstr "Banca Taler"
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:106
-msgid "Escalation"
-msgstr "Escalation"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:121
+msgid "Cyclos"
+msgstr ""
-#. screenid: 121
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:120
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:243
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:800
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:844
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:902
-msgid "%1$s"
-msgstr "%1$s"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:124
+msgid "Bitcoin address"
+msgstr ""
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:195
-msgctxt "threshold"
-msgid "%1$s every %2$s"
-msgstr "%1$s ogni %2$s"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:129
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:144
+msgid "Reserve public key"
+msgstr ""
-#. screenid: 121
-#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:213
-msgid "(all)"
-msgstr "(tutti)"
-
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:59
-#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:69
-msgid "Since"
-msgstr "Da"
-
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:70
-msgid "Expired"
-msgstr "Scaduto"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:133
+msgid "Bitcoin"
+msgstr ""
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:72
-msgid "Expires"
-msgstr "Scade"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:136
+msgid "Ethereum address"
+msgstr ""
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:82
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:724
-msgid "Successor measure"
-msgstr "Misura successiva"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:139
+msgid "Ethereum"
+msgstr ""
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:140
-msgid "AML officer justification"
-msgstr "Giustificazione dell'ufficiale AML"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:142
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:70
+msgid "Exchange"
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/components/ShowDefaultRules.tsx:11
-msgid "Default rules"
-msgstr "Regole predefinite"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:149
+msgid "Taler reserve"
+msgstr "Riserva Taler"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:42
-msgid "Forms"
-msgstr "Moduli"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:150
+msgid "Taler reserve (HTTP)"
+msgstr ""
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:45
-#, fuzzy
-msgid "Measures used to gather information about the customer."
-msgstr "Misure utilizzate per raccogliere informazioni sul cliente."
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:157
+msgid "Test account"
+msgstr "Conto di prova"
-#. screenid: 123
-#. screenid: 108
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:69
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:162
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:248
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:153
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:552
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:992
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:192
-msgid "Name"
-msgstr "Nome"
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:180
+#: packages/taler-exchange-aml-webui/src/components/PaytoTargetDetails.tsx:225
+msgid "Account details unavailable"
+msgstr ""
-#. screenid: 123
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:76
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:169
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:584
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:837
-msgid "Check"
-msgstr "Verifica"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:54
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:96
+msgid "Not opened"
+msgstr "Non aperto"
-#. screenid: 123
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:82
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:255
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:564
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:791
-msgid "Program"
-msgstr "Programma"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:59
+msgid "Opened:"
+msgstr "Aperto:"
-#. screenid: 123
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:88
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:175
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:267
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:607
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:805
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:893
-msgid "Context"
-msgstr "Contesto"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:68
+msgid "Closed:"
+msgstr "Chiuso:"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:102
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:189
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:281
-msgid "Modify"
-msgstr "Modifica"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:94
+msgid "Closed"
+msgstr "Chiuso"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:135
-msgid "Info"
-msgstr "Info"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:95
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:263
+msgid "Open"
+msgstr "Aperto"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:138
-msgid "Will show information to the user."
-msgstr "Mostrerà informazioni all'utente."
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:125
+msgid "No note"
+msgstr "Nessuna nota"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:221
-msgid "Instant measures"
-msgstr "Misure istantanee"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:136
+msgid "Show full note"
+msgstr "Mostra la nota completa"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:224
-msgid "Triggered immediately without customer interaction."
-msgstr "Attivate immediatamente senza interazione del cliente."
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:146
+msgid "System information"
+msgstr "Informazioni di sistema"
-#. screenid: 123
-#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:261
-msgid "Input requirement"
-msgstr "Requisito di input"
+#: packages/taler-exchange-aml-webui/src/components/AccountSummary.tsx:149
+msgid "Transactions remain below the threshold that opens an AML file."
+msgstr ""
+"Le transazioni restano al di sotto della soglia che apre un fascicolo AML."
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:78
-msgid "Already completed."
-msgstr "Già completato."
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:122
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:202
+msgid "Account case"
+msgstr "Caso del conto"
-#. screenid: 120
-#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:80
-msgid "Waiting to be completed."
-msgstr "In attesa di essere completato."
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:149
+msgid "Failed to download AML file."
+msgstr "Impossibile scaricare il fascicolo AML."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:183
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:365
-msgid "Current active rules"
-msgstr "Regole attive correnti"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:152
+msgid "No AML file is available for this account."
+msgstr "Non è disponibile alcun fascicolo AML per questo conto."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:188
-msgid "There are no rules for this account yet."
-msgstr "Non ci sono ancora regole per questo conto."
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:154
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:72
+msgid "Authorization denied for this session. Contact the administrator."
+msgstr ""
+"Autorizzazione negata per questa sessione. Contattare l’amministratore."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:238
-msgid "New rule form"
-msgstr "Modulo per nuova regola"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:156
+msgid "The account or session was not found."
+msgstr "Il conto o la sessione non sono stati trovati."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:250
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:230
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:412
-msgid "Add"
-msgstr "Aggiungi"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:158
+msgid "The session is disabled. Contact the administrator."
+msgstr "La sessione è disabilitata. Contattare l’amministratore."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:258
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:221
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:403
-msgid "Cancel"
-msgstr "Annullare"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:160
+msgid "The exchange does not support PDF reports."
+msgstr "L’Exchange non supporta i rapporti PDF."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:356
-msgid "Basic plan"
-msgstr "Piano base"
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:175
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:354
+msgid "Read-only officers cannot create AML decisions."
+msgstr ""
+"Gli operatori con accesso in sola lettura non possono creare decisioni AML."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:367
-msgid "Premium"
-msgstr "Premium"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:177
+msgid "A payto URI is required to create a new decision."
+msgstr "È necessario un URI payto per creare una nuova decisione."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:378
-msgid "E-commerce"
-msgstr "E-commerce"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:194
+msgid "Back to accounts"
+msgstr "Torna ai conti"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:389
-msgid "Point of Sale"
-msgstr "Punto vendita"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:224
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:505
+msgid "File no. %1$s"
+msgstr "Fascicolo n. %1$s"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:408
-msgid "Check rules"
-msgstr "Verifica regole"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:253
+msgid "New decision"
+msgstr "Nuova decisione"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:428
-msgid ""
-"The account is a wallet and there are bank account operation's limits which "
-"may trigger actions that are not required: %1$s"
-msgstr ""
-"Il conto è un portafoglio e ci sono limiti di operazioni per conto bancario "
-"che potrebbero attivare azioni non necessarie: %1$s"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:265
+msgid "Download AML file (PDF)"
+msgstr "Scarica il fascicolo AML (PDF)"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:437
-msgid ""
-"The account isn't a wallet and there are wallet operation's limits which may "
-"trigger actions that are not required: %1$s"
-msgstr ""
-"Il conto non è un portafoglio e ci sono limiti di operazioni per portafoglio "
-"che potrebbero attivare azioni non necessarie: %1$s"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:278
+msgid "AML file download started."
+msgstr "Il download del fascicolo AML è iniziato."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:446
-msgid ""
-"The account is a wallet and there are wallet operation's limits which are "
-"not limited: %1$s"
-msgstr ""
-"Il conto è un portafoglio e ci sono limiti di operazioni per portafoglio che "
-"non sono limitati: %1$s"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:284
+#, fuzzy
+#| msgid "Account open"
+msgid "Account notes"
+msgstr "Conto aperto"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:454
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:293
#, fuzzy
-msgid ""
-"The AML account is a bank account, but not all account-related operations "
-"are limited ( %1$s)."
+#| msgid "Account assessment could not be loaded"
+msgid "Current account status and notes could not be loaded."
+msgstr "Impossibile caricare la valutazione del conto"
+
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:302
+msgid "Try again"
msgstr ""
-"Il conto AML è un conto bancario, ma non tutte le operazioni relative al "
-"conto sono limitate (%1$s)."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:482
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:269
-msgid "New rules"
-msgstr "Nuove regole"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:316
+msgid "Account identifiers"
+msgstr "Identificativi del conto"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:503
-msgid "Reset rules to current state"
-msgstr "Reimposta le regole allo stato attuale"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:325
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:509
+msgid "Technical identifiers"
+msgstr "Identificatori tecnici"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:511
-msgid "Set rules to default"
-msgstr "Imposta le regole ai valori predefiniti"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:329
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:513
+msgid "Full payto URI"
+msgstr "URI payto completo"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:519
-msgid "Freeze account"
-msgstr "Congela conto"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:331
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:144
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:155
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:173
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:190
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:390
+msgid "Unavailable"
+msgstr "Non disponibile"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:535
-msgid "Behavior on rule expiration"
-msgstr "Comportamento alla scadenza della regola"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:332
+msgid "Copy payto URI"
+msgstr "Copia URI payto"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:546
-msgid "Reset measure"
-msgstr "Reimposta misura"
+#. screenid: 113
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:335
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:517
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:188
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:157
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:289
+msgid "Normalized payto hash"
+msgstr "Hash payto normalizzato"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:558
-msgid "Reset expiration"
-msgstr "Reimposta scadenza"
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:337
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:194
+msgid "Copy normalized payto hash"
+msgstr "Copia l’hash payto normalizzato"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:583
-msgctxt "operation type"
-msgid "Withdraw"
-msgstr "Prelievo"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:341
+#, fuzzy
+#| msgid "number"
+msgid "File number"
+msgstr "numero"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:585
-msgctxt "operation type"
-msgid "Deposit"
-msgstr "Deposito"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:343
+#, fuzzy
+#| msgid "Not a number"
+msgid "Copy file number"
+msgstr "Non è un numero"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:587
-msgctxt "operation type"
-msgid "Merge"
-msgstr "Unione"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:351
+msgid "Account case views"
+msgstr "Viste del caso del conto"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:589
-msgctxt "operation type"
-msgid "Aggregate"
-msgstr "Aggregazione"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:355
+msgid "Overview"
+msgstr "Panoramica"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:591
-msgctxt "operation type"
-msgid "Balance"
-msgstr "Saldo"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:360
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:565
+msgid "Transfers"
+msgstr "Trasferimenti"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:593
-msgctxt "operation type"
-msgid "Refund"
-msgstr "Rimborso"
+#: packages/taler-exchange-aml-webui/src/components/AccountCaseShell.tsx:365
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:67
+msgid "Decision history"
+msgstr "Cronologia delle decisioni"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:595
-msgctxt "operation type"
+#: packages/taler-exchange-aml-webui/src/components/ConfirmationModal.tsx:73
msgid "Close"
-msgstr "Chiusura"
-
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:597
-msgctxt "operation type"
-msgid "Transaction"
-msgstr "Transazione"
-
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:612
-msgid "Operation type"
-msgstr "Tipo di operazione"
+msgstr "Chiudi"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:633
-msgid "Timeframe"
-msgstr "Intervallo di tempo"
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/ConfirmationModal.tsx:91
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:207
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:534
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:280
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:469
+msgid "Cancel"
+msgstr "Annullare"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:639
-msgid "Exposed"
-msgstr "Esposto"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:36
+msgid "AML officer enrollment request"
+msgstr "Richiesta di registrazione dell’ufficiale AML"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:640
-msgid "Is this limit communicated to the customer?"
-msgstr "Questo limite viene comunicato al cliente?"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:37
+msgid ""
+"Please enroll this AML officer public key:\n"
+"\n"
+"%1$s"
+msgstr ""
+"Registra questa chiave pubblica dell’ufficiale AML:\n"
+"\n"
+"%1$s"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:652
-msgid "Escalation measure"
-msgstr "Misura di escalation"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:59
+msgid "Officer key awaiting enrollment"
+msgstr "Chiave dell’ufficiale AML in attesa di registrazione"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:653
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:62
msgid ""
-"Measures that the customer will need to satisfy to apply for a new threshold."
+"This browser has created an AML officer key, but the exchange has not "
+"granted it access. Ask the exchange operator or administrator to enroll the "
+"public key below."
msgstr ""
-"Misure che il cliente dovrà soddisfare per richiedere una nuova soglia."
+"Questo browser ha creato una chiave per l’ufficiale AML, ma l’Exchange non "
+"le ha concesso l’accesso. Chiedi all’operatore o all’amministratore "
+"dell’Exchange di registrare la chiave pubblica qui sotto."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:658
-msgid "All measures"
-msgstr "Tutte le misure"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:70
+msgid "AML officer public key"
+msgstr "Chiave pubblica dell’ufficiale AML"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:659
-msgid "Hint the customer that all measures should be completed"
-msgstr "Segnala al cliente che tutte le misure devono essere completate"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:76
+msgid "Copy AML officer public key"
+msgstr "Copia la chiave pubblica dell’addetto AML"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:672
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:157
-msgid "Expiration"
-msgstr "Scadenza"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:82
+msgid "After the operator confirms enrollment, retry the access check."
+msgstr ""
+"Dopo che l’operatore ha confermato la registrazione, riprova a verificare "
+"l’accesso."
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:92
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:69
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:212
+msgid "Retry access check"
+msgstr "Riprova la verifica dell’accesso"
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:101
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:188
+msgid "Checking officer access"
+msgstr "Verifica dell’accesso dell’ufficiale AML"
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:104
+msgid "Last checked at %1$s"
+msgstr "Ultima verifica alle %1$s"
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:114
+msgid "Request enrollment"
+msgstr "Richiedi la registrazione"
+
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:121
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:128
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:77
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:85
+msgid "Discard this key"
+msgstr "Elimina questa chiave"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:673
-msgid "Predefined shortcuts"
-msgstr "Scorciatoie predefinite"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:127
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:84
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:250
+msgid "Confirmation required"
+msgstr "Conferma richiesta"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:677
-msgid "In a week"
-msgstr "Tra una settimana"
+#: packages/taler-exchange-aml-webui/src/components/OfficerEnrollment.tsx:135
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:92
+msgid ""
+"Discarding this key removes the officer session from this browser. You will "
+"need to create a new key to use the AML WebUI again."
+msgstr ""
+"Eliminando questa chiave, la sessione dell’ufficiale verrà rimossa da questo "
+"browser. Per utilizzare nuovamente l’interfaccia web AML, dovrai creare una "
+"nuova chiave."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:685
-msgid "In a month"
-msgstr "Tra un mese"
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:41
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:205
+msgid "Failed to check AML officer access."
+msgstr "Impossibile verificare l’accesso dell’operatore AML."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:693
-msgid "In a year"
-msgstr "Tra un anno"
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:45
+msgid ""
+"This officer key cannot authenticate with the exchange. Retry the check or "
+"discard the key and create a new session."
+msgstr ""
+"Questa chiave dell’operatore non può autenticarsi presso l’exchange. Riprova "
+"la verifica oppure elimina la chiave e crea una nuova sessione."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:701
-msgid "Never"
-msgstr "Mai"
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:50
+msgid "The exchange rejected the officer access check."
+msgstr "L’exchange ha rifiutato la verifica dell’accesso dell’operatore."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:712
-msgid "Expiration date"
-msgstr "Data di scadenza"
+#: packages/taler-exchange-aml-webui/src/components/OfficerAccessFailure.tsx:57
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:211
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:522
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:101
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:612
+msgid "Technical details"
+msgstr "Dettagli tecnici"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:713
-msgid "Until when are the new rules active."
-msgstr "Fino a quando sono attive le nuove regole."
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:69
+msgid "Failed to unlock the session."
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:725
-msgid "Measure taken automatically upon expiration of the current decision."
-msgstr "Misura adottata automaticamente alla scadenza della decisione attuale."
-
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:107
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:62
-msgid "Failed to load account information."
-msgstr ""
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:95
+#, fuzzy
+msgid "Session locked"
+msgstr "Conto bloccato"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:125
-msgid "Failed to load decision history."
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:98
+#, fuzzy
+msgid ""
+"Your session is normally locked anytime you reload. To unlock type your "
+"password again."
msgstr ""
+"Il tuo conto viene normalmente bloccato ogni volta che ricarichi la pagina. "
+"Per sbloccarlo digita di nuovo la password."
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:143
-msgid "Failed to load current legitimizations."
-msgstr ""
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:136
+msgid "Unlock"
+msgstr "Sblocca"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:188
-msgid "New decision"
-msgstr "Nuova decisione"
+#. screenid: 119
+#: packages/taler-exchange-aml-webui/src/components/UnlockSession.tsx:144
+msgid "Forget session"
+msgstr "Elimina sessione"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:196
-msgid "Show transfers"
-msgstr "Mostra trasferimenti"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:162
+#, fuzzy
+#| msgid "No account properties"
+msgid "Review derived account properties"
+msgstr "Nessuna proprietà del conto"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:236
-msgid "Failed to download report."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:165
+msgid ""
+"Values may be derived from the selected AML/KYC form. Confirm them against "
+"the case record and change only values that require an officer override."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:241
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:187
#, fuzzy
-msgid "The account has no KYC info."
-msgstr "Il conto non è stato trovato"
+#| msgid "Reset to default"
+msgid "Reset to derived values"
+msgstr "Ripristina i valori predefiniti"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:245
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:183
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:195
-msgid "Session not found. Contact the administrator."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:192
+msgid "Invalid custom properties"
+msgstr "Proprietà personalizzate non valide"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:247
-msgid "The session is disabled. Contact the administrator."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:193
+msgid ""
+"Custom property names and values must be non-empty and names must be unique "
+"and different from built-in properties."
msgstr ""
+"I nomi e i valori delle proprietà personalizzate non possono essere vuoti; i "
+"nomi devono essere univoci e diversi dalle proprietà integrate."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:216
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:466
+msgid "Properties"
+msgstr "Proprietà"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:249
-msgid "The server doesn't support PDF download. Contact the administrator."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:217
+msgid "Built-in property names are preserved when the decision is submitted."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:260
-msgid "Case history for selected account"
-msgstr "Cronologia dei casi per il conto selezionato"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:223
+msgid "Custom properties"
+msgstr "Proprietà personalizzate"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:224
+msgid "Add more properties that are not listed above."
+msgstr "Aggiungi altre proprietà non elencate sopra."
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:265
-msgid "ID:"
-msgstr "ID:"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:229
+msgid "New properties"
+msgstr "Nuove proprietà"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:271
-msgid "Payto:"
-msgstr "Payto:"
+#. screenid: 123
+#. screenid: 108
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:234
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:73
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:171
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:261
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:204
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:626
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1104
+msgid "Name"
+msgstr "Nome"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:282
-msgid "Export as PDF"
-msgstr "Esporta come PDF"
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:240
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:720
+msgid "Value"
+msgstr "Valore"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:298
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:279
-msgid "Export completed"
-msgstr "Esportazione completata"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:262
+msgid "Current note on the GwG file"
+msgstr "Nota attuale sul fascicolo GwG"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:301
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:282
-msgid "Click here to save the file in your computer."
-msgstr "Clicca qui per salvare il file sul tuo computer."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:267
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:63
+msgid "Customer name or internal alias."
+msgstr "Nome del cliente o alias interno."
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:310
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:411
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:208
-msgid "Under investigation"
-msgstr "Sotto indagine"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:272
+msgid "Is the account active for deposit and payments?"
+msgstr "Il conto è attivo per depositi e pagamenti?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:311
-msgid ""
-"This account requires a manual review and is waiting for a decision to be "
-"made."
-msgstr ""
-"Questo conto richiede una revisione manuale ed è in attesa di una decisione."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:277
+msgid "Is the account idle?"
+msgstr "Il conto è inattivo?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:322
-msgid "Collected information"
-msgstr "Informazioni raccolte"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:278
+msgid "No operation for a period of time"
+msgstr "Nessuna operazione per un periodo di tempo"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:325
-msgid "Every attribute collection event (via form upload or KYC provider)."
-msgstr ""
-"Ogni evento di raccolta attributi (tramite caricamento di moduli o fornitore "
-"KYC)."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:283
+msgid "Does account belong to a domestic PEP?"
+msgstr "Il conto appartiene a un PEP nazionale?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:333
-msgid "No collected attributes for this account."
-msgstr "Nessun attributo raccolto per questo conto."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:288
+msgid "Does account belong to a foreign PEP?"
+msgstr "Il conto appartiene a un PEP straniero?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:347
-msgid "Current account properties"
-msgstr "Proprietà attuali del conto"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:293
+msgid "Does account belong to an international-organization PEP?"
+msgstr "Il conto appartiene a un PEP di organizzazione internazionale?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:354
-msgid "No active decision found"
-msgstr "Nessuna decisione attiva trovata"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:298
+msgid "Does account belong to a high risk customer?"
+msgstr "Il conto appartiene a un cliente ad alto rischio?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:355
-msgid ""
-"There is no decision for this account yet. The account is limited by the "
-"default rules."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:303
+msgid "Does account belong to a person from a high risk country?"
msgstr ""
-"Non c'è ancora alcuna decisione per questo conto. Il conto è limitato dalle "
-"regole predefinite."
+"Il conto appartiene a una persona proveniente da un paese ad alto rischio?"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:384
-msgid "Previous AML decisions"
-msgstr "Decisioni AML precedenti"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:308
+msgid "The MROS reporting state for the account."
+msgstr "Lo stato di segnalazione MROS per il conto."
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:403
-msgid "No AML history found"
-msgstr "Nessuna cronologia AML trovata"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:313
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:307
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:175
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:199
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:497
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:630
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:653
+msgid "None"
+msgstr "Nessuno"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:409
-msgid "Current active measures"
-msgstr "Misure attive correnti"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:317
+msgid "Pending investigation"
+msgstr "Indagine in corso"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:537
-msgid "Now"
-msgstr "Ora"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:321
+msgid "Investigated without suspicion"
+msgstr "Indagato senza sospetti"
-#. screenid: 112
-#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:43
-#, fuzzy
-msgid "Session public key"
-msgstr "Chiave pubblica"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:325
+msgid "Reported simple suspicion"
+msgstr "Sospetto semplice segnalato"
-#. screenid: 112
-#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:59
-#, fuzzy
-msgid "Request session activation"
-msgstr "Richiedi attivazione del conto"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:329
+msgid "Reported substantiated suspicion"
+msgstr "Sospetto comprovato segnalato"
-#. screenid: 112
-#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:70
-msgid "Lock session"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:336
+msgid "Informal reason why the AML investigation was triggered"
+msgstr "Motivo informale per cui è stata avviata l'indagine AML"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:341
+msgid "Identifies the sanction list entry that the account matched against"
msgstr ""
+"Identifica la voce dell'elenco sanzionatorio con cui il conto corrisponde"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:73
-msgid "Failed to load accounts"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:343
+msgid "Best match, does not mean it was a good match."
msgstr ""
+"Migliore corrispondenza, non significa che fosse una buona corrispondenza."
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:83
-#, fuzzy
-msgid "Failed to load the accounts"
-msgstr "Cronologia dei casi per il conto selezionato"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:347
+msgid "Score for how good the sanction list match was"
+msgstr ""
+"Punteggio di quanto buona sia stata la corrispondenza con l'elenco "
+"sanzionatorio"
-#. screenid: 111
-#. screenid: 110
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:88
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:168
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:76
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:128
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:66
-#, fuzzy
-msgid ""
-"This session signature is invalid, contact administrator or create a new one."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:349
+msgid "Integer score from 0 (no match) to 1,000,000,000 (best match)."
msgstr ""
-"La firma di questo conto non è valida, contatta l'amministratore o creane "
-"una nuova."
-#. screenid: 111
-#. screenid: 110
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:95
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:175
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:83
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:135
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:73
-#, fuzzy
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:353
+msgid "Score for how much supporting data we had for the sanction list match"
+msgstr ""
+"Punteggio di quanti dati di supporto avevamo per la corrispondenza con "
+"l'elenco sanzionatorio"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:355
msgid ""
-"The designated AML session is not known, contact administrator or create a "
-"new one."
+"Integer score from 0 (no supporting data) to 1,000,000,000 (highest "
+"confidence)."
msgstr ""
-"Il conto AML designato non è noto, contatta l'amministratore o creane uno "
-"nuovo."
-#. screenid: 111
-#. screenid: 110
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:102
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:182
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:90
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:142
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:80
-#, fuzzy
+#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:359
msgid ""
-"The designated AML session is not enabled, contact administrator or create a "
-"new one."
+"Suppress flagging this account when it creates a hit on a sanctions list, "
+"this is a false-positive"
msgstr ""
-"Il conto AML designato non è abilitato, contatta l'amministratore o creane "
-"uno nuovo."
+"Sopprimi la segnalazione di questo conto quando genera una corrispondenza in "
+"un elenco sanzionatorio, si tratta di un falso positivo"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:122
-msgid "High risk accounts. Only with custom rules."
-msgstr "Conti ad alto rischio. Solo con regole personalizzate."
+#: packages/taler-exchange-aml-webui/src/components/DecisionProperties.tsx:46
+#, fuzzy
+#| msgid "No account properties"
+msgid "No account properties were recorded."
+msgstr "Nessuna proprietà del conto"
+
+#: packages/taler-exchange-aml-webui/src/components/DecisionProperties.tsx:91
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:317
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:509
+msgid "Yes"
+msgstr "Sì"
+
+#: packages/taler-exchange-aml-webui/src/components/DecisionProperties.tsx:91
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:317
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:509
+msgid "No"
+msgstr "No"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:123
-msgid "Account with custom rules."
-msgstr "Conto con regole personalizzate."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:59
+msgid "There are no rules for operations"
+msgstr "Non ci sono regole per le operazioni"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:125
-msgid "High risk accounts"
-msgstr "Conti ad alto rischio"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:62
+msgid "This means that no operation has any limit."
+msgstr "Questo significa che nessuna operazione ha limiti."
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:126
-msgid "All known accounts."
-msgstr "Tutti i conti conosciuti."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:90
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:312
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:500
+msgid "Operation"
+msgstr "Operazione"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:130
-msgid "High risk accounts under investigation. Only with custom rules."
-msgstr "Conti ad alto rischio sotto indagine. Solo con regole personalizzate."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:96
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:695
+msgid "Threshold"
+msgstr "Soglia"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:131
-msgid "Accounts under investigation. Only with custom rules."
-msgstr "Conti sotto indagine. Solo con regole personalizzate."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:102
+msgid "Escalation"
+msgstr "Escalation"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:133
-msgid "High risk accounts under investigation."
-msgstr "Conti ad alto rischio sotto indagine."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:108
+msgid "Visibility"
+msgstr "Visibilità"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:134
-msgid "Accounts under investigation."
-msgstr "Conti sotto indagine."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:114
+msgid "Priority"
+msgstr "Priorità"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:137
-msgid "High risk accounts without investigation. Only with custom rules."
-msgstr "Conti ad alto rischio senza indagine. Solo con regole personalizzate."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:121
+msgid "Actions"
+msgstr "Azioni"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:138
-msgid "Accounts without investigation. Only with custom rules."
-msgstr "Conti senza indagine. Solo con regole personalizzate."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:142
+msgctxt "threshold"
+msgid "%1$s every %2$s"
+msgstr "%1$s ogni %2$s"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:140
-msgid "High risk accounts without investigation."
-msgstr "Conti ad alto rischio senza indagine."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:161
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:725
+msgid "Block operation"
+msgstr "Blocca operazione"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:141
-msgid "Accounts without investigation."
-msgstr "Conti senza indagine."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:163
+msgid "All required:"
+msgstr "Tutte necessarie:"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:174
-msgid "Failed to download"
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:165
+msgid "Any one:"
+msgstr "Una qualsiasi:"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:177
-#, fuzzy
-msgid "There are no accounts in the resultset."
-msgstr "Non ci sono ancora regole per questo conto."
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:182
+msgid "Customer-visible"
+msgstr "Visibile al cliente"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:179
-msgid "The format requested is not acceptable from the service provider."
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:184
+msgid "Internal"
+msgstr "Interno"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:181
-msgid "Authorization denied for this session."
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:197
+msgid "Move %1$s rule up"
+msgstr "Sposta in alto la regola %1$s"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:185
-msgid "The session is disabled. Contact the administrator"
-msgstr ""
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:206
+msgid "Move %1$s rule down"
+msgstr "Sposta in basso la regola %1$s"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:240
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:368
-msgid "Accounts"
-msgstr "Conti"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:217
+msgid "Edit %1$s rule"
+msgstr "Modifica la regola %1$s"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:247
-msgid "Export as file"
-msgstr "Esporta come file"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:240
+msgid "Remove %1$s rule"
+msgstr "Rimuovi la regola %1$s"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:318
-msgid "No results"
-msgstr "Nessun risultato"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:282
+msgctxt "operation type"
+msgid "Withdraw"
+msgstr "Prelievo"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:329
-msgid "#"
-msgstr "#"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:284
+msgctxt "operation type"
+msgid "Deposit"
+msgstr "Deposito"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:335
-msgid "Account Identification"
-msgstr "Identificazione del conto"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:286
+msgctxt "operation type"
+msgid "Merge"
+msgstr "Unione"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:341
-msgid "Open time"
-msgstr "Ora di apertura"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:288
+msgctxt "operation type"
+msgid "Aggregate"
+msgstr "Aggregazione"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:347
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:243
-msgid "Status"
-msgstr "Stato"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:290
+msgctxt "operation type"
+msgid "Balance"
+msgstr "Saldo"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:365
-msgid "From %1$s %2$s To %3$s"
-msgstr "Da %1$s %2$s a %3$s"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:292
+msgctxt "operation type"
+msgid "Refund"
+msgstr "Rimborso"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:371
-msgid "Since %1$s"
-msgstr "Da %1$s"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:294
+msgctxt "operation type"
+msgid "Close"
+msgstr "Chiusura"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:374
-msgid "Not opened"
-msgstr "Non aperto"
+#. screenid: 121
+#: packages/taler-exchange-aml-webui/src/components/RulesInfo.tsx:296
+msgctxt "operation type"
+msgid "Transaction"
+msgstr "Transazione"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:419
-msgid "High risk"
-msgstr "Alto rischio"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:83
+#, fuzzy
+#| msgid "Decision date"
+msgid "Decision provenance"
+msgstr "Data della decisione"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:427
-msgid "With custom rules"
-msgstr "Con regole personalizzate"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:85
+#, fuzzy
+#| msgid "Decision date"
+msgid "Decision made by"
+msgstr "Data della decisione"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:642
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:673
-msgid "Invalid account"
-msgstr "Conto non valido"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:88
+#, fuzzy
+#| msgid "AML officer public key"
+msgid "AML officer (name unavailable)"
+msgstr "Chiave pubblica dell’ufficiale AML"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:657
-msgid "Search by ID"
-msgstr "Cerca per ID"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:89
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:369
+msgid "Automated outcome"
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:687
-msgid "Under investigation: "
-msgstr "Sotto indagine:"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:91
+msgid "Resulting case disposition"
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:696
-msgid "High risk:"
-msgstr "Alto rischio:"
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:94
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:246
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:105
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:132
+msgid "Not under investigation"
+msgstr "Non sotto indagine"
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:99
+#, fuzzy
+#| msgid "Justification"
+msgid "Justification:"
+msgstr "Giustificazione"
-#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:705
-msgid "Custom rules:"
-msgstr "Regole personalizzate:"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:101
+msgid "No justification was recorded."
+msgstr "Non è stata registrata alcuna motivazione."
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:47
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:366
-msgid "Dashboard"
-msgstr "Dashboard"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:112
+#, fuzzy
+#| msgid "System information"
+msgid "View submitted customer information"
+msgstr "Informazioni di sistema"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:88
-msgid "Failed to load TOPS statistics."
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:120
+#, fuzzy
+#| msgid "Instant measures"
+msgid "Immediate measures requested"
+msgstr "Misure istantanee"
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:123
+msgid "This decision did not request an immediate measure."
msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:99
-msgid "Statistics"
-msgstr "Statistiche"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:131
+#, fuzzy
+#| msgid "All listed measures must be completed."
+msgid "All listed measures were requested (AND)."
+msgstr "Tutte le misure elencate devono essere completate."
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:187
-msgid "Accounts open"
-msgstr "Conti aperti"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:132
+#, fuzzy
+#| msgid "Any one listed measure may be completed."
+msgid "Any listed measure may satisfy the request (OR)."
+msgstr "È possibile completare una qualsiasi delle misure elencate."
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:190
-msgid "New files last year"
-msgstr "Nuovi fascicoli nell'ultimo anno"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:151
+msgid "Operation rules"
+msgstr "Regole operative"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:193
-msgid "Closed files last year"
-msgstr "Fascicoli chiusi nell'ultimo anno"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:156
+msgid "No operation-specific rules were stored."
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:196
-msgid "MROS substantiated"
-msgstr "MROS comprovate"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:163
+#, fuzzy
+#| msgid "Select transaction type"
+msgid "Policy transition"
+msgstr "Seleziona il tipo di transazione"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:199
-msgid "MROS simple"
-msgstr "MROS semplici"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:165
+msgid "Policy expires"
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:202
-msgid "High risk files"
-msgstr "Fascicoli ad alto rischio"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:173
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:796
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:362
+msgid "Successor measure"
+msgstr "Misura successiva"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:205
-msgid "PEP files"
-msgstr "Fascicoli PEP"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:174
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:479
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:163
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:365
+msgid "Exchange defaults"
+msgstr "Regole predefinite dell’Exchange"
+
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:179
+#, fuzzy
+#| msgid "Custom measures"
+msgid "Custom measure definitions"
+msgstr "Misure personalizzate"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:267
-msgid "Number of accounts that are opened"
-msgstr "Numero di conti aperti"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:182
+#, fuzzy
+#| msgid "No active measure has been selected."
+msgid "No custom measures were stored."
+msgstr "Non è stata selezionata alcuna misura attiva."
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:270
-msgid "Number of new GwG files in the last year"
-msgstr "Numero di nuovi fascicoli GwG nell'ultimo anno"
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:202
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:278
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:128
+msgid "Account properties"
+msgstr "Proprietà del conto"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:273
-msgid "Number of GwG files closed in the last year"
-msgstr "Numero di fascicoli GwG chiusi nell'ultimo anno"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:214
+#, fuzzy
+#| msgid "Decision date"
+msgid "Decision row"
+msgstr "Data della decisione"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:276
-msgid "Number of MROS reports based on Art 9 Abs. 1 GwG (per year)"
-msgstr "Numero di segnalazioni MROS basate sull'Art. 9 cpv. 1 GwG (all'anno)"
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:217
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:174
+msgid "Officer public key"
+msgstr "Chiave pubblica dell’operatore"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:279
-msgid "Number of MROS reports based on Art 305ter Abs. 2 StGB (per year)"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:219
+msgid "Not applicable"
msgstr ""
-"Numero di segnalazioni MROS basate sull'Art. 305ter cpv. 2 StGB (all'anno)"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:282
-msgid "Number of GwG files of high-risk customers"
-msgstr "Numero di fascicoli GwG di clienti ad alto rischio"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:277
+#, fuzzy
+#| msgid "System information"
+msgid "Stored custom definition"
+msgstr "Informazioni di sistema"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:285
-msgid "Number of GwG files managed with “increased risk” due to PEP status"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:284
+msgid ""
+"Current measure metadata is still loading; the stored machine name is shown."
msgstr ""
-"Numero di fascicoli GwG gestiti con \"rischio aumentato\" a causa dello "
-"stato PEP"
-
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:288
-#, fuzzy
-msgid "Number of customers with open proceeding."
-msgstr "Numero di conti aperti"
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:343
-msgid "previous"
-msgstr "precedente"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:286
+msgid ""
+"The current measure configuration could not be loaded; the stored machine "
+"name is shown."
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:386
-msgid "Decreased by"
-msgstr "Diminuito di"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:287
+msgid ""
+"No stored or currently configured definition is available for this reference."
+msgstr ""
-#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:390
-msgid "Increased by"
-msgstr "Aumentato di"
+#. screenid: 123
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:291
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:80
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:178
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:659
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:938
+msgid "Check"
+msgstr "Verifica"
-#. screenid: 108
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:115
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:217
-msgid "Events"
-msgstr "Eventi"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:295
+msgid "Built-in check that requires no customer interaction."
+msgstr ""
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:116
-msgid ""
-"The events will be triggered only after the decision has been confirmed."
-msgstr "Gli eventi verranno attivati solo dopo la conferma della decisione."
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:296
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:304
+#, fuzzy
+#| msgid "Attributes unavailable"
+msgid "Description unavailable"
+msgstr "Attributi non disponibili"
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:121
-msgid "Calculated"
-msgstr "Calcolato"
+#. screenid: 123
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:299
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:86
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:268
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:639
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:891
+msgid "Program"
+msgstr "Programma"
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:122
-msgid "Events based on properties and new attributes that should be triggered"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:316
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:508
+msgid "Voluntary"
msgstr ""
-"Eventi basati su proprietà e nuovi attributi che dovrebbero essere attivati"
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:134
-msgid "Others"
-msgstr "Altri"
+#. screenid: 123
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:320
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:92
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:184
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:280
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:682
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:907
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:644
+msgid "Context"
+msgstr "Contesto"
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:135
-msgid "Events that can be triggered manually"
-msgstr "Eventi che possono essere attivati manualmente"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:349
+msgid "Decision date"
+msgstr "Data della decisione"
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:147
-msgid "Custom list"
-msgstr "Elenco personalizzato"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:357
+msgid "Expired"
+msgstr "Scaduto"
-#. screenid: 108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:148
-msgid "Events without built-in support."
-msgstr "Eventi senza supporto integrato."
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:357
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:419
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:354
+msgid "Expires"
+msgstr "Scade"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:132
-msgid "Complete the form"
-msgstr "Completa il modulo"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:362
+#, fuzzy
+#| msgid "Decision date"
+msgid "Decision status"
+msgstr "Data della decisione"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:135
-msgid "These measures will ask the customer for information."
-msgstr "Queste misure chiederanno informazioni al cliente."
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:363
+#, fuzzy
+#| msgid "Send decision"
+msgid "Current"
+msgstr "Invia decisione"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:153
-msgid "change form"
-msgstr "cambia modulo"
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:363
+msgid "Historical"
+msgstr ""
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:158
-msgid "Expiration date of the information filled in this form."
-msgstr "Data di scadenza delle informazioni compilate in questo modulo."
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:365
+msgid "Made by"
+msgstr ""
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:217
-msgid "Include new information"
-msgstr "Includi nuove informazioni"
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/components/ShowDecisionLimitInfo.tsx:368
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:272
+#, fuzzy
+#| msgid "AML officer public key"
+msgid "AML officer"
+msgstr "Chiave pubblica dell’ufficiale AML"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:218
-msgid ""
-"Select a form to submit new information about the customer or continue to "
-"the next step"
-msgstr ""
-"Seleziona un modulo per inviare nuove informazioni sul cliente oppure "
-"continua al passaggio successivo"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:44
+msgid "Forms"
+msgstr "Moduli"
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:223
-msgid "Form:"
-msgstr "Modulo:"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:47
+msgid "Measures used to gather information about the customer."
+msgstr "Misure utilizzate per raccogliere informazioni sul cliente."
-#. screenid: 106
-#. screenid: 113
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:81
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:227
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:237
-msgid "Justification"
-msgstr "Giustificazione"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:62
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:160
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:250
+msgid "Select"
+msgstr "Seleziona"
-#. screenid: 106
-#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:86
-msgid "Keep investigation?"
-msgstr "Mantenere l'indagine?"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:107
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:199
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:295
+msgid "Modify"
+msgstr "Modifica"
-#. screenid: 106
-#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:91
-msgid "Account holder"
-msgstr "Titolare del conto"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:141
+#, fuzzy
+#| msgid "System information"
+msgid "Information"
+msgstr "Informazioni di sistema"
-#. screenid: 106
-#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:93
-msgid "Full name of the account holder"
-msgstr "Nome completo del titolare del conto"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:144
+#, fuzzy
+#| msgid "KYC information filed by the customer or an AML officer."
+msgid "Shows information to the customer without running an AML program."
+msgstr "Informazioni KYC inserite dal cliente o da un addetto AML."
-#. screenid: 122
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:90
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:394
-msgid "loading..."
-msgstr "caricamento..."
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:232
+msgid "Instant measures"
+msgstr "Misure istantanee"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:239
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:421
-msgid "Update"
-msgstr "Aggiorna"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:235
+msgid "Triggered immediately without customer interaction."
+msgstr "Attivate immediatamente senza interazione del cliente."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:246
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:428
-msgid "Remove"
-msgstr "Rimuovi"
+#. screenid: 123
+#: packages/taler-exchange-aml-webui/src/components/MeasuresTable.tsx:274
+msgid "Input requirement"
+msgstr "Requisito di input"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:473
-msgid "Configure verification type: %1$s"
-msgstr "Configura il tipo di verifica: %1$s"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:56
+msgid "Started"
+msgstr "Avviato"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:484
-msgid "Show complete form"
-msgstr "Mostra modulo completo"
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:64
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:301
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:140
+msgid "Status"
+msgstr "Stato"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:505
-msgid "Configure measure"
-msgstr "Configura misura"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:76
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:447
+msgid "Forbidden"
+msgstr "Vietato"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:515
-msgid "Show as verification"
-msgstr "Mostra come verifica"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:78
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:443
+msgid "Completed"
+msgstr "Completato"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:557
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:998
-msgid "There is already a measure with that name"
-msgstr "Esiste già una misura con quel nome"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:79
+msgid "Waiting for customer"
+msgstr "In attesa del cliente"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:571
-msgid "Only required when no check is specified"
-msgstr "Obbligatorio solo quando non è specificata alcuna verifica"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:92
+msgid "The operation is categorically forbidden by this requirement."
+msgstr "Questo requisito vieta categoricamente l’operazione."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:575
-msgid "Missing check or program"
-msgstr "Verifica o programma mancante"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:100
+msgid "All listed measures must be completed."
+msgstr "Tutte le misure elencate devono essere completate."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:585
-msgid "Without a check the program will run automatically"
-msgstr "Senza una verifica, il programma verrà eseguito automaticamente"
+#: packages/taler-exchange-aml-webui/src/components/ShowLegitimizationInfo.tsx:104
+msgid "Any one listed measure may be completed."
+msgstr "È possibile completare una qualsiasi delle misure elencate."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:614
-msgid "Field name"
-msgstr "Nome del campo"
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:24
+msgid "Expiration shortcuts"
+msgstr "Scorciatoie di scadenza"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:619
-msgid "Type"
-msgstr "Tipo"
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:29
+msgid "In a week"
+msgstr "Tra una settimana"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:623
-msgid "string"
-msgstr "stringa"
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:30
+msgid "In a month"
+msgstr "Tra un mese"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:627
-msgid "number"
-msgstr "numero"
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:31
+msgid "In a year"
+msgstr "Tra un anno"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:631
-msgid "boolean"
-msgstr "booleano"
+#: packages/taler-exchange-aml-webui/src/components/ExpirationShortcuts.tsx:50
+msgid "Never"
+msgstr "Mai"
#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:635
-msgid "json"
-msgstr "json"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:115
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:98
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:63
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:72
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:209
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:218
+msgid "Failed to load available measures."
+msgstr "Impossibile caricare le misure disponibili."
#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:644
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:197
-msgid "Value"
-msgstr "Valore"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:120
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:112
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:77
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:223
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:294
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:480
+msgid "The officer session is invalid."
+msgstr "La sessione dell’addetto AML non è valida."
#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:663
-msgid "There are unsatisfied inputs: %1$s"
-msgstr "Ci sono input non soddisfatti: %1$s"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:124
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:116
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:81
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:227
+msgid "The measures endpoint was not found."
+msgstr "L’endpoint delle misure non è stato trovato."
#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:674
-msgid "There are missing inputs: %1$s"
-msgstr "Ci sono input mancanti: %1$s"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:130
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:122
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:87
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:233
+msgid "The officer session is disabled."
+msgstr "La sessione dell’addetto AML è disabilitata."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:694
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:711
-msgid "There are missing requirements: %1$s"
-msgstr "Ci sono requisiti mancanti: %1$s"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:195
+msgid "Edit proposed rule"
+msgstr "Modifica regola proposta"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:751
-msgid "Can't be empty"
-msgstr "Non può essere vuoto"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:197
+msgid "Add proposed rule"
+msgstr "Aggiungi regola proposta"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:755
-msgid "It should be a number"
-msgstr "Deve essere un numero"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:216
+msgid "Save rule"
+msgstr "Salva regola"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:757
-msgid "Not a number"
-msgstr "Non è un numero"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:218
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:372
+msgid "Add rule"
+msgstr "Aggiungi regola"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:759
-msgid "It should be finite"
-msgstr "Deve essere finito"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:356
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:348
+#, fuzzy
+#| msgid "Properties"
+msgid "Proposed rules"
+msgstr "Proprietà"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:761
-msgid "It should be a safe integer"
-msgstr "Deve essere un intero sicuro"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:359
+msgid ""
+"This complete rule set replaces the currently applied rules and exchange "
+"defaults until it expires. Higher rows take precedence."
+msgstr ""
+"Questo insieme completo sostituisce le regole attualmente applicate e quelle "
+"predefinite dell’exchange fino alla scadenza. Le righe più in alto hanno la "
+"precedenza."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:766
-msgid "It should be either \"true\" or \"false\""
-msgstr "Deve essere \"true\" o \"false\""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:390
+msgid "Rules for another account type"
+msgstr "Regole per un altro tipo di conto"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:771
-msgid "Couldn't parse as json string: %1$s"
-msgstr "Impossibile analizzare come stringa json: %1$s"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:393
+msgid "These operations do not apply to this account type: %1$s."
+msgstr "Queste operazioni non si applicano a questo tipo di conto: %1$s."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:797
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:940
-msgid "Description"
-msgstr "Descrizione"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:400
+msgid "Operations without limits"
+msgstr "Operazioni senza limiti"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:813
-msgid "Inputs"
-msgstr "Input"
-
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:849
-msgid "Output"
-msgstr "Output"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:401
+msgid "No proposed rule limits these operations: %1$s."
+msgstr "Nessuna regola proposta limita queste operazioni: %1$s."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:859
-msgid "Requires"
-msgstr "Richiede"
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:408
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:336
+msgid "Invalid proposed rules"
+msgstr "Regole proposte non valide"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:867
-msgid "Fallback"
-msgstr "Fallback"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:409
+msgid ""
+"Edit the highlighted rule set before continuing. Hard blocks cannot be "
+"combined with measures, and Balance and Refund rules must use an instant "
+"timeframe."
+msgstr ""
+"Modifica l’insieme di regole evidenziato prima di continuare. I blocchi "
+"rigidi non possono essere combinati con misure e le regole per saldo e "
+"rimborso devono usare un intervallo istantaneo."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:993
-msgid "Name of the verification measure"
-msgstr "Nome della misura di verifica"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:432
+msgid "Remove proposed rule?"
+msgstr "Rimuovere la regola proposta?"
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1005
-msgid "Read only"
-msgstr "Sola lettura"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:434
+msgid ""
+"This is the final rule. Removing it leaves every applicable operation "
+"unlimited."
+msgstr ""
+"Questa è l’ultima regola. Rimuovendola, tutte le operazioni applicabili "
+"resteranno senza limiti."
-#. screenid: 122
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1006
-msgid "Prevent the customer from changing the address"
-msgstr "Impedisce al cliente di modificare l'indirizzo"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:439
+msgid "The rule will be removed from the proposed set."
+msgstr "La regola verrà rimossa dall’insieme proposto."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:256
-msgid "Configure verification measure: \"%1$s\""
-msgstr "Configura misura di verifica: \"%1$s\""
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:449
+msgid "Keep rule"
+msgstr "Mantieni regola"
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:294
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:115
-msgid "Add custom measure"
-msgstr "Aggiungi misura personalizzata"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:459
+msgid "Remove rule"
+msgstr "Rimuovi regola"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:300
-msgid "Custom measures"
-msgstr "Misure personalizzate"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:467
+msgid "Replace proposed rules"
+msgstr "Sostituisci regole proposte"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:329
-msgid "Server measures"
-msgstr "Misure del server"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:470
+msgid "Preview a complete replacement before applying it."
+msgstr ""
+"Visualizza l’anteprima della sostituzione completa prima di applicarla."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:426
-msgid "New measures"
-msgstr "Nuove misure"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:476
+msgid "Currently applied"
+msgstr "Attualmente applicate"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:427
-msgid ""
-"Measures that are available/executed directly after the decision is "
-"confirmed."
-msgstr ""
-"Misure disponibili/eseguite immediatamente dopo la conferma della decisione."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:486
+msgid "E-commerce"
+msgstr "E-commerce"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:154
-msgid "Reset to default"
-msgstr "Ripristina i valori predefiniti"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:489
+msgid "Point of Sale"
+msgstr "Punto vendita"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:175
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:234
-msgid "Properties"
-msgstr "Proprietà"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:496
+msgid "Basic plan"
+msgstr "Piano base"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:181
-msgid "Custom properties"
-msgstr "Proprietà personalizzate"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:501
+msgid "Premium"
+msgstr "Premium"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:182
-msgid "Add more properties that are not listed above."
-msgstr "Aggiungi altre proprietà non elencate sopra."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:510
+msgid "Freeze account"
+msgstr "Congela conto"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:187
-msgid "New properties"
-msgstr "Nuove proprietà"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:518
+msgid "Replacement preview"
+msgstr "Anteprima della sostituzione"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:218
-msgid "Current note on the GwG file"
-msgstr "Nota attuale sul fascicolo GwG"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:521
+msgid "Confirm account freeze"
+msgstr "Conferma il blocco del conto"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:223
-msgid "Customer name or internal alias."
-msgstr "Nome del cliente o alias interno."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:522
+msgid "Every applicable operation will receive a zero hard limit."
+msgstr "Ogni operazione applicabile riceverà un limite rigido pari a zero."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:228
-msgid "Is the account active for deposit and payments?"
-msgstr "Il conto è attivo per depositi e pagamenti?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:548
+msgid "Apply replacement"
+msgstr "Applica sostituzione"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:233
-msgid "Is the account idle?"
-msgstr "Il conto è inattivo?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:556
+#, fuzzy
+#| msgid "Reset expiration"
+msgid "Rule expiration"
+msgstr "Reimposta scadenza"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:234
-msgid "No operation for a period of time"
-msgstr "Nessuna operazione per un periodo di tempo"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:559
+msgid "Choose how long the proposed rules apply and what happens afterwards."
+msgstr ""
+"Scegli per quanto tempo si applicano le regole proposte e cosa accade dopo."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:239
-msgid "Does account belong to a domestic PEP?"
-msgstr "Il conto appartiene a un PEP nazionale?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:578
+msgid "The proposed rules never expire, so no successor action will run."
+msgstr ""
+"Le regole proposte non scadono mai, quindi non verrà eseguita alcuna azione "
+"successiva."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:244
-msgid "Does account belong to a foreign PEP?"
-msgstr "Il conto appartiene a un PEP straniero?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:598
+msgid "Restore currently applied expiration"
+msgstr "Ripristina la scadenza attualmente applicata"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:249
-msgid "Does account belong to an international-organization PEP?"
-msgstr "Il conto appartiene a un PEP di organizzazione internazionale?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:682
+msgid "Operation type"
+msgstr "Tipo di operazione"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:254
-msgid "Does account belong to a high risk customer?"
-msgstr "Il conto appartiene a un cliente ad alto rischio?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:704
+msgid "Timeframe"
+msgstr "Intervallo di tempo"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:259
-msgid "Does account belong to a person from a high risk country?"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:705
+msgid ""
+"Use Y, M, D, h, m or s after each number. Forever accumulates over the "
+"account's full history."
msgstr ""
-"Il conto appartiene a una persona proveniente da un paese ad alto rischio?"
-
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:264
-msgid "The MROS reporting state for the account."
-msgstr "Lo stato di segnalazione MROS per il conto."
+"Usa Y, M, D, h, m o s dopo ogni numero. «Per sempre» accumula l’intera "
+"cronologia del conto."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:269
-msgid "None"
-msgstr "Nessuno"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:709
+msgid "Instant timeframe"
+msgstr "Intervallo istantaneo"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:273
-msgid "Pending investigation"
-msgstr "Indagine in corso"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:710
+msgid ""
+"Balance and Refund limits apply to one balance or transaction, so their "
+"timeframe is fixed to zero."
+msgstr ""
+"I limiti per saldo e rimborso si applicano a un saldo o a una transazione, "
+"quindi il loro intervallo è fissato a zero."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:277
-msgid "Investigated without suspicion"
-msgstr "Indagato senza sospetti"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:716
+msgid "Exposed"
+msgstr "Esposto"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:281
-msgid "Reported simple suspicion"
-msgstr "Sospetto semplice segnalato"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:717
+msgid "Is this limit communicated to the customer?"
+msgstr "Questo limite viene comunicato al cliente?"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:285
-msgid "Reported substantiated suspicion"
-msgstr "Sospetto comprovato segnalato"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:723
+msgid "When the threshold is crossed"
+msgstr "Quando viene superata la soglia"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:292
-msgid "Informal reason why the AML investigation was triggered"
-msgstr "Motivo informale per cui è stata avviata l'indagine AML"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:726
+msgid "Require measures"
+msgstr "Richiedi misure"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:297
-msgid "Identifies the sanction list entry that the account matched against"
-msgstr ""
-"Identifica la voce dell'elenco sanzionatorio con cui il conto corrisponde"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:740
+msgid "Required measures"
+msgstr "Misure richieste"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:299
-msgid "Best match, does not mean it was a good match."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:741
+msgid ""
+"Measures that the customer will need to satisfy to apply for a new threshold."
msgstr ""
-"Migliore corrispondenza, non significa che fosse una buona corrispondenza."
+"Misure che il cliente dovrà soddisfare per richiedere una nuova soglia."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:303
-msgid "Score for how good the sanction list match was"
-msgstr ""
-"Punteggio di quanto buona sia stata la corrispondenza con l'elenco "
-"sanzionatorio"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:747
+msgid "All measures"
+msgstr "Tutte le misure"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:308
-msgid "Score for how much supporting data we had for the sanction list match"
-msgstr ""
-"Punteggio di quanti dati di supporto avevamo per la corrispondenza con "
-"l'elenco sanzionatorio"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:748
+msgid "Hint the customer that all measures should be completed"
+msgstr "Segnala al cliente che tutte le misure devono essere completate"
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:313
-msgid ""
-"Suppress flagging this account when it creates a hit on a sanctions list, "
-"this is a false-positive"
-msgstr ""
-"Sopprimi la segnalazione di questo conto quando genera una corrispondenza in "
-"un elenco sanzionatorio, si tratta di un falso positivo"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:767
+msgid "Expiration date"
+msgstr "Data di scadenza"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:190
-#, fuzzy
-msgid "Failed to make the decision."
-msgstr "Descrivi la decisione."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:768
+msgid "Until when are the new rules active."
+msgstr "Fino a quando sono attive le nuove regole."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:193
-#, fuzzy
-msgid "Invalid credentials."
-msgstr "Credenziali invalide."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:773
+msgid "Choose a future expiration date or Never."
+msgstr "Scegli una data di scadenza futura oppure «Mai»."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:197
-#, fuzzy
-msgid ""
-"The session is disabled or a more recent decision was already submitted."
-msgstr ""
-"Ufficiale disabilitato o è già stata inviata una decisione più recente."
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:779
+msgid "After expiration"
+msgstr "Dopo la scadenza"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:208
-msgid "Confirmation required"
-msgstr "Conferma richiesta"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:781
+msgid "Return to exchange defaults"
+msgstr "Torna alle impostazioni predefinite dell’exchange"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:209
-#, fuzzy
-msgid ""
-"This decision declares that the MROS report has concluded. Please make sure "
-"that this is the case"
-msgstr ""
-"Questa decisione dichiara che la segnalazione MROS è stata conclusa. "
-"Assicurati che sia effettivamente così"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:782
+msgid "Trigger a successor measure"
+msgstr "Attiva una misura successiva"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:222
-msgid "I want to check first!"
-msgstr "Voglio prima controllare!"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:797
+msgid "Measure taken automatically upon expiration of the current decision."
+msgstr "Misura adottata automaticamente alla scadenza della decisione attuale."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:229
-msgid "Confirm decision"
-msgstr "Conferma decisione"
+#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:805
+msgid "This successor measure is no longer available."
+msgstr "Questa misura successiva non è più disponibile."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:245
-msgid "Missing deadline"
-msgstr "Scadenza mancante"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:133
+msgid "Case summary"
+msgstr "Riepilogo del caso"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:248
-msgid ""
-"Deadline should specify when this rules ends and what is the next measures "
-"to apply after expiration."
-msgstr ""
-"La scadenza deve specificare quando termina questa regola e quali sono le "
-"prossime misure da applicare dopo la scadenza."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:134
+msgid "Current review state and the latest account activity."
+msgstr "Stato attuale della revisione e attività più recente del conto."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:257
-msgid "Missing rules"
-msgstr "Regole mancanti"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:138
+msgid "Review status"
+msgstr "Stato della revisione"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:260
-msgid "Can't make a decision without rules."
-msgstr "Impossibile prendere una decisione senza regole."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:142
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:153
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:171
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:188
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:492
+msgid "Loading…"
+msgstr "Caricamento…"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:284
-msgid "Missing active measure"
-msgstr "Misura attiva mancante"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:146
+msgid "Manual review required — waiting for an AML decision."
+msgstr "Revisione manuale richiesta — in attesa di una decisione AML."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:287
-msgid "You should specify in the measure section."
-msgstr "Devi specificarlo nella sezione delle misure."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:147
+msgid "No manual review"
+msgstr "Nessuna revisione manuale"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:294
-msgid "No customer action required."
-msgstr "Non è richiesta alcuna azione da parte del cliente."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:150
+msgid "Effective decision"
+msgstr "Decisione in vigore"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:297
-msgid "No active measure has been selected."
-msgstr "Non è stata selezionata alcuna misura attiva."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:168
+msgid "Requirements"
+msgstr "Requisiti"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:305
-msgid "Missing properties"
-msgstr "Proprietà mancanti"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:185
+msgid "Latest collected information"
+msgstr "Ultime informazioni raccolte"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:308
-msgid "You should specify in the properties section."
-msgstr "Devi specificarlo nella sezione delle proprietà."
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:208
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:305
+#, fuzzy
+#| msgid "Send decision"
+msgid "Current decision"
+msgstr "Invia decisione"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:318
-msgid "Missing events"
-msgstr "Eventi mancanti"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:209
+#, fuzzy
+#| msgid ""
+#| "The AML decision and operation rules currently applied to this account."
+msgid "The complete AML decision currently applied to this account."
+msgstr ""
+"La decisione AML e le regole operative attualmente applicate a questo conto."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:321
-msgid "You should specify in the events section."
-msgstr "Devi specificarlo nella sezione degli eventi."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:216
+msgid "Effective policy could not be loaded"
+msgstr "Impossibile caricare la politica effettiva"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:331
-msgid "Missing justification"
-msgstr "Giustificazione mancante"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:234
+msgid "Exchange defaults apply"
+msgstr "Si applicano le regole predefinite dell’Exchange"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:334
-msgid "You must complete the justification section."
-msgstr "Devi completare la sezione della giustificazione."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:235
+msgid "No AML officer decision is active for this account."
+msgstr "Nessuna decisione di un addetto AML è attiva per questo conto."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:344
-msgid "Invalid attributes"
-msgstr "Attributi non validi"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:238
+msgid "Account type unavailable"
+msgstr "Tipo di conto non disponibile"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:347
-msgid "You should check form errors or submit a decision without attributes."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:239
+msgid ""
+"Open this case from the account directory or payto search to see the "
+"applicable default rules."
msgstr ""
-"Controlla gli errori del modulo oppure invia una decisione senza attributi."
+"Aprire questo caso dalla directory dei conti o dalla ricerca payto per "
+"visualizzare le regole predefinite applicabili."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:361
-msgid "Clear"
-msgstr "Cancella"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:248
+msgid "Default rules could not be loaded"
+msgstr "Impossibile caricare le regole predefinite"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:368
-msgid "Send decision"
-msgstr "Invia decisione"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:255
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:419
+#: packages/taler-exchange-aml-webui/src/components/ShowDefaultRules.tsx:11
+msgid "Default rules"
+msgstr "Regole predefinite"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:173
-msgid "Prev"
-msgstr "Prec."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:266
+msgid "Collected information"
+msgstr "Informazioni raccolte"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:182
-msgid "Next"
-msgstr "Successivo"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:267
+msgid "KYC information filed by the customer or an AML officer."
+msgstr "Informazioni KYC inserite dal cliente o da un addetto AML."
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:207
-msgid "Attributes"
-msgstr "Attributi"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:273
+msgid "Collected information could not be loaded"
+msgstr "Impossibile caricare le informazioni raccolte"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:208
-msgid "Add more information about the customer"
-msgstr "Aggiungi ulteriori informazioni sul cliente"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:279
+msgid "No collected information"
+msgstr "Nessuna informazione raccolta"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:212
-msgid "Rules"
-msgstr "Regole"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:280
+msgid "No KYC information has been collected for this account."
+msgstr "Non sono state raccolte informazioni KYC per questo conto."
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:213
-msgid "Set the limit of the operations"
-msgstr "Imposta il limite delle operazioni"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:302
+msgid "Active requirements"
+msgstr "Requisiti attivi"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:218
-msgid "Trigger notifications."
-msgstr "Attiva le notifiche."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:303
+msgid "Measures the customer must complete under the current policy."
+msgstr "Misure che il cliente deve completare secondo la politica attuale."
-#. screenid: 113
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:222
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:102
-msgid "Measures"
-msgstr "Misure"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:309
+msgid "Active requirements could not be loaded"
+msgstr "Impossibile caricare i requisiti attivi"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:223
-msgid "Ask the customer to take action."
-msgstr "Chiedi al cliente di intervenire."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:315
+msgid "No active requirements"
+msgstr "Nessun requisito attivo"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:228
-msgid "Describe the decision."
-msgstr "Descrivi la decisione."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:316
+msgid "The customer has no active legitimization measures to complete."
+msgstr "Il cliente non ha misure di legittimazione attive da completare."
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:235
-msgid "Flag the current account state."
-msgstr "Contrassegna lo stato attuale del conto."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:413
+msgid "Officer decision"
+msgstr "Decisione dell’addetto"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:239
-msgid "Summary"
-msgstr "Riepilogo"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:416
+msgid "Does not expire"
+msgstr "Non scade"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:240
-msgid "Review and submit."
-msgstr "Rivedi e invia."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:439
+msgid "Waiting"
+msgstr "In attesa"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:404
-msgid "Decision for account:"
-msgstr "Decisione per il conto:"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:451
+msgid "More on later pages"
+msgstr "Altri elementi nelle pagine successive"
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:411
-msgid "Decision for wallet:"
-msgstr "Decisione per il portafoglio:"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:510
+msgid "Try loading this section again."
+msgstr "Provare a ricaricare questa sezione."
-#. screenid: 113
-#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:417
-msgid "Decision for bank account:"
-msgstr "Decisione per il conto bancario:"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:518
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:97
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:633
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:205
+msgid "Retry"
+msgstr "Riprova"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:88
-msgid "Search account"
-msgstr "Cerca conto"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:566
+msgid "Unconfigured form"
+msgstr "Modulo non configurato"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:154
-msgid "Failed to load account decisions."
-msgstr ""
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:567
+msgid "Form not identified"
+msgstr "Modulo non identificato"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:163
-#, fuzzy
-msgid "Failed to load the account history."
-msgstr "Nome completo del titolare del conto"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:576
+msgid "Filed by an AML officer"
+msgstr "Inserito da un addetto AML"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:205
-msgid "Check account details"
-msgstr "Controlla i dettagli del conto"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:577
+msgid "Provided by the customer"
+msgstr "Fornito dal cliente"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:212
-msgid "Account most recent decisions"
-msgstr "Decisioni più recenti del conto"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:581
+msgid "Attribute data is unavailable."
+msgstr "I dati degli attributi non sono disponibili."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:231
-msgid "When"
-msgstr "Quando"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:595
+msgid "View details"
+msgstr "Vedi dettagli"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:265
-msgid "LATEST"
-msgstr "ULTIMA"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:70
+msgid ""
+"Review superseded AML decisions for this account, from newest to oldest."
+msgstr ""
+"Esamina le decisioni AML sostituite per questo conto, dalla più recente alla "
+"meno recente."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:270
-msgid "ACTIVE"
-msgstr "ATTIVA"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:79
+msgid "Loading decision history…"
+msgstr "Caricamento della cronologia delle decisioni…"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:297
-msgid "Account not found"
-msgstr "Conto non trovato"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:84
+msgid "Decision history could not be loaded"
+msgstr "Impossibile caricare la cronologia delle decisioni"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:298
-msgid "There is no history known for this account yet."
-msgstr "Non è ancora nota alcuna cronologia per questo conto."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:87
+msgid "Try loading the decision history again."
+msgstr "Prova a caricare di nuovo la cronologia delle decisioni."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:308
-msgid "You can make a decision for this account anyway."
-msgstr "Puoi comunque prendere una decisione per questo conto."
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:111
+msgid "No previous decisions"
+msgstr "Nessuna decisione precedente"
-#. screenid: 111
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:357
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:400
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:449
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:490
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:377
-msgid "Search"
-msgstr "Cerca"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:114
+msgid "No superseded AML decisions have been recorded for this account."
+msgstr "Non sono state registrate decisioni AML sostituite per questo conto."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:528
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:761
-msgid "IBAN"
-msgstr "IBAN"
+#: packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx:125
+msgid "Previous decisions"
+msgstr "Decisioni precedenti"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:532
-msgid "Taler Bank"
-msgstr "Taler Bank"
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:153
+msgid "The export could not be prepared. Try again."
+msgstr "Non è stato possibile preparare l’esportazione. Riprova."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:536
-msgid "Wallet"
-msgstr "Portafoglio"
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:164
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:173
+msgid "Failed to load accounts"
+msgstr "Impossibile caricare i conti"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:540
-msgid "Generic Payto:// URI"
-msgstr "URI Payto:// generico"
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:193
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:552
+msgid "Accounts"
+msgstr "Conti"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:543
-msgid "Account type"
-msgstr "Tipo di conto"
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:196
+msgid "Review accounts known to the exchange for AML and KYC handling."
+msgstr "Esamina i conti noti all’exchange per la gestione AML e KYC."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:553
-msgid "Should be 52 characters."
-msgstr "Deve essere di 52 caratteri."
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:203
+msgid "Export filtered accounts"
+msgstr "Esporta i conti filtrati"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:555
-msgid "Failed to parse: %1$s"
-msgstr "Impossibile analizzare: %1$s"
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:211
+msgid "Download CSV"
+msgstr "Scarica CSV"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:567
-msgid "Address contains invalid characters."
-msgstr "L'indirizzo contiene caratteri non validi."
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:218
+msgid "Download Excel"
+msgstr "Scarica Excel"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:569
-msgid "Can't mix uppercased and lowercased characters."
-msgstr "Impossibile combinare caratteri maiuscoli e minuscoli."
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:226
+msgid "Preparing export…"
+msgstr "Preparazione dell’esportazione…"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:571
-msgid "The addr checksum doesn't match."
-msgstr "Il checksum dell'indirizzo non corrisponde."
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:230
+msgid "Export failed"
+msgstr "Esportazione non riuscita"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:573
-msgid "Missing separator or address type."
-msgstr "Separatore o tipo di indirizzo mancante."
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:236
+msgid "Account filters"
+msgstr "Filtri dei conti"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:575
-msgid "Address should have less than 90 characters."
-msgstr "L'indirizzo deve avere meno di 90 caratteri."
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:242
+msgid "Investigation"
+msgstr "Indagine"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:577
-msgid "Address should have more than 6 characters."
-msgstr "L'indirizzo deve avere più di 6 caratteri."
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:244
+msgid "All accounts"
+msgstr "Tutti i conti"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:579
-msgid "Decoding issue."
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:251
+msgid "Risk"
+msgstr "Rischio"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:253
+msgid "All risk levels"
+msgstr "Tutti i livelli di rischio"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:255
+msgid "Not high risk"
+msgstr "Senza rischio elevato"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:260
+msgid "File status"
+msgstr "Stato del fascicolo"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:262
+msgid "All file statuses"
+msgstr "Tutti gli stati del fascicolo"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:264
+msgid "Not open"
+msgstr "Non aperto"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:273
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:589
+msgid "Clear filters"
+msgstr "Cancella filtri"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:283
+msgid "Showing %1$s accounts · newest first"
+msgstr "Visualizzati %1$s conti · prima i più recenti"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:290
+msgid "AML and KYC accounts"
+msgstr "Conti AML e KYC"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:298
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:458
+msgid "Account lifecycle"
+msgstr "Ciclo di vita del fascicolo"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:304
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:467
+msgid "Latest note"
+msgstr "Nota più recente"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:550
+msgid "Copied"
+msgstr "Copiato"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:550
+msgid "Copy"
+msgstr "Copia"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:576
+msgid "No matching accounts"
+msgstr "Nessun conto corrispondente"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:576
+msgid "No accounts yet"
+msgstr "Ancora nessun conto"
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:580
+msgid "No accounts match the selected filters."
+msgstr "Nessun conto corrisponde ai filtri selezionati."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:581
+msgid "The exchange has not recorded any AML or KYC accounts yet."
+msgstr "L’exchange non ha ancora registrato alcun conto AML o KYC."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:647
+msgid "This officer session is not authorized to list accounts."
+msgstr "Questa sessione operatore non è autorizzata a elencare i conti."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:649
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:674
+msgid "The exchange does not recognize this officer session."
+msgstr "L’exchange non riconosce questa sessione operatore."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:651
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:676
+msgid "This officer session is currently disabled."
+msgstr "Questa sessione operatore è attualmente disabilitata."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:668
+msgid "There are no matching accounts to export."
+msgstr "Non ci sono conti corrispondenti da esportare."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:670
+msgid "The exchange does not support the selected export format."
+msgstr "L’exchange non supporta il formato di esportazione selezionato."
+
+#: packages/taler-exchange-aml-webui/src/pages/AccountList.tsx:672
+msgid "This officer session is not authorized to export accounts."
+msgstr "Questa sessione operatore non è autorizzata a esportare i conti."
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:52
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:546
+msgid "Dashboard"
+msgstr "Dashboard"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:55
+msgid ""
+"Review cases requiring attention, investigate accounts, and monitor AML "
+"reporting indicators."
msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:581
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:77
+msgid "Review case queue"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:80
#, fuzzy
-msgid "Invalid data"
-msgstr "Host non valido"
+#| msgid "Accounts under investigation."
+msgid "Review accounts currently under investigation."
+msgstr "Conti sotto indagine."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:591
-msgid "Unsupported country."
-msgstr "Paese non supportato."
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:94
+#, fuzzy
+#| msgid "Show transfers"
+msgid "Inspect transfers"
+msgstr "Mostra trasferimenti"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:593
-msgid "IBANs have fewer than 34 characters."
-msgstr "Gli IBAN hanno meno di 34 caratteri."
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:97
+msgid "Find credit, debit, and KYC authorization activity."
+msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:595
-msgid "IBANs have more than 4 characters."
-msgstr "Gli IBAN hanno più di 4 caratteri."
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:128
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:165
+msgid "Statistics"
+msgstr "Statistiche"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:597
-msgid "IBAN length is invalid for this country."
-msgstr "La lunghezza dell'IBAN non è valida per questo paese."
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:132
+msgid "No reporting profile for this dialect"
+msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:597
-msgid "It should only contain numbers and letters."
-msgstr "Deve contenere solo numeri e lettere."
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:137
+msgid ""
+"The testing dialect does not define dashboard statistics. Select TOPS in "
+"development settings to inspect the TOPS reporting profile."
+msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:599
-msgid "The checksum is wrong."
-msgstr "Il checksum è errato."
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:154
+msgid "Failed to load TOPS statistics."
+msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:617
-msgid "The string should start with payto://"
-msgstr "La stringa deve iniziare con payto://"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:192
+#, fuzzy
+#| msgid "Attributes unavailable"
+msgid "Some statistics are unavailable."
+msgstr "Attributi non disponibili"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:619
-msgid "After the target type it should follow a '/' with more information."
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:195
+msgid "The available values are shown below. Missing values are not zero."
msgstr ""
-"Dopo il tipo di destinazione deve seguire un '/' con ulteriori informazioni."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:621
-msgid ""
-"The target type is not supported, only x-taler-bank, taler-reserve or iban"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:275
+msgid "Accounts open"
+msgstr "Conti aperti"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:278
+msgid "New files last year"
+msgstr "Nuovi fascicoli nell'ultimo anno"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:281
+msgid "Closed files last year"
+msgstr "Fascicoli chiusi nell'ultimo anno"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:284
+msgid "MROS substantiated"
+msgstr "MROS comprovate"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:287
+msgid "MROS simple"
+msgstr "MROS semplici"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:290
+msgid "High risk files"
+msgstr "Fascicoli ad alto rischio"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:293
+msgid "PEP files"
+msgstr "Fascicoli PEP"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:333
+msgid "Number of accounts that are opened"
+msgstr "Numero di conti aperti"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:336
+msgid "Number of new GwG files in the last year"
+msgstr "Numero di nuovi fascicoli GwG nell'ultimo anno"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:339
+msgid "Number of GwG files closed in the last year"
+msgstr "Numero di fascicoli GwG chiusi nell'ultimo anno"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:342
+msgid "Number of MROS reports based on Art 9 Abs. 1 GwG (per year)"
+msgstr "Numero di segnalazioni MROS basate sull'Art. 9 cpv. 1 GwG (all'anno)"
+
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:345
+msgid "Number of MROS reports based on Art 305ter Abs. 2 StGB (per year)"
msgstr ""
-"Il tipo di destinazione non è supportato, solo x-taler-bank, taler-reserve o "
-"iban"
+"Numero di segnalazioni MROS basate sull'Art. 305ter cpv. 2 StGB (all'anno)"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:626
-msgid "IBAN is missing"
-msgstr "L'IBAN è mancante"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:348
+msgid "Number of GwG files of high-risk customers"
+msgstr "Numero di fascicoli GwG di clienti ad alto rischio"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:628
-msgid "Bitcoin address is missing"
-msgstr "L'indirizzo Bitcoin è mancante"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:351
+msgid "Number of GwG files managed with “increased risk” due to PEP status"
+msgstr ""
+"Numero di fascicoli GwG gestiti con \"rischio aumentato\" a causa dello "
+"stato PEP"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:630
-msgid "Bank host and account is missing"
-msgstr "L'host della banca e il conto sono mancanti"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:354
+#, fuzzy
+msgid "Number of customers with open proceeding."
+msgstr "Numero di conti aperti"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:632
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:634
-msgid "Exchange host and account is missing"
-msgstr "L'host dell'Exchange e il conto sono mancanti"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:400
+msgid "previous"
+msgstr "precedente"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:636
-msgid "Ethereum address is missing"
-msgstr "L'indirizzo Ethereum è mancante"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:443
+msgid "Decreased by"
+msgstr "Diminuito di"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:638
-msgid "Cyclos address is missing"
-msgstr "L'indirizzo Cyclos è mancante"
+#: packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx:447
+msgid "Increased by"
+msgstr "Aumentato di"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:640
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:114
+msgid ""
+"The built-in event selection differs from the events derived from the "
+"proposed account state."
+msgstr ""
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:119
+msgid ""
+"Built-in events are derived from changes to the proposed account properties. "
+"They are stored for reporting and statistics; they do not notify the "
+"customer."
+msgstr ""
+
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:138
#, fuzzy
-msgid "Void address is missing"
-msgstr "L'indirizzo Bitcoin è mancante"
+#| msgid "Reset to default"
+msgid "Reset to derived events"
+msgstr "Ripristina i valori predefiniti"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:648
-msgid "Invalid IBAN: %1$s"
-msgstr "IBAN non valido: %1$s"
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:169
+msgid "Calculated"
+msgstr "Calcolato"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:655
-msgid "Invalid BTC: %1$s"
-msgstr "BTC non valido: %1$s"
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:170
+msgid ""
+"Events derived from proposed property changes and submitted information."
+msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:660
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:683
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:696
-msgid "Invalid reserve: %1$s"
-msgstr "Riserva non valida: %1$s"
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:184
+msgid "Other built-in events"
+msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:671
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:681
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:694
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:715
-msgid "Invalid host"
-msgstr "Host non valido"
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:185
+#, fuzzy
+#| msgid "Events that can be triggered manually"
+msgid "Additional events that may be recorded manually."
+msgstr "Eventi che possono essere attivati manualmente"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:707
-msgid "Invalid address"
-msgstr "Indirizzo non valido"
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:198
+#, fuzzy
+#| msgid "Next event"
+msgid "Custom events"
+msgstr "Evento successivo"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:745
-msgid "Payto URI"
-msgstr "URI Payto"
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:199
+msgid "Operator-defined event names that are not part of the selected dialect."
+msgstr ""
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:746
-msgid "As defined by RFC 8905"
-msgstr "Come definito dalla RFC 8905"
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:213
+#, fuzzy
+#| msgid "Describe the decision."
+msgid "Events recorded with this decision"
+msgstr "Descrivi la decisione."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:747
-msgid "payto://"
-msgstr "payto://"
+#. screenid: 108
+#: packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx:214
+#, fuzzy
+#| msgid ""
+#| "The events will be triggered only after the decision has been confirmed."
+msgid "Events are added only after the decision is successfully submitted."
+msgstr "Gli eventi verranno attivati solo dopo la conferma della decisione."
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:209
+#, fuzzy
+#| msgid "System information"
+msgid "Add customer information"
+msgstr "Informazioni di sistema"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:212
+msgid ""
+"The completed form is attached to this AML decision as reviewed account "
+"information. It does not create a customer-facing measure."
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:223
+#, fuzzy
+#| msgid "Collected information"
+msgid "Selected form"
+msgstr "Informazioni raccolte"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:233
+#, fuzzy
+#| msgid "Complete the form"
+msgid "Choose another form"
+msgstr "Completa il modulo"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:242
+msgid "Expiration"
+msgstr "Scadenza"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:243
+msgid "Expiration date of the information filled in this form."
+msgstr "Data di scadenza delle informazioni compilate in questo modulo."
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:254
+#, fuzzy
+#| msgid "Context"
+msgid "Form context"
+msgstr "Contesto"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:261
+#, fuzzy
+#| msgid "Context"
+msgid "Advanced form context"
+msgstr "Contesto"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:264
+msgid ""
+"Only change this operator-defined JSON when the form documentation requires "
+"additional context."
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:270
+#, fuzzy
+#| msgid "Context"
+msgid "Context as JSON"
+msgstr "Contesto"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:291
+#, fuzzy
+msgid "Invalid JSON"
+msgstr "Host non valido"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:296
+msgid "Invalid expiration"
+msgstr "Scadenza non valida"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:297
+msgid "Attributes require an expiration date in the future or set to Never."
+msgstr ""
+"Gli attributi richiedono una data di scadenza futura o devono essere "
+"impostati su «Mai»."
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:355
+msgid "Include new information"
+msgstr "Includi nuove informazioni"
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:356
+msgid ""
+"This step is optional. Select a form to attach newly reviewed AML/KYC "
+"information, or continue without one."
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:361
+msgid "AML/KYC form"
+msgstr ""
+
+#. screenid: 107
+#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:362
+msgid "Search AML/KYC forms"
+msgstr "Cerca moduli AML/KYC"
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:101
+#, fuzzy
+#| msgid "Accounts under investigation."
+msgid "The account will be included in the AML investigation queue."
+msgstr "Conti sotto indagine."
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:106
+#, fuzzy
+#| msgid "Accounts under investigation."
+msgid "The account will not be included in the AML investigation queue."
+msgstr "Conti sotto indagine."
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:114
+#, fuzzy
+#| msgid "Investigation"
+msgid "Current investigation status"
+msgstr "Indagine"
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:128
+#, fuzzy
+#| msgid "No previous decisions"
+msgid "No previous decision"
+msgstr "Nessuna decisione precedente"
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:140
+#, fuzzy
+#| msgid "Investigation"
+msgid "Investigation status after this decision"
+msgstr "Indagine"
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:145
+#, fuzzy
+#| msgid "Measures the customer must complete under the current policy."
+msgid ""
+"Choose whether the account should remain in the AML investigation queue "
+"after this decision is submitted."
+msgstr "Misure che il cliente deve completare secondo la politica attuale."
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:201
+msgid ""
+"Full name used in the payto URI when creating this previously unknown "
+"account."
+msgstr ""
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:208
+#, fuzzy
+#| msgid "Decision date"
+msgid "Decision rationale"
+msgstr "Data della decisione"
+
+#. screenid: 106
+#: packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx:209
+msgid ""
+"Record the facts and reasoning needed to understand this decision in a later "
+"audit or review."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:264
+#, fuzzy
+#| msgid "Custom measures"
+msgid "Create custom measure"
+msgstr "Misure personalizzate"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:266
+#, fuzzy
+#| msgid "Add custom measure"
+msgid "Edit custom measure"
+msgstr "Aggiungi misura personalizzata"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:270
+msgid ""
+"Combine a customer check with an AML program, or use SKIP to run a program "
+"immediately. Context values must satisfy the selected check and program "
+"requirements."
+msgstr ""
+
+#. screenid: 122
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:289
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:478
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:366
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:115
+msgid "Add custom measure"
+msgstr "Aggiungi misura personalizzata"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:299
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:488
+msgid "Save changes"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:306
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:495
+#, fuzzy
+#| msgid "Add custom measure"
+msgid "Remove custom measure"
+msgstr "Aggiungi misura personalizzata"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:547
+#, fuzzy
+#| msgid "Configure verification type: %1$s"
+msgid "Configure %1$s verification"
+msgstr "Configura il tipo di verifica: %1$s"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:558
+msgid "Use advanced measure editor"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:587
+#, fuzzy
+#| msgid "Name of the verification measure"
+msgid "Use guided verification editor"
+msgstr "Nome della misura di verifica"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:632
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1111
+msgid "There is already a measure with that name"
+msgstr "Esiste già una misura con quel nome"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:646
+msgid ""
+"Runs immediately for SKIP measures, or after a successful check. It may be "
+"omitted for a check that only presents or collects information."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:650
+msgid "Missing check or program"
+msgstr "Verifica o programma mancante"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:660
+msgid ""
+"The customer-facing check to perform before the program. Leave empty to use "
+"SKIP and run the program immediately."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:683
+msgid ""
+"Configuration values required by the selected check or program. Property "
+"names and value types must match the exchange configuration."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:690
+msgid "Field name"
+msgstr "Nome del campo"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:695
+msgid "Type"
+msgstr "Tipo"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:699
+msgid "string"
+msgstr "stringa"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:703
+msgid "number"
+msgstr "numero"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:707
+msgid "boolean"
+msgstr "booleano"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:711
+msgid "json"
+msgstr "json"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:738
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:792
+#, fuzzy
+#| msgid "Form not available"
+msgid "Program \"%1$s\" is not available"
+msgstr "Modulo non disponibile"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:742
+msgid "There are unsatisfied inputs: %1$s"
+msgstr "Ci sono input non soddisfatti: %1$s"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:750
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:772
+msgid "Check \"%1$s\" is not available"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:756
+msgid "There are missing inputs: %1$s"
+msgstr "Ci sono input mancanti: %1$s"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:779
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:799
+msgid "There are missing requirements: %1$s"
+msgstr "Ci sono requisiti mancanti: %1$s"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:855
+msgid "Can't be empty"
+msgstr "Non può essere vuoto"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:859
+msgid "Not a number"
+msgstr "Non è un numero"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:861
+msgid "It should be finite"
+msgstr "Deve essere finito"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:866
+msgid "It should be either \"true\" or \"false\""
+msgstr "Deve essere \"true\" o \"false\""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:871
+msgid "Couldn't parse as json string: %1$s"
+msgstr "Impossibile analizzare come stringa json: %1$s"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:899
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:946
+msgid "Description"
+msgstr "Descrizione"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:915
+msgid "Inputs"
+msgstr "Input"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:954
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:534
+#, fuzzy
+#| msgid "Output"
+msgid "Outputs"
+msgstr "Output"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:962
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:401
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:533
+#, fuzzy
+#| msgid "Required"
+msgid "Required context"
+msgstr "Obbligatorio"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:970
+msgid "Fallback"
+msgstr "Fallback"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:993
+#, fuzzy
+#| msgid "Context"
+msgid "Context values"
+msgstr "Contesto"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1045
+msgid "Selected pipeline"
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1048
+msgid "Review how the exchange will execute this measure."
+msgstr ""
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1105
+msgid "Name of the verification measure"
+msgstr "Nome della misura di verifica"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1118
+msgid "Read only"
+msgstr "Sola lettura"
+
+#. screenid: 122
+#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:1119
+msgid "Prevent the customer from changing the address"
+msgstr "Impedisce al cliente di modificare l'indirizzo"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:154
+msgid "Customer actions after submission"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:157
+msgid ""
+"Immediate measures start as soon as this decision is accepted. A measure may "
+"show information, collect customer data, or run an AML program. Leave the "
+"selection empty when no immediate customer action is required."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:302
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:301
+msgid "Too many SKIP measures"
+msgstr "Troppe misure SKIP"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:303
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:302
+msgid "At most one immediate measure may use the SKIP check."
+msgstr "Al massimo una misura immediata può usare il controllo SKIP."
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:332
+#, fuzzy
+#| msgid "Configure verification measure: \"%1$s\""
+msgid "Configure verification measure “%1$s”"
+msgstr "Configura misura di verifica: \"%1$s\""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:372
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:522
+msgid "Custom measures"
+msgstr "Misure personalizzate"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:375
+msgid "Measures defined only for this proposed decision."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:399
+msgid "Edit"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:407
+#, fuzzy
+#| msgid "All measures"
+msgid "Available exchange measures"
+msgstr "Tutte le misure"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:410
+msgid "Reusable templates configured by the exchange operator"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:432
+msgid "Use as template"
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:512
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:288
+#, fuzzy
+#| msgid "Instant measures"
+msgid "Immediate measures"
+msgstr "Misure istantanee"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:513
+msgid ""
+"Selected measures begin immediately after the decision is accepted by the "
+"exchange."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:518
+#, fuzzy
+#| msgid "Require all measures"
+msgid "Require every selected measure"
+msgstr "Richiedi tutte le misure"
+
+#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:519
+#, fuzzy
+#| msgid ""
+#| "Run all selected measures together instead of accepting any one of them."
+msgid ""
+"When enabled, all selected measures must be completed. Otherwise, completing "
+"any one of them is sufficient."
+msgstr ""
+"Esegui insieme tutte le misure selezionate anziché accettarne una qualsiasi."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:190
+#, fuzzy
+msgid "Failed to make the decision."
+msgstr "Descrivi la decisione."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:193
+#, fuzzy
+msgid "Invalid credentials."
+msgstr "Credenziali invalide."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:195
+msgid "Session not found. Contact the administrator."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:197
+msgid ""
+"The exchange rejected the decision because the officer session is disabled "
+"or the account has a newer decision. Reload the account before trying again."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:251
+msgid ""
+"This decision records that an MROS report was filed. Confirm that the report "
+"has actually been submitted before continuing."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:264
+#, fuzzy
+#| msgid "No manual review"
+msgid "Go back and review"
+msgstr "Nessuna revisione manuale"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:271
+msgid "Confirm decision"
+msgstr "Conferma decisione"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:283
+msgid "Unknown measure"
+msgstr "Misura sconosciuta"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:284
+msgid ""
+"A rule or immediate action references a measure that is not available. "
+"Review the rules and measures before submitting."
+msgstr ""
+"Una regola o un’azione immediata fa riferimento a una misura non "
+"disponibile. Verifica le regole e le misure prima dell’invio."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:291
+#, fuzzy
+#| msgid "Add custom measure"
+msgid "Invalid custom measure"
+msgstr "Aggiungi misura personalizzata"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:292
+msgid ""
+"A custom measure references an unavailable check or program, lacks required "
+"context, or cannot provide the selected program inputs. Review the immediate "
+"measures before submitting."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:310
+msgid "Missing deadline"
+msgstr "Scadenza mancante"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:311
+msgid "Set when the proposed rules expire and what should happen afterward."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:319
+msgid "Invalid rule expiration"
+msgstr "Scadenza delle regole non valida"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:320
+msgid "Rule expiration must be in the future or set to Never."
+msgstr "La scadenza delle regole deve essere futura oppure impostata su «Mai»."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:327
+msgid "Missing rules"
+msgstr "Regole mancanti"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:328
+msgid ""
+"A decision must contain the complete rule set that will apply to the account."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:337
+msgid ""
+"Review the proposed rules. Hard blocks must be explicit, and Balance and "
+"Refund rules must use an instant timeframe."
+msgstr ""
+"Controlla le regole proposte. I blocchi rigidi devono essere espliciti e le "
+"regole per saldo e rimborso devono usare un intervallo istantaneo."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:376
+msgid "Immediate measures not reviewed"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:378
+#, fuzzy
+#| msgid "Measures the customer must complete under the current policy."
+msgid "Review whether the customer must complete any immediate measures."
+msgstr "Misure che il cliente deve completare secondo la politica attuale."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:384
+#, fuzzy
+#| msgid "Triggered immediately without customer interaction."
+msgid "No immediate customer action"
+msgstr "Attivate immediatamente senza interazione del cliente."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:385
+msgid "No measure will start when this decision is submitted."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:396
+#, fuzzy
+#| msgid "Account properties"
+msgid "Account properties not reviewed"
+msgstr "Proprietà del conto"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:398
+msgid "Review the account properties before submitting the decision."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:409
+msgid "Reporting events not reviewed"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:411
+msgid "Review which statistical events will be recorded with the decision."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:420
+msgid "Case disposition incomplete"
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:421
+msgid "You must complete the justification section."
+msgstr "Devi completare la sezione della giustificazione."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:430
+msgid "Invalid attributes"
+msgstr "Attributi non validi"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:431
+msgid ""
+"Correct the selected form or continue without attaching new customer "
+"information."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:443
+#, fuzzy
+#| msgid "Check account details"
+msgid "Decision details"
+msgstr "Controlla i dettagli del conto"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:447
+msgid "Justification"
+msgstr "Giustificazione"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:450
+#, fuzzy
+#| msgid "Not opened"
+msgid "Not provided"
+msgstr "Non aperto"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:454
+#, fuzzy
+#| msgid "Accounts under investigation."
+msgid "The account remains under investigation."
+msgstr "Conti sotto indagine."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:458
+#, fuzzy
+#| msgid "Accounts under investigation."
+msgid "The account will not remain under investigation."
+msgstr "Conti sotto indagine."
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:487
+msgid "No account properties"
+msgstr "Nessuna proprietà del conto"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:493
+msgid "Events"
+msgstr "Eventi"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:496
+#, fuzzy
+#| msgid "Next event"
+msgid "No events"
+msgstr "Evento successivo"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:501
+#, fuzzy
+#| msgid "Invalid attributes"
+msgid "Submitted attributes"
+msgstr "Attributi non validi"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:509
+#, fuzzy
+#| msgid "Expiration date"
+msgid "expiration set"
+msgstr "Data di scadenza"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:515
+#, fuzzy
+#| msgid "Invalid attributes"
+msgid "No new attributes"
+msgstr "Attributi non validi"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:537
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:550
+#, fuzzy
+#| msgid "Officer decision"
+msgid "Discard decision"
+msgstr "Decisione dell’addetto"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:544
+#, fuzzy
+#| msgid "Send decision"
+msgid "Submit AML decision"
+msgstr "Invia decisione"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:549
+#, fuzzy
+#| msgid "Discard this key"
+msgid "Discard this decision?"
+msgstr "Elimina questa chiave"
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:554
+msgid ""
+"All entries made in this decision wizard will be lost. No change will be "
+"submitted to the exchange."
+msgstr ""
+
+#. screenid: 102
+#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:571
+#, fuzzy
+#| msgid "Review status"
+msgid "Review this step"
+msgstr "Stato della revisione"
+
+#. screenid: 113
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:172
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:250
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:507
+#, fuzzy
+#| msgid "Back to accounts"
+msgid "Back to account"
+msgstr "Torna ai conti"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:177
+#, fuzzy
+#| msgid "New decision"
+msgid "New AML decision"
+msgstr "Nuova decisione"
+
+#. screenid: 113
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:201
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:297
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:790
+msgid "Payto URI"
+msgstr "URI Payto"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:218
+#, fuzzy
+#| msgctxt "threshold"
+#| msgid "%1$s every %2$s"
+msgid "Step %1$s of %2$s"
+msgstr "%1$s ogni %2$s"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:236
+msgid "Decision steps"
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:245
+#, fuzzy
+#| msgid "Previous event"
+msgid "Previous step"
+msgstr "Evento precedente"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:254
+#, fuzzy
+#| msgid "Next event"
+msgid "Next step"
+msgstr "Evento successivo"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:273
+#, fuzzy
+#| msgid "System information"
+msgid "Customer information"
+msgstr "Informazioni di sistema"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:274
+#, fuzzy
+#| msgid ""
+#| "You can review AML information, but this officer key cannot submit "
+#| "decisions."
+msgid "Optionally add reviewed AML/KYC information to this decision."
+msgstr ""
+"Puoi consultare le informazioni AML, ma questa chiave dell’operatore non può "
+"inviare decisioni."
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:279
+msgid "Review the account state derived from the available information."
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:283
+#, fuzzy
+#| msgid "Missing events"
+msgid "Reporting events"
+msgstr "Eventi mancanti"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:284
+msgid "Review the statistical events recorded with this decision."
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:289
+#, fuzzy
+#| msgid "Measures the customer must complete under the current policy."
+msgid ""
+"Choose actions the customer must complete after the decision is submitted."
+msgstr "Misure che il cliente deve completare secondo la politica attuale."
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:293
+#, fuzzy
+#| msgctxt "operation type"
+#| msgid "Transaction"
+msgid "Transaction rules"
+msgstr "Transazione"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:294
+msgid "Set operation thresholds, escalation measures, and expiration behavior."
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:298
+msgid "Case disposition"
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:299
+#, fuzzy
+#| msgid "Accounts under investigation."
+msgid "Record the rationale and whether the case remains under investigation."
+msgstr "Conti sotto indagine."
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:305
+#, fuzzy
+#| msgid "Review and submit."
+msgid "Review and submit"
+msgstr "Rivedi e invia."
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:306
+msgid "Check the complete decision before signing and submitting it."
+msgstr ""
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:326
+#, fuzzy
+#| msgid "Decision date"
+msgid "Decision progress"
+msgstr "Data della decisione"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:407
+#, fuzzy
+#| msgid "Failed to load account decisions."
+msgid "Loading account decision"
+msgstr "Impossibile caricare le decisioni del conto."
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:418
+#, fuzzy
+#| msgid "Decision for account:"
+msgid "Decision for account"
+msgstr "Decisione per il conto:"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:425
+#, fuzzy
+#| msgid "Decision for account:"
+msgid "Decision for wallet account"
+msgstr "Decisione per il conto:"
+
+#. screenid: 113
+#: packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx:431
+#, fuzzy
+#| msgid "Decision for bank account:"
+msgid "Decision for bank account"
+msgstr "Decisione per il conto bancario:"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:107
+msgid "Enter a valid HTTP or HTTPS URL."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:114
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:176
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:218
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:259
+msgid "Development settings"
+msgstr "Impostazioni di sviluppo"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:117
+msgid ""
+"These browser-local settings are intended for development and "
+"troubleshooting."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:132
+#, fuzzy
+#| msgid "Exchange hostname"
+msgid "Exchange connection"
+msgstr "Hostname dell'Exchange"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:135
+msgid ""
+"Changing the exchange reloads the application. The override is stored only "
+"in this browser."
+msgstr ""
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:147
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:97
+msgid "Exchange base URL"
+msgstr "URL di base dell’exchange"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:166
+msgid "Leave empty to use the configured URL: %1$s"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:170
+msgid "Leave empty to derive the exchange URL from this page."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:184
+msgid "Currently connected to"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:196
+msgid "Apply and reload"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:207
+msgid "Use configured URL"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:214
+msgid "Preferences"
+msgstr "Preferenze"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:221
+msgid "AML SPA dialect"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:236
+#, fuzzy
+#| msgid "Welcome to the exchange configuration"
+msgid "Use exchange configuration"
+msgstr "Benvenuto nella configurazione dell'Exchange"
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:240
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:44
+msgid "Testing"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:244
+msgid ""
+"Override how this web interface presents dialect-specific AML rules and "
+"properties. The override is stored only in this browser."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Developer.tsx:262
+#, fuzzy
+msgid "Show debug information"
+msgstr "Mostra le informazioni di debug"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:45
+msgid "Fallback dialect for development and testing."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:52
+msgid "TOPS"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:53
+msgid "Taler Operations deployment for Swiss AML processes."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:56
+msgid "File note"
+msgstr "Nota del fascicolo"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:57
+#, fuzzy
+#| msgid "Current note on the GwG file"
+msgid "Current note on the GwG file."
+msgstr "Nota attuale sul fascicolo GwG"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:58
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:64
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:112
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:124
+msgid "Text"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:62
+msgid "Customer label"
+msgstr "Etichetta del cliente"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:68
+msgid "Account open"
+msgstr "Conto aperto"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:69
+#, fuzzy
+#| msgid "Is the account active for deposit and payments?"
+msgid "Whether the account is active for deposits and payments."
+msgstr "Il conto è attivo per depositi e pagamenti?"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:70
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:76
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:82
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:88
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:94
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:100
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:106
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:142
+#, fuzzy
+#| msgid "boolean"
+msgid "Boolean"
+msgstr "booleano"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:74
+msgid "Domestic PEP"
+msgstr "PEP nazionale"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:75
+msgid "Whether the customer is a domestic politically exposed person."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:80
+msgid "Foreign PEP"
+msgstr "PEP estera"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:81
+msgid "Whether the customer is a foreign politically exposed person."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:86
+msgid "International-organization PEP"
+msgstr "PEP di un’organizzazione internazionale"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:87
+msgid ""
+"Whether the customer is a politically exposed person associated with an "
+"international organization."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:92
+msgid "High-risk customer"
+msgstr "Cliente ad alto rischio"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:93
+#, fuzzy
+#| msgid "Measures the customer must complete under the current policy."
+msgid "Whether the customer is classified as high risk."
+msgstr "Misure che il cliente deve completare secondo la politica attuale."
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:98
+msgid "High-risk country"
+msgstr "Paese ad alto rischio"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:99
+msgid "Whether the customer is associated with a high-risk country."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:104
+msgid "Account idle"
+msgstr "Conto inattivo"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:105
+msgid "Whether the account has been marked as idle."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:110
+#, fuzzy
+#| msgid "Investigation trigger"
+msgid "Investigation trigger"
+msgstr "Motivo dell’indagine"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:111
+#, fuzzy
+#| msgid "Informal reason why the AML investigation was triggered"
+msgid "Informal reason why the AML investigation was triggered."
+msgstr "Motivo informale per cui è stata avviata l'indagine AML"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:116
+#, fuzzy
+#| msgid "Investigation"
+msgid "Investigation state"
+msgstr "Indagine"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:117
+#, fuzzy
+#| msgid "The MROS reporting state for the account."
+msgid "Special-clarification and MROS reporting state for the account."
+msgstr "Lo stato di segnalazione MROS per il conto."
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:118
+#, fuzzy
+#| msgid "Operation"
+msgid "Enumeration"
+msgstr "Operazione"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:122
+#, fuzzy
+#| msgid "Sanctions-list best match"
+msgid "Sanction-list best match"
+msgstr "Migliore corrispondenza nell’elenco delle sanzioni"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:123
+#, fuzzy
+#| msgid "Identifies the sanction list entry that the account matched against"
+msgid ""
+"Sanction-list entry that best matched the account, regardless of match "
+"quality."
+msgstr ""
+"Identifica la voce dell'elenco sanzionatorio con cui il conto corrisponde"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:128
+#, fuzzy
+#| msgid "Sanctions-list rating"
+msgid "Sanction-list rating"
+msgstr "Valutazione della corrispondenza nell’elenco delle sanzioni"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:129
+msgid "Score from 0 (no match) to 1,000,000,000 (best match)."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:130
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:136
+#, fuzzy
+#| msgid "Internal"
+msgid "Integer"
+msgstr "Interno"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:134
+#, fuzzy
+#| msgid "Sanctions-list confidence"
+msgid "Sanction-list confidence"
+msgstr "Attendibilità della corrispondenza nell’elenco delle sanzioni"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:135
+msgid ""
+"Score from 0 (no supporting data) to 1,000,000,000 (highest confidence)."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:140
+#, fuzzy
+#| msgid "Suppress sanctions-list match"
+msgid "Suppress sanction-list match"
+msgstr "Ignora la corrispondenza nell’elenco delle sanzioni"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:141
+msgid ""
+"Whether this account's sanction-list hit is treated as a false positive."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:148
+#, fuzzy
+#| msgid "Account open"
+msgid "Account opened"
+msgstr "Conto aperto"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:149
+msgid "Recorded when an account changes to open."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:153
+#, fuzzy
+#| msgid "Account case"
+msgid "Account closed"
+msgstr "Caso del conto"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:154
+msgid "Recorded when an account changes from open to closed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:158
+#, fuzzy
+#| msgid "High-risk customer"
+msgid "High-risk customer classification added"
+msgstr "Cliente ad alto rischio"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:159
+msgid ""
+"Recorded when an open account becomes classified as a high-risk customer."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:163
+#, fuzzy
+#| msgid "High-risk customer"
+msgid "High-risk customer classification removed"
+msgstr "Cliente ad alto rischio"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:164
+msgid "Recorded when the high-risk customer classification is removed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:168
+#, fuzzy
+#| msgid "High-risk country"
+msgid "High-risk country classification added"
+msgstr "Paese ad alto rischio"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:169
+msgid ""
+"Recorded when an open account becomes associated with a high-risk country."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:173
+msgid "High-risk country classification removed"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:174
+msgid "Recorded when the high-risk country classification is removed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:178
+msgid "PEP classification added"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:179
+msgid "Recorded when an open account becomes associated with any PEP category."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:183
+#, fuzzy
+#| msgid "No justification was recorded."
+msgid "PEP classification removed"
+msgstr "Non è stata registrata alcuna motivazione."
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:184
+msgid ""
+"Recorded when the account is no longer associated with any PEP category."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:188
+msgid "Foreign PEP classification added"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:189
+msgid "Recorded when an open account becomes associated with a foreign PEP."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:193
+msgid "Foreign PEP classification removed"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:194
+msgid "Recorded when the foreign PEP classification is removed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:198
+msgid "Domestic PEP classification added"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:199
+msgid "Recorded when an open account becomes associated with a domestic PEP."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:203
+msgid "Domestic PEP classification removed"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:204
+msgid "Recorded when the domestic PEP classification is removed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:208
+#, fuzzy
+#| msgid "International-organization PEP"
+msgid "International-organization PEP classification added"
+msgstr "PEP di un’organizzazione internazionale"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:209
+#, fuzzy
+#| msgid "Does account belong to an international-organization PEP?"
+msgid ""
+"Recorded when an open account becomes associated with an international-"
+"organization PEP."
+msgstr "Il conto appartiene a un PEP di organizzazione internazionale?"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:213
+#, fuzzy
+#| msgid "International-organization PEP"
+msgid "International-organization PEP classification removed"
+msgstr "PEP di un’organizzazione internazionale"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:214
+msgid ""
+"Recorded when the international-organization PEP classification is removed."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:218
+msgid "Simple suspicion reported to MROS"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:219
+msgid "Recorded when a report is filed under Article 305ter paragraph 2 StGB."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:223
+#, fuzzy
+#| msgid "Reported substantiated suspicion"
+msgid "Substantiated suspicion reported to MROS"
+msgstr "Sospetto comprovato segnalato"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:224
+msgid "Recorded when a report is filed under Article 9 GwG."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:228
+#, fuzzy
+#| msgid "Investigation trigger"
+msgid "Investigation concluded"
+msgstr "Motivo dell’indagine"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:229
+msgid "Recorded when a pending special clarification is concluded."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:233
+#, fuzzy
+#| msgid "Investigation trigger"
+msgid "Investigation conclusion reversed"
+msgstr "Motivo dell’indagine"
+
+#: packages/taler-exchange-aml-webui/src/utils/dialect-info.ts:234
+msgid ""
+"Recorded when a previously concluded investigation returns to a non-"
+"concluded state."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:50
+msgid "Browser override"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:52
+#, fuzzy
+#| msgid "Welcome to the exchange configuration"
+msgid "Exchange configuration"
+msgstr "Benvenuto nella configurazione dell'Exchange"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:53
+#, fuzzy
+#| msgid "Default rules"
+msgid "Default fallback"
+msgstr "Regole predefinite"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:59
+#, fuzzy
+#| msgid "Welcome to the exchange configuration"
+msgid "Exchange and AML configuration"
+msgstr "Benvenuto nella configurazione dell'Exchange"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:62
+msgid ""
+"Exchange identity, the active AML dialect, and the checks and programs "
+"available to AML decisions."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:71
+msgid "Public information reported by this exchange."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:75
+msgid "Base URL"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:76
+msgid "Protocol"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:77
+msgid "Protocol version"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:78
+#, fuzzy
+#| msgid "Operation"
+msgid "Implementation"
+msgstr "Operazione"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:80
+#, fuzzy
+#| msgid "Not opened"
+msgid "Not reported"
+msgstr "Non aperto"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:82
+msgid "Currency"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:88
+msgid "AML dialect"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:95
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:119
+#, fuzzy
+#| msgid "Effective decision"
+msgid "Effective dialect"
+msgstr "Decisione in vigore"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:111
+#, fuzzy
+#| msgid "Configure measure"
+msgid "Configured dialect"
+msgstr "Configura misura"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:114
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:504
+#, fuzzy
+#| msgid "Not opened"
+msgid "Not specified"
+msgstr "Non aperto"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:129
+msgid "Canonical properties defined by the effective dialect."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:130
+#, fuzzy
+#| msgid "No account properties"
+msgid "This dialect does not define account properties."
+msgstr "Nessuna proprietà del conto"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:136
+#, fuzzy
+#| msgid "Reset to default"
+msgid "Derived events"
+msgstr "Ripristina i valori predefiniti"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:137
+#, fuzzy
+#| msgid "No account properties"
+msgid "Canonical events derived from account property changes."
+msgstr "Nessuna proprietà del conto"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:138
+msgid "This dialect does not define derived events."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:144
+#, fuzzy
+#| msgid "All measures"
+msgid "AML measures"
+msgstr "Tutte le misure"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:145
+msgid ""
+"Checks, programs, root measures, and default rules reported by the exchange."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:213
+#, fuzzy
+#| msgctxt "threshold"
+#| msgid "%1$s every %2$s"
+msgid "%1$s entry"
+msgstr "%1$s ogni %2$s"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:214
+msgid "%1$s entries"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:277
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:289
+#, fuzzy
+msgid "Failed to load the exchange AML measures."
+msgstr "Misure attive correnti"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:300
+#, fuzzy
+#| msgid "The measures endpoint was not found."
+msgid "The measures endpoint is not available."
+msgstr "L’endpoint delle misure non è stato trovato."
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:306
+#, fuzzy
+#| msgid "The account state changed. Reload it and try again."
+msgid "The exchange configuration changed. Reload it and try again."
+msgstr "Lo stato dell’account è cambiato. Ricaricalo e riprova."
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:332
+#, fuzzy
+#| msgid "Required measures"
+msgid "Retry loading measures"
+msgstr "Misure richieste"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:351
+#, fuzzy
+#| msgid "Reset measure"
+msgid "Root measures"
+msgstr "Reimposta misura"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:366
+msgid "No root measures are configured."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:371
+#, fuzzy
+#| msgid "Check"
+msgid "KYC checks"
+msgstr "Verifica"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:386
+msgid "No KYC checks are configured."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:391
+#, fuzzy
+#| msgid "Program"
+msgid "AML programs"
+msgstr "Programma"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:405
+#, fuzzy
+#| msgid "Requirements"
+msgid "Required inputs"
+msgstr "Requisiti"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:413
+msgid "No AML programs are configured."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:428
+msgid "No default AML rules are configured."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:480
+#, fuzzy
+#| msgid "Check"
+msgid "KYC check"
+msgstr "Verifica"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:484
+msgid "Built-in check that proceeds without collecting customer data."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:491
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:497
+#, fuzzy
+#| msgid "Program"
+msgid "AML program"
+msgstr "Programma"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:536
+#, fuzzy
+#| msgid "All measures"
+msgid "Fallback measure"
+msgstr "Tutte le misure"
+
+#: packages/taler-exchange-aml-webui/src/pages/Info.tsx:602
+#, fuzzy
+#| msgid "Unavailable"
+msgid "Unavailable reference"
+msgstr "Non disponibile"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:48
+msgid "Session and access"
+msgstr "Sessione e accesso"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:51
+msgid ""
+"Review this officer's exchange access and manage the unlocked key in this "
+"browser."
+msgstr ""
+"Controlla l’accesso di questo operatore all’exchange e gestisci la chiave "
+"sbloccata in questo browser."
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:66
+msgid "Officer access"
+msgstr "Accesso dell’operatore"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:71
+msgid "Officer name"
+msgstr "Nome dell’operatore"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:77
+msgid "Permissions"
+msgstr "Autorizzazioni"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:88
+msgid "Read-only"
+msgstr "Sola lettura"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:90
+msgid "Read and write"
+msgstr "Lettura e scrittura"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:118
+msgid "Session security"
+msgstr "Sicurezza della sessione"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:121
+msgid "Lock the session when you leave this device unattended."
+msgstr "Blocca la sessione quando lasci questo dispositivo incustodito."
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:133
+msgid "Lock now"
+msgstr "Blocca ora"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:148
+msgid "Unlocked"
+msgstr "Sbloccata"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:154
+msgid "Locks automatically"
+msgstr "Blocco automatico"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:165
+msgid "Exact time"
+msgstr "Ora esatta"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:185
+msgid "Copy public key"
+msgstr "Copia chiave pubblica"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:200
+msgid "Remove key from this browser"
+msgstr "Rimuovi la chiave da questo browser"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:203
+msgid ""
+"Removing this key deletes the officer key from this browser. It does not "
+"revoke or change the officer's access at the exchange. Ask the exchange "
+"operator to revoke access if needed."
+msgstr ""
+"La rimozione di questa chiave elimina la chiave dell’operatore da questo "
+"browser. Non revoca né modifica l’accesso dell’operatore all’exchange. Se "
+"necessario, chiedi all’operatore dell’exchange di revocare l’accesso."
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:214
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:222
+msgid "Remove key"
+msgstr "Rimuovi chiave"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:221
+msgid "Remove officer key?"
+msgstr "Rimuovere la chiave dell’operatore?"
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:231
+msgid ""
+"This deletes the officer key from this browser. You will need to create and "
+"enroll a new key to use the AML WebUI here again."
+msgstr ""
+"Questa operazione elimina la chiave dell’operatore da questo browser. Dovrai "
+"creare e far registrare una nuova chiave per utilizzare nuovamente qui "
+"l’interfaccia web AML."
+
+#. screenid: 112
+#: packages/taler-exchange-aml-webui/src/pages/Profile.tsx:237
+msgid ""
+"This does not revoke the officer at the exchange. Ask the exchange operator "
+"to revoke its access if the key may be compromised."
+msgstr ""
+"Questa operazione non revoca l’operatore presso l’exchange. Chiedi "
+"all’operatore dell’exchange di revocarne l’accesso se la chiave potrebbe "
+"essere compromessa."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:86
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:559
+msgid "Find account"
+msgstr "Trova conto"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:89
+msgid "Look up an account by its payto information or normalized payto hash."
+msgstr ""
+"Cerca un conto usando le informazioni payto o l’hash payto normalizzato."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:100
+msgid "Find by payto"
+msgstr "Cerca per payto"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:146
+msgid "Find by normalized payto hash"
+msgstr "Trova per hash payto normalizzato"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:169
+msgid "Enter a valid 52-character normalized payto hash."
+msgstr "Inserisci un hash payto normalizzato valido di 52 caratteri."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:179
+msgid "Open account"
+msgstr "Apri conto"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:214
+msgid "Failed to load account decisions."
+msgstr "Impossibile caricare le decisioni del conto."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:223
+msgid "Failed to load the account history."
+msgstr "Impossibile caricare la cronologia del conto."
+
+#. screenid: 111
+#. screenid: 110
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:228
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:82
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:268
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:66
+msgid ""
+"This session signature is invalid, contact administrator or create a new one."
+msgstr ""
+"La firma di questa sessione non è valida. Contatta l’amministratore o crea "
+"una nuova sessione."
+
+#. screenid: 111
+#. screenid: 110
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:235
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:89
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:275
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:73
+msgid ""
+"The designated AML session is not known, contact administrator or create a "
+"new one."
+msgstr ""
+"La sessione AML indicata non è nota. Contatta l’amministratore o creane una "
+"nuova."
+
+#. screenid: 111
+#. screenid: 110
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:242
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:96
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:282
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:80
+msgid ""
+"The designated AML session is not enabled, contact administrator or create a "
+"new one."
+msgstr ""
+"La sessione AML indicata non è abilitata. Contatta l’amministratore o creane "
+"una nuova."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:268
+#, fuzzy
+#| msgid "Account not found"
+msgid "Account found"
+msgstr "Conto non trovato"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:271
+msgid ""
+"This account has an AML decision history. Open its case to review current "
+"rules, measures, attributes, and past decisions."
+msgstr ""
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:283
+#, fuzzy
+#| msgid "Open account"
+msgid "Open account case"
+msgstr "Apri conto"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:309
+msgid "Active"
+msgstr ""
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:311
+#, fuzzy
+#| msgid "Effective decision"
+msgid "No active decision"
+msgstr "Decisione in vigore"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:317
+#, fuzzy
+#| msgid "File status"
+msgid "Case status"
+msgstr "Stato del fascicolo"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:321
+#, fuzzy
+#| msgid "Investigation trigger"
+msgid "Investigation required"
+msgstr "Motivo dell’indagine"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:323
+#, fuzzy
+#| msgid "Investigation state"
+msgid "No investigation requested"
+msgstr "Stato dell’indagine"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:333
+msgid "Account not found"
+msgstr "Conto non trovato"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:335
+msgid "There is no history known for this account yet."
+msgstr "Non è ancora nota alcuna cronologia per questo conto."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:350
+#, fuzzy
+#| msgid "You can make a decision for this account anyway."
+msgid "Start a decision for this account"
+msgstr "Puoi comunque prendere una decisione per questo conto."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:403
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:445
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:493
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:533
+msgid "Search"
+msgstr "Cerca"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:575
+msgid "Taler Bank"
+msgstr "Taler Bank"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:579
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:364
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:433
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:441
+msgid "Wallet"
+msgstr "Portafoglio"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:583
+msgid "Generic Payto:// URI"
+msgstr "URI Payto:// generico"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:586
+msgid "Account type"
+msgstr "Tipo di conto"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:596
+msgid "Should be 52 characters."
+msgstr "Deve essere di 52 caratteri."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:598
+msgid "Failed to parse: %1$s"
+msgstr "Impossibile analizzare: %1$s"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:610
+msgid "Address contains invalid characters."
+msgstr "L'indirizzo contiene caratteri non validi."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:612
+msgid "Can't mix uppercased and lowercased characters."
+msgstr "Impossibile combinare caratteri maiuscoli e minuscoli."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:614
+msgid "The addr checksum doesn't match."
+msgstr "Il checksum dell'indirizzo non corrisponde."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:616
+msgid "Missing separator or address type."
+msgstr "Separatore o tipo di indirizzo mancante."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:618
+msgid "Address should have less than 90 characters."
+msgstr "L'indirizzo deve avere meno di 90 caratteri."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:620
+msgid "Address should have more than 6 characters."
+msgstr "L'indirizzo deve avere più di 6 caratteri."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:622
+msgid "Decoding issue."
+msgstr "Problema di decodifica."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:624
+msgid "Invalid data"
+msgstr "Dati non validi"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:634
+msgid "Unsupported country."
+msgstr "Paese non supportato."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:636
+msgid "IBANs have fewer than 34 characters."
+msgstr "Gli IBAN hanno meno di 34 caratteri."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:638
+msgid "IBANs have more than 4 characters."
+msgstr "Gli IBAN hanno più di 4 caratteri."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:640
+msgid "IBAN length is invalid for this country."
+msgstr "La lunghezza dell'IBAN non è valida per questo paese."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:642
+msgid "It should only contain numbers and letters."
+msgstr "Deve contenere solo numeri e lettere."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:644
+msgid "The checksum is wrong."
+msgstr "Il checksum è errato."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:662
+msgid "The string should start with payto://"
+msgstr "La stringa deve iniziare con payto://"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:664
+msgid "After the target type it should follow a '/' with more information."
+msgstr ""
+"Dopo il tipo di destinazione deve seguire un '/' con ulteriori informazioni."
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:666
+msgid ""
+"The target type is not supported, only x-taler-bank, taler-reserve or iban"
+msgstr ""
+"Il tipo di destinazione non è supportato, solo x-taler-bank, taler-reserve o "
+"iban"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:671
+msgid "IBAN is missing"
+msgstr "L'IBAN è mancante"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:673
+msgid "Bitcoin address is missing"
+msgstr "L'indirizzo Bitcoin è mancante"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:675
+msgid "Bank host and account is missing"
+msgstr "L'host della banca e il conto sono mancanti"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:677
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:679
+msgid "Exchange host and account is missing"
+msgstr "L'host dell'Exchange e il conto sono mancanti"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:681
+msgid "Ethereum address is missing"
+msgstr "L'indirizzo Ethereum è mancante"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:683
+msgid "Cyclos address is missing"
+msgstr "L'indirizzo Cyclos è mancante"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:685
+msgid "Void address is missing"
+msgstr "Manca l’indirizzo void"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:693
+msgid "Invalid IBAN: %1$s"
+msgstr "IBAN non valido: %1$s"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:700
+msgid "Invalid BTC: %1$s"
+msgstr "BTC non valido: %1$s"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:705
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:728
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:741
+msgid "Invalid reserve: %1$s"
+msgstr "Riserva non valida: %1$s"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:716
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:726
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:739
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:760
+msgid "Invalid host"
+msgstr "Host non valido"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:718
+msgid "Invalid account"
+msgstr "Conto non valido"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:752
+msgid "Invalid address"
+msgstr "Indirizzo non valido"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:791
+msgid "As defined by RFC 8905"
+msgstr "Come definito dalla RFC 8905"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:792
+msgid "payto://"
+msgstr "payto://"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:807
+msgid "International Bank Account Number"
+msgstr "Numero di conto bancario internazionale"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:808
+msgid "DE1231231231"
+msgstr "DE1231231231"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:820
+msgid "Host"
+msgstr "Host"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:821
+msgid "Exchange hostname"
+msgstr "Hostname dell'Exchange"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:822
+msgid "exchange.taler.net"
+msgstr "exchange.taler.net"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:827
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:874
+msgid "Remove last '/'"
+msgstr "Rimuovi l'ultimo '/'"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:829
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:846
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:426
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:472
+msgid "Invalid value"
+msgstr "Valore non valido"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:837
+msgid "ID"
+msgstr "ID"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:838
+msgid "Wallet reserve public key"
+msgstr "Chiave pubblica di riserva del portafoglio"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:839
+msgid "abcdef1235"
+msgstr "abcdef1235"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:844
+msgid "Should be 52 characters"
+msgstr "Deve essere di 52 caratteri"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:860
+msgid "Bank account identification"
+msgstr "Identificazione del conto bancario"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:861
+msgid "DE123123123"
+msgstr "DE123123123"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:867
+msgid "Hostname"
+msgstr "Hostname"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:868
+msgid "Without the scheme, may include subpath: bank.com, bank.com/path/"
+msgstr ""
+"Senza lo schema, può includere un sottopercorso: bank.com, bank.com/path/"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:869
+msgid "bank.demo.taler.net"
+msgstr "bank.demo.taler.net"
+
+#. screenid: 111
+#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:876
+msgid "Invalid hostname"
+msgstr "Hostname non valido"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:68
+msgid "Failed to load account information."
+msgstr "Impossibile caricare le informazioni del conto."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:77
+msgid "Failed to load the account information."
+msgstr ""
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:115
+msgid "Collection event not found"
+msgstr "Evento di raccolta non trovato"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:117
+msgid "There is no collection event with ID %1$s for this account."
+msgstr "Non esiste alcun evento di raccolta con ID %1$s per questo account."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:129
+msgid "Attributes unavailable"
+msgstr "Attributi non disponibili"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:131
+msgid "The collection event does not contain readable attributes."
+msgstr "L’evento di raccolta non contiene attributi leggibili."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:148
+msgid "Form identifier missing"
+msgstr "Identificatore del modulo mancante"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:150
+msgid "The collected information does not identify the form used to create it."
+msgstr ""
+"Le informazioni raccolte non identificano il modulo utilizzato per crearle."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:165
+msgid "Form not available"
+msgstr "Modulo non disponibile"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:167
+msgid "Form %1$s is not configured in this AML Web UI."
+msgstr "Il modulo %1$s non è configurato in questa interfaccia web AML."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:255
+#, fuzzy
+#| msgid "Collected information"
+msgid "Collected AML/KYC information"
+msgstr "Informazioni raccolte"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:262
+#, fuzzy
+#| msgid "Forms"
+msgid "Form"
+msgstr "Moduli"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:267
+#, fuzzy
+#| msgid "Collected information"
+msgid "Collected"
+msgstr "Informazioni raccolte"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:270
+msgid "Source"
+msgstr ""
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:274
+#, fuzzy
+#| msgid "Custom properties"
+msgid "Customer process"
+msgstr "Proprietà personalizzate"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:277
+#, fuzzy
+#| msgid "Events"
+msgid "Event ID"
+msgstr "Eventi"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:284
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:292
+msgid "Different form version"
+msgstr "Versione del modulo differente"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:285
+msgid ""
+"The collected information does not identify the form version used. The "
+"latest configured version is shown and field labels may differ from those "
+"used at collection time."
+msgstr ""
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:293
+#, fuzzy
+#| msgid "Form %1$s is not configured in this AML Web UI."
+msgid ""
+"Form version %1$s is not configured in this AML Web UI. Version %2$s is "
+"shown and field labels may differ."
+msgstr "Il modulo %1$s non è configurato in questa interfaccia web AML."
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:301
+#, fuzzy
+#| msgid "Collected information"
+msgid "Collected information events"
+msgstr "Informazioni raccolte"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:305
+#, fuzzy
+#| msgid "Next event"
+msgid "Older event"
+msgstr "Evento successivo"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:316
+#, fuzzy
+#| msgid "Next event"
+msgid "Newer event"
+msgstr "Evento successivo"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:329
+#, fuzzy
+#| msgid "Invalid attributes"
+msgid "Submitted values"
+msgstr "Attributi non validi"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:369
+#, fuzzy
+#| msgid "Officer name"
+msgid "Officer view"
+msgstr "Nome dell’operatore"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:371
+#, fuzzy
+#| msgid "Customer-visible"
+msgid "Customer view"
+msgstr "Visibile al cliente"
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:372
+msgid "JSON view"
+msgstr ""
+
+#. screenid: 110
+#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:403
+#, fuzzy
+#| msgid "System information"
+msgid "Submitted information view"
+msgstr "Informazioni di sistema"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:109
+msgid "Incoming"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:113
+msgid "Outgoing"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:117
+msgid "KYC authorization"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:127
+msgid "Wallet credits (P2P)"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:140
+#, fuzzy
+#| msgid "Transfers history"
+msgid "Transfer category"
+msgstr "Cronologia dei trasferimenti"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:147
+msgid "Minimum amount"
+msgstr "Importo minimo"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:148
+msgid "All amounts below the given threshold will be filtered."
+msgstr "Tutti gli importi inferiori alla soglia indicata verranno filtrati."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:182
+#, fuzzy
+#| msgid "Exchange hostname"
+msgid "Exchange transfer activity"
+msgstr "Hostname dell'Exchange"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:188
+#, fuzzy
+#| msgid "Transfers history"
+msgid "Wallet credit activity"
+msgstr "Cronologia dei trasferimenti"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:190
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:198
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:241
+#, fuzzy
+#| msgid "Transfers history"
+msgid "Transfer activity"
+msgstr "Cronologia dei trasferimenti"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:196
+#, fuzzy
+#| msgid "Transfers history for account"
+msgid "Transfer activity for account"
+msgstr "Cronologia dei trasferimenti per il conto"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:204
+msgid ""
+"Inspect successful P2P credits received by this wallet. Requests that were "
+"not paid are not shown."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:209
+msgid ""
+"Inspect effective bank transfers observed by the exchange. Credit transfers "
+"are incoming, debit transfers are outgoing, and bounced or drain transfers "
+"are not included."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:215
+msgid ""
+"Inspect effective transfers observed by the exchange. Incoming, outgoing, "
+"and KYC authorization entries are bank transfers. Wallet credits are "
+"successful P2P transfers into wallets."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:233
+#, fuzzy
+#| msgid "Transfers history"
+msgid "Transfer filters"
+msgstr "Cronologia dei trasferimenti"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:254
+#, fuzzy
+msgid "Failed to load transfer list."
+msgstr "Impossibile analizzare: %1$s"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:263
+msgid "Failed to load the transfer list."
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:299
+msgid "Select transaction type"
+msgstr "Seleziona il tipo di transazione"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:300
+msgid "Please select a transaction type to show transactions."
+msgstr "Seleziona un tipo di transazione per mostrare le transazioni."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:314
+#, fuzzy
+#| msgid "No transfers yet."
+msgid "No wallet credits yet."
+msgstr "Nessun trasferimento ancora."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:315
+msgid "No transfers yet."
+msgstr "Nessun trasferimento ancora."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:319
+#, fuzzy
+#| msgid "There are no transfers for this account."
+msgid "There are no P2P credits for this wallet."
+msgstr "Non ci sono trasferimenti per questo conto."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:323
+#, fuzzy
+#| msgid ""
+#| "There are no transfers reported to the exchange with the current "
+#| "threshold."
+msgid ""
+"There are no wallet credits reported to the exchange with the current "
+"threshold."
+msgstr ""
+"Non ci sono trasferimenti segnalati all'Exchange con la soglia attuale."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:328
+msgid "There are no transfers for this account."
+msgstr "Non ci sono trasferimenti per questo conto."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:332
+msgid ""
+"There are no transfers reported to the exchange with the current threshold."
+msgstr ""
+"Non ci sono trasferimenti segnalati all'Exchange con la soglia attuale."
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:343
+msgid "Unknown date"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:355
+msgid "Time"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:359
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:406
+msgid "Amount"
+msgstr "Importo"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:393
+msgid "Unknown time"
+msgstr ""
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:410
+#, fuzzy
+#| msgid "Credit"
+msgid "credited"
+msgstr "Credito"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:412
+msgid "sent"
+msgstr "inviato"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:413
+msgid "received"
+msgstr "ricevuto"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:443
+msgid "to"
+msgstr "a"
+
+#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:444
+msgid "from"
+msgstr "da"
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:165
+msgid "This exchange is not compatible with the AML WebUI."
+msgstr "Questo exchange non è compatibile con l’interfaccia web AML."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:167
+msgid ""
+"Officer identity and permissions require exchange protocol v40 or newer."
+msgstr ""
+"L’identità e i permessi dell’operatore richiedono il protocollo exchange v40 "
+"o successivo."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:191
+msgid "Verifying that this public key is enrolled by the exchange."
+msgstr "Verifica che questa chiave pubblica sia registrata presso l’exchange."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:278
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:331
+msgid "Read-only officer access"
+msgstr "Accesso operatore in sola lettura"
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:279
+msgid ""
+"You can review AML information, but this officer key cannot submit decisions."
+msgstr ""
+"Puoi consultare le informazioni AML, ma questa chiave dell’operatore non può "
+"inviare decisioni."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:332
+msgid "This officer key cannot create or submit AML decisions."
+msgstr "Questa chiave dell’operatore non può creare né inviare decisioni AML."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:340
+msgid "Return to account"
+msgstr "Torna all’account"
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:466
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:475
+msgid "Failed to load the active AML decision."
+msgstr "Impossibile caricare la decisione AML attiva."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:484
+msgid "The account was not found."
+msgstr "L’account non è stato trovato."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:488
+msgid "The account state changed. Reload it and try again."
+msgstr "Lo stato dell’account è cambiato. Ricaricalo e riprova."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:511
+msgid ""
+"The payto URI does not belong to this account. Return to the account search "
+"and start the decision again."
+msgstr ""
+"L’URI payto non appartiene a questo account. Torna alla ricerca degli "
+"account e avvia nuovamente la decisione."
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:571
+#, fuzzy
+#| msgid "AML navigation"
+msgid "AML configuration"
+msgstr "Navigazione AML"
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:577
+msgid "Session"
+msgstr "Sessione"
+
+#: packages/taler-exchange-aml-webui/src/Routing.tsx:585
+msgid "AML navigation"
+msgstr "Navigazione AML"
+
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:49
+#, fuzzy
+msgid "Failed to load server measures."
+msgstr "Misure del server"
+
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:61
+#, fuzzy
+msgid "Failed to load the measures"
+msgstr "Misure attive correnti"
+
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:102
+msgid "Measures"
+msgstr "Misure"
+
+#. screenid: 124
+#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:105
+#, fuzzy
+msgid "A list of all the predefined measures you can use."
+msgstr "Un elenco di tutte le misure predefinite che puoi utilizzare."
+
+#~ msgid "AML officer justification"
+#~ msgstr "Giustificazione dell'ufficiale AML"
+
+#~ msgid "Effective policy"
+#~ msgstr "Politica in vigore"
+
+#~ msgid "Account assessment"
+#~ msgstr "Valutazione del conto"
+
+#~ msgid "Properties recorded by AML officers for this account."
+#~ msgstr "Proprietà registrate dagli addetti AML per questo conto."
+
+#~ msgid "Account assessment could not be loaded"
+#~ msgstr "Impossibile caricare la valutazione del conto"
+
+#~ msgid "No assessment properties have been recorded for this account."
+#~ msgstr ""
+#~ "Non sono state registrate proprietà di valutazione per questo conto."
+
+#~ msgid "Currently applied rules"
+#~ msgstr "Regole attualmente applicate"
+
+#~ msgid ""
+#~ "This account has no account-specific decision. The exchange default rules "
+#~ "currently apply."
+#~ msgstr ""
+#~ "Questo conto non ha una decisione specifica. Attualmente si applicano le "
+#~ "regole predefinite dell’exchange."
+
+#, fuzzy
+#~ msgid "Keep case under investigation"
+#~ msgstr "Non sotto indagine"
+
+#~ msgid "Account views"
+#~ msgstr "Viste dei conti"
+
+#~ msgid "Date"
+#~ msgstr "Data"
+
+#~ msgid "Show transfers"
+#~ msgstr "Mostra trasferimenti"
+
+#, fuzzy
+#~ msgid "View decision history"
+#~ msgstr "Cronologia delle decisioni"
+
+#~ msgid "Save PDF"
+#~ msgstr "Salva PDF"
+
+#~ msgid "Manual review required"
+#~ msgstr "Revisione manuale richiesta"
+
+#~ msgid "At a glance"
+#~ msgstr "Panoramica"
+
+#~ msgid "Requirements present"
+#~ msgstr "Requisiti presenti"
+
+#~ msgid "Current assessment and policy"
+#~ msgstr "Valutazione e politica attuali"
+
+#~ msgid "The current account properties and effective AML rules."
+#~ msgstr "Le proprietà attuali del conto e le regole AML in vigore."
+
+#, fuzzy
+#~ msgid "Property"
+#~ msgstr "Proprietà"
+
+#~ msgid "The officer session signature is invalid."
+#~ msgstr "La firma della sessione dell’addetto AML non è valida."
+
+#~ msgid "The requested AML account was not found."
+#~ msgstr "Il conto AML richiesto non è stato trovato."
+
+#~ msgid "The officer session is disabled or the account state changed."
+#~ msgstr ""
+#~ "La sessione dell’addetto AML è disabilitata oppure lo stato dell’account "
+#~ "è cambiato."
+
+#, fuzzy
+#~ msgid "Account audit trail"
+#~ msgstr "Filtri dei conti"
+
+#~ msgid "(all)"
+#~ msgstr "(tutti)"
+
+#~ msgid "Info"
+#~ msgstr "Info"
+
+#~ msgid "Will show information to the user."
+#~ msgstr "Mostrerà informazioni all'utente."
+
+#~ msgid ""
+#~ "The account isn't a wallet and there are wallet operation's limits which "
+#~ "may trigger actions that are not required: %1$s"
+#~ msgstr ""
+#~ "Il conto non è un portafoglio e ci sono limiti di operazioni per "
+#~ "portafoglio che potrebbero attivare azioni non necessarie: %1$s"
+
+#~ msgid ""
+#~ "The account is a wallet and there are wallet operation's limits which are "
+#~ "not limited: %1$s"
+#~ msgstr ""
+#~ "Il conto è un portafoglio e ci sono limiti di operazioni per portafoglio "
+#~ "che non sono limitati: %1$s"
+
+#~ msgid "New rules"
+#~ msgstr "Nuove regole"
+
+#~ msgid "Set rules to default"
+#~ msgstr "Imposta le regole ai valori predefiniti"
+
+#~ msgid "Behavior on rule expiration"
+#~ msgstr "Comportamento alla scadenza della regola"
+
+#~ msgid ""
+#~ "Events based on properties and new attributes that should be triggered"
+#~ msgstr ""
+#~ "Eventi basati su proprietà e nuovi attributi che dovrebbero essere "
+#~ "attivati"
+
+#~ msgid "Others"
+#~ msgstr "Altri"
+
+#~ msgid "Custom list"
+#~ msgstr "Elenco personalizzato"
+
+#~ msgid "Events without built-in support."
+#~ msgstr "Eventi senza supporto integrato."
+
+#~ msgid "These measures will ask the customer for information."
+#~ msgstr "Queste misure chiederanno informazioni al cliente."
+
+#~ msgid ""
+#~ "Select a form to submit new information about the customer or continue to "
+#~ "the next step"
+#~ msgstr ""
+#~ "Seleziona un modulo per inviare nuove informazioni sul cliente oppure "
+#~ "continua al passaggio successivo"
+
+#~ msgid "Form:"
+#~ msgstr "Modulo:"
+
+#~ msgid "Keep investigation?"
+#~ msgstr "Mantenere l'indagine?"
+
+#~ msgid "Full name of the account holder"
+#~ msgstr "Nome completo del titolare del conto"
+
+#~ msgid "Update"
+#~ msgstr "Aggiorna"
+
+#~ msgid "Remove"
+#~ msgstr "Rimuovi"
+
+#~ msgid "Show complete form"
+#~ msgstr "Mostra modulo completo"
+
+#~ msgid "Show as verification"
+#~ msgstr "Mostra come verifica"
+
+#~ msgid "Only required when no check is specified"
+#~ msgstr "Obbligatorio solo quando non è specificata alcuna verifica"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:762
-msgid "International Bank Account Number"
-msgstr "Numero di conto bancario internazionale"
+#~ msgid "Without a check the program will run automatically"
+#~ msgstr "Senza una verifica, il programma verrà eseguito automaticamente"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:763
-msgid "DE1231231231"
-msgstr "DE1231231231"
+#~ msgid "It should be a number"
+#~ msgstr "Deve essere un numero"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:775
-msgid "Host"
-msgstr "Host"
+#~ msgid "It should be a safe integer"
+#~ msgstr "Deve essere un intero sicuro"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:776
-msgid "Exchange hostname"
-msgstr "Hostname dell'Exchange"
+#~ msgid "Server measures"
+#~ msgstr "Misure del server"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:777
-msgid "exchange.taler.net"
-msgstr "exchange.taler.net"
+#~ msgid "New measures"
+#~ msgstr "Nuove misure"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:782
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:829
-msgid "Remove last '/'"
-msgstr "Rimuovi l'ultimo '/'"
+#~ msgid ""
+#~ "Measures that are available/executed directly after the decision is "
+#~ "confirmed."
+#~ msgstr ""
+#~ "Misure disponibili/eseguite immediatamente dopo la conferma della "
+#~ "decisione."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:784
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:801
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:332
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:376
-msgid "Invalid value"
-msgstr "Valore non valido"
+#, fuzzy
+#~ msgid ""
+#~ "The session is disabled or a more recent decision was already submitted."
+#~ msgstr ""
+#~ "Ufficiale disabilitato o è già stata inviata una decisione più recente."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:792
-msgid "ID"
-msgstr "ID"
+#, fuzzy
+#~ msgid ""
+#~ "This decision declares that the MROS report has concluded. Please make "
+#~ "sure that this is the case"
+#~ msgstr ""
+#~ "Questa decisione dichiara che la segnalazione MROS è stata conclusa. "
+#~ "Assicurati che sia effettivamente così"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:793
-msgid "Wallet reserve public key"
-msgstr "Chiave pubblica di riserva del portafoglio"
+#~ msgid "I want to check first!"
+#~ msgstr "Voglio prima controllare!"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:794
-msgid "abcdef1235"
-msgstr "abcdef1235"
+#~ msgid ""
+#~ "Deadline should specify when this rules ends and what is the next "
+#~ "measures to apply after expiration."
+#~ msgstr ""
+#~ "La scadenza deve specificare quando termina questa regola e quali sono le "
+#~ "prossime misure da applicare dopo la scadenza."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:799
-msgid "Should be 52 characters"
-msgstr "Deve essere di 52 caratteri"
+#~ msgid "Can't make a decision without rules."
+#~ msgstr "Impossibile prendere una decisione senza regole."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:814
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:268
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:338
-msgid "Account"
-msgstr "Conto"
+#~ msgid "Missing active measure"
+#~ msgstr "Misura attiva mancante"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:815
-msgid "Bank account identification"
-msgstr "Identificazione del conto bancario"
+#~ msgid "You should specify in the measure section."
+#~ msgstr "Devi specificarlo nella sezione delle misure."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:816
-msgid "DE123123123"
-msgstr "DE123123123"
+#~ msgid "You should specify in the properties section."
+#~ msgstr "Devi specificarlo nella sezione delle proprietà."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:822
-msgid "Hostname"
-msgstr "Hostname"
+#~ msgid "You should specify in the events section."
+#~ msgstr "Devi specificarlo nella sezione degli eventi."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:823
-msgid "Without the scheme, may include subpath: bank.com, bank.com/path/"
-msgstr ""
-"Senza lo schema, può includere un sottopercorso: bank.com, bank.com/path/"
+#~ msgid "Missing justification"
+#~ msgstr "Giustificazione mancante"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:824
-msgid "bank.demo.taler.net"
-msgstr "bank.demo.taler.net"
+#~ msgid ""
+#~ "You should check form errors or submit a decision without attributes."
+#~ msgstr ""
+#~ "Controlla gli errori del modulo oppure invia una decisione senza "
+#~ "attributi."
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:831
-msgid "Invalid hostname"
-msgstr "Hostname non valido"
+#~ msgid "Clear"
+#~ msgstr "Cancella"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:71
-msgid "Failed to load the account information."
-msgstr ""
+#~ msgid "Attributes"
+#~ msgstr "Attributi"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:198
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:204
-msgid "Different form version"
-msgstr "Versione del modulo differente"
+#~ msgid "Add more information about the customer"
+#~ msgstr "Aggiungi ulteriori informazioni sul cliente"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:199
-msgid "The collected information don't have the form version used."
-msgstr ""
-"Le informazioni raccolte non riportano la versione del modulo utilizzata."
+#~ msgid "Rules"
+#~ msgstr "Regole"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:205
-msgid ""
-"The collected information used the form version \"%1$s \" but is not "
-"available."
-msgstr ""
-"Le informazioni raccolte hanno usato la versione del modulo \"%1$s \" ma non "
-"è disponibile."
+#~ msgid "Set the limit of the operations"
+#~ msgstr "Imposta il limite delle operazioni"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:217
-msgid "Case details"
-msgstr "Dettagli del caso"
+#~ msgid "Trigger notifications."
+#~ msgstr "Attiva le notifiche."
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:231
-msgid "Next event"
-msgstr "Evento successivo"
+#~ msgid "Ask the customer to take action."
+#~ msgstr "Chiedi al cliente di intervenire."
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:245
-msgid "Previous event"
-msgstr "Evento precedente"
+#~ msgid "Flag the current account state."
+#~ msgstr "Contrassegna lo stato attuale del conto."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:66
-msgid "Direction"
-msgstr "Direzione"
+#~ msgid "loading..."
+#~ msgstr "caricamento..."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:69
-msgid "Credit"
-msgstr "Credito"
+#~ msgid "Decision for wallet:"
+#~ msgstr "Decisione per il portafoglio:"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:73
-msgid "Debit"
-msgstr "Debito"
+#~ msgid "Check account details"
+#~ msgstr "Controlla i dettagli del conto"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:77
-msgid "KYC Auth"
-msgstr "Autenticazione KYC"
+#~ msgid "Account most recent decisions"
+#~ msgstr "Decisioni più recenti del conto"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:85
-msgid "Minimum amount"
-msgstr "Importo minimo"
+#~ msgid "When"
+#~ msgstr "Quando"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:86
-msgid "All amounts below the given threshold will be filtered."
-msgstr "Tutti gli importi inferiori alla soglia indicata verranno filtrati."
+#~ msgid "LATEST"
+#~ msgstr "ULTIMA"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:114
-#, fuzzy
-msgid "Failed to load transfer list."
-msgstr "Impossibile analizzare: %1$s"
+#~ msgid "ACTIVE"
+#~ msgstr "ATTIVA"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:123
-msgid "Failed to load the transfer list."
-msgstr ""
+#~ msgid "Requires investigation"
+#~ msgstr "Richiede un’indagine"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:160
-msgid "Select transaction type"
-msgstr "Seleziona il tipo di transazione"
+#~ msgid "The collected information don't have the form version used."
+#~ msgstr ""
+#~ "Le informazioni raccolte non riportano la versione del modulo utilizzata."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:161
-msgid "Please select a transaction type to show transactions."
-msgstr "Seleziona un tipo di transazione per mostrare le transazioni."
+#~ msgid ""
+#~ "The collected information used the form version \"%1$s \" but is not "
+#~ "available."
+#~ msgstr ""
+#~ "Le informazioni raccolte hanno usato la versione del modulo \"%1$s \" ma "
+#~ "non è disponibile."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:176
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:234
-msgid "Transfers history for account"
-msgstr "Cronologia dei trasferimenti per il conto"
+#~ msgid "Case details"
+#~ msgstr "Dettagli del caso"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:188
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:246
-msgid "Transfers history"
-msgstr "Cronologia dei trasferimenti"
+#~ msgid "Previous event"
+#~ msgstr "Evento precedente"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:195
-msgid "No transfers yet."
-msgstr "Nessun trasferimento ancora."
+#~ msgid "Direction"
+#~ msgstr "Direzione"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:197
-msgid "There are no transfers for this account."
-msgstr "Non ci sono trasferimenti per questo conto."
+#~ msgid "Debit"
+#~ msgstr "Debito"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:201
-msgid ""
-"There are no transfers reported to the exchange with the current threshold."
-msgstr ""
-"Non ci sono trasferimenti segnalati all'Exchange con la soglia attuale."
+#~ msgid "KYC Auth"
+#~ msgstr "Autenticazione KYC"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:260
-msgid "Date"
-msgstr "Data"
+#~ msgid "Previous AML decisions that are no longer active."
+#~ msgstr "Decisioni AML precedenti non più attive."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:264
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:310
-msgid "Amount"
-msgstr "Importo"
+#~ msgid "The account has no KYC information."
+#~ msgstr "Il conto non contiene informazioni KYC."
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:314
-msgid "sent"
-msgstr "inviato"
+#~ msgid "Download KYC report"
+#~ msgstr "Scarica il rapporto KYC"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:315
-msgid "received"
-msgstr "ricevuto"
+#~ msgid "KYC report ready"
+#~ msgstr "Rapporto KYC pronto"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:348
-msgid "to"
-msgstr "a"
+#~ msgid "Use testing dialect"
+#~ msgstr "Usa il dialetto di test"
-#: packages/taler-exchange-aml-webui/src/pages/Transfers.tsx:349
-msgid "from"
-msgstr "da"
+#~ msgid "Since"
+#~ msgstr "Da"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:92
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:101
-msgid "Welcome to the exchange configuration"
-msgstr "Benvenuto nella configurazione dell'Exchange"
+#~ msgid "Already completed."
+#~ msgstr "Già completato."
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:372
-msgid "Transfers"
-msgstr "Trasferimenti"
+#~ msgid "Case history for selected account"
+#~ msgstr "Cronologia dei casi per il conto selezionato"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:379
-msgid "Profile"
-msgstr "Profilo"
+#~ msgid "ID:"
+#~ msgstr "ID:"
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:49
-#, fuzzy
-msgid "Failed to load server measures."
-msgstr "Misure del server"
+#~ msgid "Payto:"
+#~ msgstr "Payto:"
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:61
-#, fuzzy
-msgid "Failed to load the measures"
-msgstr "Misure attive correnti"
+#~ msgid "Export as PDF"
+#~ msgstr "Esporta come PDF"
-#. screenid: 124
-#: packages/taler-exchange-aml-webui/src/components/MeasureList.tsx:105
-#, fuzzy
-msgid "A list of all the predefined measures you can use."
-msgstr "Un elenco di tutte le misure predefinite che puoi utilizzare."
+#~ msgid "Click here to save the file in your computer."
+#~ msgstr "Clicca qui per salvare il file sul tuo computer."
-#. screenid: 122
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:165
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:174
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:214
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:222
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:90
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:99
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:62
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:71
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:191
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:200
-msgid "Failed to load available measures."
-msgstr "Impossibile caricare le misure disponibili."
+#~ msgid "Every attribute collection event (via form upload or KYC provider)."
+#~ msgstr ""
+#~ "Ogni evento di raccolta attributi (tramite caricamento di moduli o "
+#~ "fornitore KYC)."
-#. screenid: 122
-#. screenid: 102
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:179
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:104
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:76
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:205
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:403
-msgid "The officer session is invalid."
-msgstr "La sessione dell’addetto AML non è valida."
+#~ msgid ""
+#~ "There is no decision for this account yet. The account is limited by the "
+#~ "default rules."
+#~ msgstr ""
+#~ "Non c'è ancora alcuna decisione per questo conto. Il conto è limitato "
+#~ "dalle regole predefinite."
-#. screenid: 122
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:183
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:108
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:80
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:209
-msgid "The measures endpoint was not found."
-msgstr "L’endpoint delle misure non è stato trovato."
+#~ msgid "No AML history found"
+#~ msgstr "Nessuna cronologia AML trovata"
-#. screenid: 122
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx:189
-#: packages/taler-exchange-aml-webui/src/components/NewMeasure.tsx:114
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:86
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:215
-msgid "The officer session is disabled."
-msgstr "La sessione dell’addetto AML è disabilitata."
+#~ msgid "Current active measures"
+#~ msgstr "Misure attive correnti"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:182
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:190
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:389
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:398
-msgid "Failed to load the active AML decision."
-msgstr "Impossibile caricare la decisione AML attiva."
+#, fuzzy
+#~ msgid "There are no accounts in the resultset."
+#~ msgstr "Non ci sono ancora regole per questo conto."
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:488
-msgid "The officer session signature is invalid."
-msgstr "La firma della sessione dell’addetto AML non è valida."
+#, fuzzy
+#~ msgid "Failed to load the accounts"
+#~ msgstr "Cronologia dei casi per il conto selezionato"
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:491
-msgid "The requested AML account or session was not found."
-msgstr "L’account AML o la sessione richiesta non è stato trovato."
+#~ msgid "High risk accounts. Only with custom rules."
+#~ msgstr "Conti ad alto rischio. Solo con regole personalizzate."
-#: packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx:495
-msgid "The officer session is disabled or the account state changed."
-msgstr ""
-"La sessione dell’addetto AML è disabilitata oppure lo stato dell’account è "
-"cambiato."
+#~ msgid "Account with custom rules."
+#~ msgstr "Conto con regole personalizzate."
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:192
-msgid "Invalid expiration"
-msgstr "Scadenza non valida"
+#~ msgid "High risk accounts under investigation. Only with custom rules."
+#~ msgstr ""
+#~ "Conti ad alto rischio sotto indagine. Solo con regole personalizzate."
-#. screenid: 107
-#: packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx:193
-msgid "Attributes require an expiration date in the future."
-msgstr "Gli attributi richiedono una data di scadenza futura."
+#~ msgid "Accounts under investigation. Only with custom rules."
+#~ msgstr "Conti sotto indagine. Solo con regole personalizzate."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:288
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:273
-msgid "Too many SKIP measures"
-msgstr "Troppe misure SKIP"
+#~ msgid "High risk accounts under investigation."
+#~ msgstr "Conti ad alto rischio sotto indagine."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:289
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:274
-msgid "At most one immediate measure may use the SKIP check."
-msgstr "Al massimo una misura immediata può usare il controllo SKIP."
+#~ msgid "Accounts under investigation."
+#~ msgstr "Conti sotto indagine."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:491
-msgid "Require all measures"
-msgstr "Richiedi tutte le misure"
+#~ msgid "High risk accounts without investigation. Only with custom rules."
+#~ msgstr ""
+#~ "Conti ad alto rischio senza indagine. Solo con regole personalizzate."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx:492
-msgid ""
-"Run all selected measures together instead of accepting any one of them."
-msgstr ""
-"Esegui insieme tutte le misure selezionate anziché accettarne una qualsiasi."
+#~ msgid "Accounts without investigation. Only with custom rules."
+#~ msgstr "Conti senza indagine. Solo con regole personalizzate."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:172
-msgid "Invalid custom properties"
-msgstr "Proprietà personalizzate non valide"
+#~ msgid "High risk accounts without investigation."
+#~ msgstr "Conti ad alto rischio senza indagine."
-#: packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx:173
-msgid ""
-"Custom property names and values must be non-empty and names must be unique "
-"and different from built-in properties."
-msgstr ""
-"I nomi e i valori delle proprietà personalizzate non possono essere vuoti; i "
-"nomi devono essere univoci e diversi dalle proprietà integrate."
+#~ msgid "Accounts without investigation."
+#~ msgstr "Conti senza indagine."
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:265
-msgid "Unknown measure"
-msgstr "Misura sconosciuta"
+#~ msgid "No results"
+#~ msgstr "Nessun risultato"
-#. screenid: 102
-#: packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx:266
-msgid ""
-"A rule or immediate action references a measure that is not available. "
-"Review the rules and measures before submitting."
-msgstr ""
-"Una regola o un’azione immediata fa riferimento a una misura non "
-"disponibile. Verifica le regole e le misure prima dell’invio."
+#~ msgid "#"
+#~ msgstr "#"
-#. screenid: 111
-#: packages/taler-exchange-aml-webui/src/pages/Search.tsx:274
-msgid "Requires investigation"
-msgstr "Richiede un’indagine"
+#~ msgid "Account Identification"
+#~ msgstr "Identificazione del conto"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:106
-msgid "Collection event not found"
-msgstr "Evento di raccolta non trovato"
+#~ msgid "From %1$s %2$s To %3$s"
+#~ msgstr "Da %1$s %2$s a %3$s"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:107
-msgid "There is no collection event with ID %1$s for this account."
-msgstr "Non esiste alcun evento di raccolta con ID %1$s per questo account."
+#~ msgid "With custom rules"
+#~ msgstr "Con regole personalizzate"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:116
-msgid "Attributes unavailable"
-msgstr "Attributi non disponibili"
+#~ msgid "Search by ID"
+#~ msgstr "Cerca per ID"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:117
-msgid "The collection event does not contain readable attributes."
-msgstr "L’evento di raccolta non contiene attributi leggibili."
+#~ msgid "Under investigation: "
+#~ msgstr "Sotto indagine:"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:131
-msgid "Form identifier missing"
-msgstr "Identificatore del modulo mancante"
+#~ msgid "High risk:"
+#~ msgstr "Alto rischio:"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:132
-msgid "The collected information does not identify the form used to create it."
-msgstr ""
-"Le informazioni raccolte non identificano il modulo utilizzato per crearle."
+#~ msgid "Case queue"
+#~ msgstr "Coda dei casi"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:144
-msgid "Form not available"
-msgstr "Modulo non disponibile"
+#~ msgid "Access"
+#~ msgstr "Accesso"
-#. screenid: 110
-#: packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx:145
-msgid "Form %1$s is not configured in this AML Web UI."
-msgstr "Il modulo %1$s non è configurato in questa interfaccia web AML."
+#~ msgid "Unlocked until"
+#~ msgstr "Sbloccata fino al"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:407
-msgid "The account was not found."
-msgstr "L’account non è stato trovato."
+#~ msgid "Confirm forgetting this session"
+#~ msgstr "Conferma l’eliminazione di questa sessione"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:411
-msgid "The account state changed. Reload it and try again."
-msgstr "Lo stato dell’account è cambiato. Ricaricalo e riprova."
+#, fuzzy
+#~ msgid "Request session activation"
+#~ msgstr "Richiedi attivazione del conto"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:436
-msgid ""
-"The payto URI does not belong to this account. Return to the account search "
-"and start the decision again."
-msgstr ""
-"L’URI payto non appartiene a questo account. Torna alla ricerca degli "
-"account e avvia nuovamente la decisione."
+#~ msgid "Prev"
+#~ msgstr "Prec."
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:448
-msgid ""
-"This account has no active decision and its payto URI is unknown. Start the "
-"decision from the account search so the account type can be determined "
-"safely."
-msgstr ""
-"Questo account non ha una decisione attiva e il suo URI payto è sconosciuto. "
-"Avvia la decisione dalla ricerca degli account affinché il tipo di account "
-"possa essere determinato in modo sicuro."
+#~ msgid "Next"
+#~ msgstr "Successivo"
-#. screenid: 126
-#: packages/taler-exchange-aml-webui/src/Routing.tsx:458
-msgid "Return to account"
-msgstr "Torna all’account"
+#~ msgid ""
+#~ "This account has no active decision and its payto URI is unknown. Start "
+#~ "the decision from the account search so the account type can be "
+#~ "determined safely."
+#~ msgstr ""
+#~ "Questo account non ha una decisione attiva e il suo URI payto è "
+#~ "sconosciuto. Avvia la decisione dalla ricerca degli account affinché il "
+#~ "tipo di account possa essere determinato in modo sicuro."
#, c-format
#~ msgid "Internal error, please report."
@@ -2394,10 +5243,6 @@ msgstr "Torna all’account"
#~ msgstr "Impossibile sbloccare il conto, la password potrebbe essere errata."
#, c-format
-#~ msgid "Lock account"
-#~ msgstr "Blocca conto"
-
-#, c-format
#~ msgid "Operation denied"
#~ msgstr "Operazione negata"
@@ -2509,10 +5354,6 @@ msgstr "Torna all’account"
#~ msgstr "L'utente '%1$s' non esiste. Login impossibile"
#, c-format
-#~ msgid "Account information could not be retrieved."
-#~ msgstr "Impossibile ricevere le informazioni relative al conto."
-
-#, c-format
#~ msgid "List of public accounts could not be retrieved."
#~ msgstr "Lista conti pubblici non pervenuta."
diff --git a/packages/taler-exchange-aml-webui/src/i18n/strings.ts b/packages/taler-exchange-aml-webui/src/i18n/strings.ts
@@ -25,9 +25,6 @@ strings['it'] = {
"lang": "it",
"plural_forms": ""
},
- "Use testing dialect": [
- "Usa il dialetto di test"
- ],
"Allow Insecure password": [
"Consenti password non sicura"
],
@@ -37,8 +34,11 @@ strings['it'] = {
"Don't compress request": [
"Non comprimere la richiesta"
],
- "Preferences": [
- "Preferenze"
+ "Lock session": [
+ "Blocca sessione"
+ ],
+ "Lock": [
+ "Blocca"
],
"Password": [
"Password"
@@ -67,5183 +67,8132 @@ strings['it'] = {
"Create": [
"Crea"
],
- "Failed to unlock the session.": [
- ""
+ "Wallet account": [
+ "Conto del portafoglio"
],
- "Authorization denied for this session. Contact the administrator.": [
- ""
+ "Bank account": [
+ "Conto bancario"
],
- "Unlock": [
- "Sblocca"
+ "Under investigation": [
+ "Sotto indagine"
],
- "There are no rules for operations": [
- "Non ci sono regole per le operazioni"
+ "High risk": [
+ "Rischio elevato"
],
- "Add custom rule": [
- "Aggiungi regola personalizzata"
+ "Payment target type": [
+ ""
],
- "Operation": [
- "Operazione"
+ "Account holder": [
+ "Titolare del conto"
],
- "Threshold": [
- "Soglia"
+ "IBAN": [
+ "IBAN"
],
- "Escalation": [
- "Escalation"
+ "BIC": [
+ ""
],
- "%1$s": [
- "%1$s"
+ "Bank": [
+ ""
],
- "(all)": [
- "(tutti)"
+ "Account": [
+ "Conto"
],
- "Since": [
- "Da"
+ "Taler bank": [
+ "Banca Taler"
],
- "Expired": [
- "Scaduto"
+ "Cyclos": [
+ ""
],
- "Expires": [
- "Scade"
+ "Bitcoin address": [
+ ""
],
- "Successor measure": [
- "Misura successiva"
+ "Reserve public key": [
+ ""
],
- "AML officer justification": [
- "Giustificazione dell'ufficiale AML"
+ "Bitcoin": [
+ ""
],
- "Default rules": [
- "Regole predefinite"
+ "Ethereum address": [
+ ""
],
- "Forms": [
- "Moduli"
+ "Ethereum": [
+ ""
],
- "Name": [
- "Nome"
+ "Exchange": [
+ ""
],
- "Check": [
- "Verifica"
+ "Taler reserve": [
+ "Riserva Taler"
],
- "Program": [
- "Programma"
+ "Taler reserve (HTTP)": [
+ ""
],
- "Context": [
- "Contesto"
+ "Test account": [
+ "Conto di prova"
],
- "Modify": [
- "Modifica"
+ "Account details unavailable": [
+ ""
],
- "Info": [
- "Info"
+ "Not opened": [
+ "Non aperto"
],
- "Will show information to the user.": [
- "Mostrerà informazioni all'utente."
+ "Opened:": [
+ "Aperto:"
],
- "Instant measures": [
- "Misure istantanee"
+ "Closed:": [
+ "Chiuso:"
],
- "Triggered immediately without customer interaction.": [
- "Attivate immediatamente senza interazione del cliente."
+ "Closed": [
+ "Chiuso"
],
- "Input requirement": [
- "Requisito di input"
+ "Open": [
+ "Aperto"
],
- "Already completed.": [
- "Già completato."
+ "No note": [
+ "Nessuna nota"
],
- "Waiting to be completed.": [
- "In attesa di essere completato."
+ "Show full note": [
+ "Mostra la nota completa"
],
- "Current active rules": [
- "Regole attive correnti"
+ "System information": [
+ "Informazioni di sistema"
],
- "There are no rules for this account yet.": [
- "Non ci sono ancora regole per questo conto."
+ "Transactions remain below the threshold that opens an AML file.": [
+ "Le transazioni restano al di sotto della soglia che apre un fascicolo AML."
],
- "New rule form": [
- "Modulo per nuova regola"
+ "Account case": [
+ "Caso del conto"
],
- "Add": [
- "Aggiungi"
+ "Failed to download AML file.": [
+ "Impossibile scaricare il fascicolo AML."
],
- "Cancel": [
- "Annullare"
+ "No AML file is available for this account.": [
+ "Non è disponibile alcun fascicolo AML per questo conto."
],
- "Basic plan": [
- "Piano base"
+ "Authorization denied for this session. Contact the administrator.": [
+ "Autorizzazione negata per questa sessione. Contattare l’amministratore."
],
- "Premium": [
- "Premium"
+ "The account or session was not found.": [
+ "Il conto o la sessione non sono stati trovati."
],
- "E-commerce": [
- "E-commerce"
+ "The session is disabled. Contact the administrator.": [
+ "La sessione è disabilitata. Contattare l’amministratore."
],
- "Point of Sale": [
- "Punto vendita"
+ "The exchange does not support PDF reports.": [
+ "L’Exchange non supporta i rapporti PDF."
],
- "Check rules": [
- "Verifica regole"
+ "Read-only officers cannot create AML decisions.": [
+ "Gli operatori con accesso in sola lettura non possono creare decisioni AML."
],
- "The account is a wallet and there are bank account operation's limits which may trigger actions that are not required: %1$s": [
- "Il conto è un portafoglio e ci sono limiti di operazioni per conto bancario che potrebbero attivare azioni non necessarie: %1$s"
+ "A payto URI is required to create a new decision.": [
+ "È necessario un URI payto per creare una nuova decisione."
],
- "The account isn't a wallet and there are wallet operation's limits which may trigger actions that are not required: %1$s": [
- "Il conto non è un portafoglio e ci sono limiti di operazioni per portafoglio che potrebbero attivare azioni non necessarie: %1$s"
+ "Back to accounts": [
+ "Torna ai conti"
],
- "The account is a wallet and there are wallet operation's limits which are not limited: %1$s": [
- "Il conto è un portafoglio e ci sono limiti di operazioni per portafoglio che non sono limitati: %1$s"
+ "File no. %1$s": [
+ "Fascicolo n. %1$s"
],
- "New rules": [
- "Nuove regole"
+ "New decision": [
+ "Nuova decisione"
],
- "Reset rules to current state": [
- "Reimposta le regole allo stato attuale"
+ "Download AML file (PDF)": [
+ "Scarica il fascicolo AML (PDF)"
],
- "Set rules to default": [
- "Imposta le regole ai valori predefiniti"
+ "AML file download started.": [
+ "Il download del fascicolo AML è iniziato."
],
- "Freeze account": [
- "Congela conto"
+ "Try again": [
+ ""
],
- "Behavior on rule expiration": [
- "Comportamento alla scadenza della regola"
+ "Account identifiers": [
+ "Identificativi del conto"
],
- "Reset measure": [
- "Reimposta misura"
+ "Technical identifiers": [
+ "Identificatori tecnici"
],
- "Reset expiration": [
- "Reimposta scadenza"
+ "Full payto URI": [
+ "URI payto completo"
],
- "Operation type": [
- "Tipo di operazione"
+ "Unavailable": [
+ "Non disponibile"
],
- "Timeframe": [
- "Intervallo di tempo"
+ "Copy payto URI": [
+ "Copia URI payto"
],
- "Exposed": [
- "Esposto"
+ "Normalized payto hash": [
+ "Hash payto normalizzato"
],
- "Is this limit communicated to the customer?": [
- "Questo limite viene comunicato al cliente?"
+ "Copy normalized payto hash": [
+ "Copia l’hash payto normalizzato"
],
- "Escalation measure": [
- "Misura di escalation"
+ "Account case views": [
+ "Viste del caso del conto"
],
- "Measures that the customer will need to satisfy to apply for a new threshold.": [
- "Misure che il cliente dovrà soddisfare per richiedere una nuova soglia."
+ "Overview": [
+ "Panoramica"
],
- "All measures": [
- "Tutte le misure"
+ "Transfers": [
+ "Trasferimenti"
],
- "Hint the customer that all measures should be completed": [
- "Segnala al cliente che tutte le misure devono essere completate"
+ "Decision history": [
+ "Cronologia delle decisioni"
],
- "Expiration": [
- "Scadenza"
+ "Close": [
+ "Chiudi"
],
- "Predefined shortcuts": [
- "Scorciatoie predefinite"
+ "Cancel": [
+ "Annullare"
],
- "In a week": [
- "Tra una settimana"
+ "AML officer enrollment request": [
+ "Richiesta di registrazione dell’ufficiale AML"
],
- "In a month": [
- "Tra un mese"
+ "Please enroll this AML officer public key:\n\n%1$s": [
+ "Registra questa chiave pubblica dell’ufficiale AML:\n\n%1$s"
],
- "In a year": [
- "Tra un anno"
+ "Officer key awaiting enrollment": [
+ "Chiave dell’ufficiale AML in attesa di registrazione"
],
- "Never": [
- "Mai"
+ "This browser has created an AML officer key, but the exchange has not granted it access. Ask the exchange operator or administrator to enroll the public key below.": [
+ "Questo browser ha creato una chiave per l’ufficiale AML, ma l’Exchange non le ha concesso l’accesso. Chiedi all’operatore o all’amministratore dell’Exchange di registrare la chiave pubblica qui sotto."
],
- "Expiration date": [
- "Data di scadenza"
+ "AML officer public key": [
+ "Chiave pubblica dell’ufficiale AML"
],
- "Until when are the new rules active.": [
- "Fino a quando sono attive le nuove regole."
+ "Copy AML officer public key": [
+ "Copia la chiave pubblica dell’addetto AML"
],
- "Measure taken automatically upon expiration of the current decision.": [
- "Misura adottata automaticamente alla scadenza della decisione attuale."
+ "After the operator confirms enrollment, retry the access check.": [
+ "Dopo che l’operatore ha confermato la registrazione, riprova a verificare l’accesso."
],
- "Failed to load account information.": [
- ""
+ "Retry access check": [
+ "Riprova la verifica dell’accesso"
],
- "Failed to load decision history.": [
- ""
+ "Checking officer access": [
+ "Verifica dell’accesso dell’ufficiale AML"
],
- "Failed to load current legitimizations.": [
- ""
+ "Last checked at %1$s": [
+ "Ultima verifica alle %1$s"
],
- "New decision": [
- "Nuova decisione"
+ "Request enrollment": [
+ "Richiedi la registrazione"
],
- "Show transfers": [
- "Mostra trasferimenti"
+ "Discard this key": [
+ "Elimina questa chiave"
],
- "Failed to download report.": [
- ""
+ "Confirmation required": [
+ "Conferma richiesta"
],
- "Session not found. Contact the administrator.": [
- ""
+ "Discarding this key removes the officer session from this browser. You will need to create a new key to use the AML WebUI again.": [
+ "Eliminando questa chiave, la sessione dell’ufficiale verrà rimossa da questo browser. Per utilizzare nuovamente l’interfaccia web AML, dovrai creare una nuova chiave."
],
- "The session is disabled. Contact the administrator.": [
- ""
+ "Failed to check AML officer access.": [
+ "Impossibile verificare l’accesso dell’operatore AML."
],
- "The server doesn't support PDF download. Contact the administrator.": [
- ""
+ "This officer key cannot authenticate with the exchange. Retry the check or discard the key and create a new session.": [
+ "Questa chiave dell’operatore non può autenticarsi presso l’exchange. Riprova la verifica oppure elimina la chiave e crea una nuova sessione."
],
- "Case history for selected account": [
- "Cronologia dei casi per il conto selezionato"
+ "The exchange rejected the officer access check.": [
+ "L’exchange ha rifiutato la verifica dell’accesso dell’operatore."
],
- "ID:": [
- "ID:"
+ "Technical details": [
+ "Dettagli tecnici"
],
- "Payto:": [
- "Payto:"
+ "Failed to unlock the session.": [
+ ""
],
- "Export as PDF": [
- "Esporta come PDF"
+ "Unlock": [
+ "Sblocca"
],
- "Export completed": [
- "Esportazione completata"
+ "Forget session": [
+ "Elimina sessione"
],
- "Click here to save the file in your computer.": [
- "Clicca qui per salvare il file sul tuo computer."
+ "There are no rules for operations": [
+ "Non ci sono regole per le operazioni"
],
- "Under investigation": [
- "Sotto indagine"
+ "This means that no operation has any limit.": [
+ "Questo significa che nessuna operazione ha limiti."
],
- "This account requires a manual review and is waiting for a decision to be made.": [
- "Questo conto richiede una revisione manuale ed è in attesa di una decisione."
+ "Operation": [
+ "Operazione"
],
- "Collected information": [
- "Informazioni raccolte"
+ "Threshold": [
+ "Soglia"
],
- "Every attribute collection event (via form upload or KYC provider).": [
- "Ogni evento di raccolta attributi (tramite caricamento di moduli o fornitore KYC)."
+ "Escalation": [
+ "Escalation"
],
- "No collected attributes for this account.": [
- "Nessun attributo raccolto per questo conto."
+ "Visibility": [
+ "Visibilità"
],
- "Current account properties": [
- "Proprietà attuali del conto"
+ "Priority": [
+ "Priorità"
],
- "No active decision found": [
- "Nessuna decisione attiva trovata"
+ "Actions": [
+ "Azioni"
],
- "There is no decision for this account yet. The account is limited by the default rules.": [
- "Non c'è ancora alcuna decisione per questo conto. Il conto è limitato dalle regole predefinite."
+ "Block operation": [
+ "Blocca operazione"
],
- "Previous AML decisions": [
- "Decisioni AML precedenti"
+ "All required:": [
+ "Tutte necessarie:"
],
- "No AML history found": [
- "Nessuna cronologia AML trovata"
+ "Any one:": [
+ "Una qualsiasi:"
],
- "Current active measures": [
- "Misure attive correnti"
+ "Customer-visible": [
+ "Visibile al cliente"
],
- "Now": [
- "Ora"
+ "Internal": [
+ "Interno"
],
- "Lock session": [
- ""
+ "Move %1$s rule up": [
+ "Sposta in alto la regola %1$s"
],
- "Failed to load accounts": [
- ""
+ "Move %1$s rule down": [
+ "Sposta in basso la regola %1$s"
],
- "High risk accounts. Only with custom rules.": [
- "Conti ad alto rischio. Solo con regole personalizzate."
+ "Edit %1$s rule": [
+ "Modifica la regola %1$s"
],
- "Account with custom rules.": [
- "Conto con regole personalizzate."
+ "Remove %1$s rule": [
+ "Rimuovi la regola %1$s"
],
- "High risk accounts": [
- "Conti ad alto rischio"
+ "AML officer justification": [
+ "Giustificazione dell'ufficiale AML"
],
- "All known accounts.": [
- "Tutti i conti conosciuti."
+ "No justification was recorded.": [
+ "Non è stata registrata alcuna motivazione."
],
- "High risk accounts under investigation. Only with custom rules.": [
- "Conti ad alto rischio sotto indagine. Solo con regole personalizzate."
+ "Operation rules": [
+ "Regole operative"
],
- "Accounts under investigation. Only with custom rules.": [
- "Conti sotto indagine. Solo con regole personalizzate."
+ "Decision date": [
+ "Data della decisione"
],
- "High risk accounts under investigation.": [
- "Conti ad alto rischio sotto indagine."
+ "Expired": [
+ "Scaduto"
],
- "Accounts under investigation.": [
- "Conti sotto indagine."
+ "Expires": [
+ "Scade"
],
- "High risk accounts without investigation. Only with custom rules.": [
- "Conti ad alto rischio senza indagine. Solo con regole personalizzate."
+ "Successor measure": [
+ "Misura successiva"
],
- "Accounts without investigation. Only with custom rules.": [
- "Conti senza indagine. Solo con regole personalizzate."
+ "Exchange defaults": [
+ "Regole predefinite dell’Exchange"
],
- "High risk accounts without investigation.": [
- "Conti ad alto rischio senza indagine."
+ "Forms": [
+ "Moduli"
],
- "Accounts without investigation.": [
- "Conti senza indagine."
+ "Measures used to gather information about the customer.": [
+ "Misure utilizzate per raccogliere informazioni sul cliente."
],
- "Failed to download": [
- ""
+ "Select": [
+ "Seleziona"
],
- "The format requested is not acceptable from the service provider.": [
- ""
+ "Name": [
+ "Nome"
],
- "Authorization denied for this session.": [
- ""
+ "Check": [
+ "Verifica"
],
- "The session is disabled. Contact the administrator": [
- ""
+ "Program": [
+ "Programma"
],
- "Accounts": [
- "Conti"
+ "Context": [
+ "Contesto"
],
- "Export as file": [
- "Esporta come file"
+ "Modify": [
+ "Modifica"
],
- "No results": [
- "Nessun risultato"
+ "Instant measures": [
+ "Misure istantanee"
],
- "#": [
- "#"
+ "Triggered immediately without customer interaction.": [
+ "Attivate immediatamente senza interazione del cliente."
],
- "Account Identification": [
- "Identificazione del conto"
+ "Input requirement": [
+ "Requisito di input"
],
- "Open time": [
- "Ora di apertura"
+ "Started": [
+ "Avviato"
],
"Status": [
"Stato"
],
- "From %1$s %2$s To %3$s": [
- "Da %1$s %2$s a %3$s"
+ "Forbidden": [
+ "Vietato"
],
- "Since %1$s": [
- "Da %1$s"
- ],
- "Not opened": [
- "Non aperto"
+ "Completed": [
+ "Completato"
],
- "High risk": [
- "Alto rischio"
+ "Waiting for customer": [
+ "In attesa del cliente"
],
- "With custom rules": [
- "Con regole personalizzate"
+ "The operation is categorically forbidden by this requirement.": [
+ "Questo requisito vieta categoricamente l’operazione."
],
- "Invalid account": [
- "Conto non valido"
+ "All listed measures must be completed.": [
+ "Tutte le misure elencate devono essere completate."
],
- "Search by ID": [
- "Cerca per ID"
+ "Any one listed measure may be completed.": [
+ "È possibile completare una qualsiasi delle misure elencate."
],
- "Under investigation: ": [
- "Sotto indagine:"
+ "Values may be derived from the selected AML/KYC form. Confirm them against the case record and change only values that require an officer override.": [
+ ""
],
- "High risk:": [
- "Alto rischio:"
+ "Invalid custom properties": [
+ "Proprietà personalizzate non valide"
],
- "Custom rules:": [
- "Regole personalizzate:"
+ "Custom property names and values must be non-empty and names must be unique and different from built-in properties.": [
+ "I nomi e i valori delle proprietà personalizzate non possono essere vuoti; i nomi devono essere univoci e diversi dalle proprietà integrate."
],
- "Dashboard": [
- "Dashboard"
+ "Properties": [
+ "Proprietà"
],
- "Failed to load TOPS statistics.": [
+ "Built-in property names are preserved when the decision is submitted.": [
""
],
- "Statistics": [
- "Statistiche"
+ "Custom properties": [
+ "Proprietà personalizzate"
],
- "Accounts open": [
- "Conti aperti"
+ "Add more properties that are not listed above.": [
+ "Aggiungi altre proprietà non elencate sopra."
],
- "New files last year": [
- "Nuovi fascicoli nell'ultimo anno"
+ "New properties": [
+ "Nuove proprietà"
],
- "Closed files last year": [
- "Fascicoli chiusi nell'ultimo anno"
+ "Value": [
+ "Valore"
],
- "MROS substantiated": [
- "MROS comprovate"
+ "Current note on the GwG file": [
+ "Nota attuale sul fascicolo GwG"
],
- "MROS simple": [
- "MROS semplici"
+ "Customer name or internal alias.": [
+ "Nome del cliente o alias interno."
],
- "High risk files": [
- "Fascicoli ad alto rischio"
+ "Is the account active for deposit and payments?": [
+ "Il conto è attivo per depositi e pagamenti?"
],
- "PEP files": [
- "Fascicoli PEP"
+ "Is the account idle?": [
+ "Il conto è inattivo?"
],
- "Number of accounts that are opened": [
- "Numero di conti aperti"
+ "No operation for a period of time": [
+ "Nessuna operazione per un periodo di tempo"
],
- "Number of new GwG files in the last year": [
- "Numero di nuovi fascicoli GwG nell'ultimo anno"
+ "Does account belong to a domestic PEP?": [
+ "Il conto appartiene a un PEP nazionale?"
],
- "Number of GwG files closed in the last year": [
- "Numero di fascicoli GwG chiusi nell'ultimo anno"
+ "Does account belong to a foreign PEP?": [
+ "Il conto appartiene a un PEP straniero?"
],
- "Number of MROS reports based on Art 9 Abs. 1 GwG (per year)": [
- "Numero di segnalazioni MROS basate sull'Art. 9 cpv. 1 GwG (all'anno)"
+ "Does account belong to an international-organization PEP?": [
+ "Il conto appartiene a un PEP di organizzazione internazionale?"
],
- "Number of MROS reports based on Art 305ter Abs. 2 StGB (per year)": [
- "Numero di segnalazioni MROS basate sull'Art. 305ter cpv. 2 StGB (all'anno)"
+ "Does account belong to a high risk customer?": [
+ "Il conto appartiene a un cliente ad alto rischio?"
],
- "Number of GwG files of high-risk customers": [
- "Numero di fascicoli GwG di clienti ad alto rischio"
+ "Does account belong to a person from a high risk country?": [
+ "Il conto appartiene a una persona proveniente da un paese ad alto rischio?"
],
- "Number of GwG files managed with “increased risk” due to PEP status": [
- "Numero di fascicoli GwG gestiti con \"rischio aumentato\" a causa dello stato PEP"
+ "The MROS reporting state for the account.": [
+ "Lo stato di segnalazione MROS per il conto."
],
- "previous": [
- "precedente"
+ "None": [
+ "Nessuno"
],
- "Decreased by": [
- "Diminuito di"
+ "Pending investigation": [
+ "Indagine in corso"
],
- "Increased by": [
- "Aumentato di"
+ "Investigated without suspicion": [
+ "Indagato senza sospetti"
],
- "Events": [
- "Eventi"
+ "Reported simple suspicion": [
+ "Sospetto semplice segnalato"
],
- "The events will be triggered only after the decision has been confirmed.": [
- "Gli eventi verranno attivati solo dopo la conferma della decisione."
+ "Reported substantiated suspicion": [
+ "Sospetto comprovato segnalato"
],
- "Calculated": [
- "Calcolato"
+ "Informal reason why the AML investigation was triggered": [
+ "Motivo informale per cui è stata avviata l'indagine AML"
],
- "Events based on properties and new attributes that should be triggered": [
- "Eventi basati su proprietà e nuovi attributi che dovrebbero essere attivati"
+ "Identifies the sanction list entry that the account matched against": [
+ "Identifica la voce dell'elenco sanzionatorio con cui il conto corrisponde"
],
- "Others": [
- "Altri"
+ "Best match, does not mean it was a good match.": [
+ "Migliore corrispondenza, non significa che fosse una buona corrispondenza."
],
- "Events that can be triggered manually": [
- "Eventi che possono essere attivati manualmente"
+ "Score for how good the sanction list match was": [
+ "Punteggio di quanto buona sia stata la corrispondenza con l'elenco sanzionatorio"
],
- "Custom list": [
- "Elenco personalizzato"
+ "Integer score from 0 (no match) to 1,000,000,000 (best match).": [
+ ""
],
- "Events without built-in support.": [
- "Eventi senza supporto integrato."
+ "Score for how much supporting data we had for the sanction list match": [
+ "Punteggio di quanti dati di supporto avevamo per la corrispondenza con l'elenco sanzionatorio"
],
- "Complete the form": [
- "Completa il modulo"
+ "Integer score from 0 (no supporting data) to 1,000,000,000 (highest confidence).": [
+ ""
],
- "These measures will ask the customer for information.": [
- "Queste misure chiederanno informazioni al cliente."
+ "Suppress flagging this account when it creates a hit on a sanctions list, this is a false-positive": [
+ "Sopprimi la segnalazione di questo conto quando genera una corrispondenza in un elenco sanzionatorio, si tratta di un falso positivo"
],
- "change form": [
- "cambia modulo"
+ "Expiration shortcuts": [
+ "Scorciatoie di scadenza"
],
- "Expiration date of the information filled in this form.": [
- "Data di scadenza delle informazioni compilate in questo modulo."
+ "In a week": [
+ "Tra una settimana"
],
- "Include new information": [
- "Includi nuove informazioni"
+ "In a month": [
+ "Tra un mese"
],
- "Select a form to submit new information about the customer or continue to the next step": [
- "Seleziona un modulo per inviare nuove informazioni sul cliente oppure continua al passaggio successivo"
+ "In a year": [
+ "Tra un anno"
],
- "Form:": [
- "Modulo:"
+ "Never": [
+ "Mai"
],
- "Justification": [
- "Giustificazione"
+ "Failed to load available measures.": [
+ "Impossibile caricare le misure disponibili."
],
- "Keep investigation?": [
- "Mantenere l'indagine?"
+ "The officer session is invalid.": [
+ "La sessione dell’addetto AML non è valida."
],
- "Account holder": [
- "Titolare del conto"
+ "The measures endpoint was not found.": [
+ "L’endpoint delle misure non è stato trovato."
],
- "Full name of the account holder": [
- "Nome completo del titolare del conto"
+ "The officer session is disabled.": [
+ "La sessione dell’addetto AML è disabilitata."
],
- "loading...": [
- "caricamento..."
+ "Edit proposed rule": [
+ "Modifica regola proposta"
],
- "Update": [
- "Aggiorna"
+ "Add proposed rule": [
+ "Aggiungi regola proposta"
],
- "Remove": [
- "Rimuovi"
+ "Save rule": [
+ "Salva regola"
],
- "Configure verification type: %1$s": [
- "Configura il tipo di verifica: %1$s"
+ "Add rule": [
+ "Aggiungi regola"
],
- "Show complete form": [
- "Mostra modulo completo"
+ "This complete rule set replaces the currently applied rules and exchange defaults until it expires. Higher rows take precedence.": [
+ "Questo insieme completo sostituisce le regole attualmente applicate e quelle predefinite dell’exchange fino alla scadenza. Le righe più in alto hanno la precedenza."
],
- "Configure measure": [
- "Configura misura"
+ "Rules for another account type": [
+ "Regole per un altro tipo di conto"
],
- "Show as verification": [
- "Mostra come verifica"
+ "These operations do not apply to this account type: %1$s.": [
+ "Queste operazioni non si applicano a questo tipo di conto: %1$s."
],
- "There is already a measure with that name": [
- "Esiste già una misura con quel nome"
+ "Operations without limits": [
+ "Operazioni senza limiti"
],
- "Only required when no check is specified": [
- "Obbligatorio solo quando non è specificata alcuna verifica"
+ "No proposed rule limits these operations: %1$s.": [
+ "Nessuna regola proposta limita queste operazioni: %1$s."
],
- "Missing check or program": [
- "Verifica o programma mancante"
+ "Invalid proposed rules": [
+ "Regole proposte non valide"
],
- "Without a check the program will run automatically": [
- "Senza una verifica, il programma verrà eseguito automaticamente"
+ "Edit the highlighted rule set before continuing. Hard blocks cannot be combined with measures, and Balance and Refund rules must use an instant timeframe.": [
+ "Modifica l’insieme di regole evidenziato prima di continuare. I blocchi rigidi non possono essere combinati con misure e le regole per saldo e rimborso devono usare un intervallo istantaneo."
],
- "Field name": [
- "Nome del campo"
+ "Remove proposed rule?": [
+ "Rimuovere la regola proposta?"
],
- "Type": [
- "Tipo"
+ "This is the final rule. Removing it leaves every applicable operation unlimited.": [
+ "Questa è l’ultima regola. Rimuovendola, tutte le operazioni applicabili resteranno senza limiti."
],
- "string": [
- "stringa"
+ "The rule will be removed from the proposed set.": [
+ "La regola verrà rimossa dall’insieme proposto."
],
- "number": [
- "numero"
+ "Keep rule": [
+ "Mantieni regola"
],
- "boolean": [
- "booleano"
+ "Remove rule": [
+ "Rimuovi regola"
],
- "json": [
- "json"
+ "Replace proposed rules": [
+ "Sostituisci regole proposte"
],
- "Value": [
- "Valore"
+ "Preview a complete replacement before applying it.": [
+ "Visualizza l’anteprima della sostituzione completa prima di applicarla."
],
- "There are unsatisfied inputs: %1$s": [
- "Ci sono input non soddisfatti: %1$s"
+ "Currently applied": [
+ "Attualmente applicate"
],
- "There are missing inputs: %1$s": [
- "Ci sono input mancanti: %1$s"
+ "E-commerce": [
+ "E-commerce"
],
- "There are missing requirements: %1$s": [
- "Ci sono requisiti mancanti: %1$s"
+ "Point of Sale": [
+ "Punto vendita"
],
- "Can't be empty": [
- "Non può essere vuoto"
+ "Basic plan": [
+ "Piano base"
],
- "It should be a number": [
- "Deve essere un numero"
+ "Premium": [
+ "Premium"
],
- "Not a number": [
- "Non è un numero"
+ "Freeze account": [
+ "Congela conto"
],
- "It should be finite": [
- "Deve essere finito"
+ "Replacement preview": [
+ "Anteprima della sostituzione"
],
- "It should be a safe integer": [
- "Deve essere un intero sicuro"
+ "Confirm account freeze": [
+ "Conferma il blocco del conto"
],
- "It should be either \"true\" or \"false\"": [
- "Deve essere \"true\" o \"false\""
+ "Every applicable operation will receive a zero hard limit.": [
+ "Ogni operazione applicabile riceverà un limite rigido pari a zero."
],
- "Couldn't parse as json string: %1$s": [
- "Impossibile analizzare come stringa json: %1$s"
+ "Apply replacement": [
+ "Applica sostituzione"
],
- "Description": [
- "Descrizione"
+ "Choose how long the proposed rules apply and what happens afterwards.": [
+ "Scegli per quanto tempo si applicano le regole proposte e cosa accade dopo."
],
- "Inputs": [
- "Input"
+ "The proposed rules never expire, so no successor action will run.": [
+ "Le regole proposte non scadono mai, quindi non verrà eseguita alcuna azione successiva."
],
- "Output": [
- "Output"
+ "Restore currently applied expiration": [
+ "Ripristina la scadenza attualmente applicata"
],
- "Requires": [
- "Richiede"
+ "Operation type": [
+ "Tipo di operazione"
],
- "Fallback": [
- "Fallback"
+ "Timeframe": [
+ "Intervallo di tempo"
],
- "Name of the verification measure": [
- "Nome della misura di verifica"
+ "Use Y, M, D, h, m or s after each number. Forever accumulates over the account's full history.": [
+ "Usa Y, M, D, h, m o s dopo ogni numero. «Per sempre» accumula l’intera cronologia del conto."
],
- "Read only": [
- "Sola lettura"
+ "Instant timeframe": [
+ "Intervallo istantaneo"
],
- "Prevent the customer from changing the address": [
- "Impedisce al cliente di modificare l'indirizzo"
+ "Balance and Refund limits apply to one balance or transaction, so their timeframe is fixed to zero.": [
+ "I limiti per saldo e rimborso si applicano a un saldo o a una transazione, quindi il loro intervallo è fissato a zero."
],
- "Configure verification measure: \"%1$s\"": [
- "Configura misura di verifica: \"%1$s\""
+ "Exposed": [
+ "Esposto"
],
- "Add custom measure": [
- "Aggiungi misura personalizzata"
+ "Is this limit communicated to the customer?": [
+ "Questo limite viene comunicato al cliente?"
],
- "Custom measures": [
- "Misure personalizzate"
+ "When the threshold is crossed": [
+ "Quando viene superata la soglia"
],
- "Server measures": [
- "Misure del server"
+ "Require measures": [
+ "Richiedi misure"
],
- "New measures": [
- "Nuove misure"
+ "Required measures": [
+ "Misure richieste"
],
- "Measures that are available/executed directly after the decision is confirmed.": [
- "Misure disponibili/eseguite immediatamente dopo la conferma della decisione."
+ "Measures that the customer will need to satisfy to apply for a new threshold.": [
+ "Misure che il cliente dovrà soddisfare per richiedere una nuova soglia."
],
- "Reset to default": [
- "Ripristina i valori predefiniti"
+ "All measures": [
+ "Tutte le misure"
],
- "Properties": [
- "Proprietà"
+ "Hint the customer that all measures should be completed": [
+ "Segnala al cliente che tutte le misure devono essere completate"
],
- "Custom properties": [
- "Proprietà personalizzate"
+ "Expiration date": [
+ "Data di scadenza"
],
- "Add more properties that are not listed above.": [
- "Aggiungi altre proprietà non elencate sopra."
+ "Until when are the new rules active.": [
+ "Fino a quando sono attive le nuove regole."
],
- "New properties": [
- "Nuove proprietà"
+ "Choose a future expiration date or Never.": [
+ "Scegli una data di scadenza futura oppure «Mai»."
],
- "Current note on the GwG file": [
- "Nota attuale sul fascicolo GwG"
+ "After expiration": [
+ "Dopo la scadenza"
],
- "Customer name or internal alias.": [
- "Nome del cliente o alias interno."
+ "Return to exchange defaults": [
+ "Torna alle impostazioni predefinite dell’exchange"
],
- "Is the account active for deposit and payments?": [
- "Il conto è attivo per depositi e pagamenti?"
+ "Trigger a successor measure": [
+ "Attiva una misura successiva"
],
- "Is the account idle?": [
- "Il conto è inattivo?"
+ "Measure taken automatically upon expiration of the current decision.": [
+ "Misura adottata automaticamente alla scadenza della decisione attuale."
],
- "No operation for a period of time": [
- "Nessuna operazione per un periodo di tempo"
+ "This successor measure is no longer available.": [
+ "Questa misura successiva non è più disponibile."
],
- "Does account belong to a domestic PEP?": [
- "Il conto appartiene a un PEP nazionale?"
+ "Case summary": [
+ "Riepilogo del caso"
],
- "Does account belong to a foreign PEP?": [
- "Il conto appartiene a un PEP straniero?"
+ "Current review state and the latest account activity.": [
+ "Stato attuale della revisione e attività più recente del conto."
],
- "Does account belong to an international-organization PEP?": [
- "Il conto appartiene a un PEP di organizzazione internazionale?"
+ "Review status": [
+ "Stato della revisione"
],
- "Does account belong to a high risk customer?": [
- "Il conto appartiene a un cliente ad alto rischio?"
+ "Loading…": [
+ "Caricamento…"
],
- "Does account belong to a person from a high risk country?": [
- "Il conto appartiene a una persona proveniente da un paese ad alto rischio?"
+ "Manual review required — waiting for an AML decision.": [
+ "Revisione manuale richiesta — in attesa di una decisione AML."
],
- "The MROS reporting state for the account.": [
- "Lo stato di segnalazione MROS per il conto."
+ "No manual review": [
+ "Nessuna revisione manuale"
],
- "None": [
- "Nessuno"
+ "Effective decision": [
+ "Decisione in vigore"
],
- "Pending investigation": [
- "Indagine in corso"
+ "Requirements": [
+ "Requisiti"
],
- "Investigated without suspicion": [
- "Indagato senza sospetti"
+ "Latest collected information": [
+ "Ultime informazioni raccolte"
],
- "Reported simple suspicion": [
- "Sospetto semplice segnalato"
+ "Effective policy": [
+ "Politica in vigore"
],
- "Reported substantiated suspicion": [
- "Sospetto comprovato segnalato"
+ "The AML decision and operation rules currently applied to this account.": [
+ "La decisione AML e le regole operative attualmente applicate a questo conto."
],
- "Informal reason why the AML investigation was triggered": [
- "Motivo informale per cui è stata avviata l'indagine AML"
+ "Effective policy could not be loaded": [
+ "Impossibile caricare la politica effettiva"
],
- "Identifies the sanction list entry that the account matched against": [
- "Identifica la voce dell'elenco sanzionatorio con cui il conto corrisponde"
+ "Exchange defaults apply": [
+ "Si applicano le regole predefinite dell’Exchange"
],
- "Best match, does not mean it was a good match.": [
- "Migliore corrispondenza, non significa che fosse una buona corrispondenza."
+ "No AML officer decision is active for this account.": [
+ "Nessuna decisione di un addetto AML è attiva per questo conto."
],
- "Score for how good the sanction list match was": [
- "Punteggio di quanto buona sia stata la corrispondenza con l'elenco sanzionatorio"
+ "Account type unavailable": [
+ "Tipo di conto non disponibile"
],
- "Score for how much supporting data we had for the sanction list match": [
- "Punteggio di quanti dati di supporto avevamo per la corrispondenza con l'elenco sanzionatorio"
+ "Open this case from the account directory or payto search to see the applicable default rules.": [
+ "Aprire questo caso dalla directory dei conti o dalla ricerca payto per visualizzare le regole predefinite applicabili."
],
- "Suppress flagging this account when it creates a hit on a sanctions list, this is a false-positive": [
- "Sopprimi la segnalazione di questo conto quando genera una corrispondenza in un elenco sanzionatorio, si tratta di un falso positivo"
+ "Default rules could not be loaded": [
+ "Impossibile caricare le regole predefinite"
],
- "Confirmation required": [
- "Conferma richiesta"
+ "Default rules": [
+ "Regole predefinite"
],
- "I want to check first!": [
- "Voglio prima controllare!"
+ "Account assessment": [
+ "Valutazione del conto"
],
- "Confirm decision": [
- "Conferma decisione"
+ "Properties recorded by AML officers for this account.": [
+ "Proprietà registrate dagli addetti AML per questo conto."
],
- "Missing deadline": [
- "Scadenza mancante"
+ "Account assessment could not be loaded": [
+ "Impossibile caricare la valutazione del conto"
],
- "Deadline should specify when this rules ends and what is the next measures to apply after expiration.": [
- "La scadenza deve specificare quando termina questa regola e quali sono le prossime misure da applicare dopo la scadenza."
+ "Collected information": [
+ "Informazioni raccolte"
],
- "Missing rules": [
- "Regole mancanti"
+ "KYC information filed by the customer or an AML officer.": [
+ "Informazioni KYC inserite dal cliente o da un addetto AML."
],
- "Can't make a decision without rules.": [
- "Impossibile prendere una decisione senza regole."
+ "Collected information could not be loaded": [
+ "Impossibile caricare le informazioni raccolte"
],
- "Missing active measure": [
- "Misura attiva mancante"
+ "No collected information": [
+ "Nessuna informazione raccolta"
],
- "You should specify in the measure section.": [
- "Devi specificarlo nella sezione delle misure."
+ "No KYC information has been collected for this account.": [
+ "Non sono state raccolte informazioni KYC per questo conto."
],
- "No customer action required.": [
- "Non è richiesta alcuna azione da parte del cliente."
+ "Active requirements": [
+ "Requisiti attivi"
],
- "No active measure has been selected.": [
- "Non è stata selezionata alcuna misura attiva."
+ "Measures the customer must complete under the current policy.": [
+ "Misure che il cliente deve completare secondo la politica attuale."
],
- "Missing properties": [
- "Proprietà mancanti"
+ "Active requirements could not be loaded": [
+ "Impossibile caricare i requisiti attivi"
],
- "You should specify in the properties section.": [
- "Devi specificarlo nella sezione delle proprietà."
+ "No active requirements": [
+ "Nessun requisito attivo"
],
- "Missing events": [
- "Eventi mancanti"
+ "The customer has no active legitimization measures to complete.": [
+ "Il cliente non ha misure di legittimazione attive da completare."
],
- "You should specify in the events section.": [
- "Devi specificarlo nella sezione degli eventi."
+ "Officer decision": [
+ "Decisione dell’addetto"
],
- "Missing justification": [
- "Giustificazione mancante"
+ "Does not expire": [
+ "Non scade"
],
- "You must complete the justification section.": [
- "Devi completare la sezione della giustificazione."
+ "Waiting": [
+ "In attesa"
],
- "Invalid attributes": [
- "Attributi non validi"
+ "More on later pages": [
+ "Altri elementi nelle pagine successive"
],
- "You should check form errors or submit a decision without attributes.": [
- "Controlla gli errori del modulo oppure invia una decisione senza attributi."
+ "Try loading this section again.": [
+ "Provare a ricaricare questa sezione."
],
- "Clear": [
- "Cancella"
+ "Retry": [
+ "Riprova"
],
- "Send decision": [
- "Invia decisione"
+ "No account properties": [
+ "Nessuna proprietà del conto"
],
- "Prev": [
- "Prec."
+ "No assessment properties have been recorded for this account.": [
+ "Non sono state registrate proprietà di valutazione per questo conto."
],
- "Next": [
- "Successivo"
+ "Yes": [
+ "Sì"
],
- "Attributes": [
- "Attributi"
+ "No": [
+ "No"
],
- "Add more information about the customer": [
- "Aggiungi ulteriori informazioni sul cliente"
+ "Unconfigured form": [
+ "Modulo non configurato"
],
- "Rules": [
- "Regole"
+ "Form not identified": [
+ "Modulo non identificato"
],
- "Set the limit of the operations": [
- "Imposta il limite delle operazioni"
+ "Filed by an AML officer": [
+ "Inserito da un addetto AML"
],
- "Trigger notifications.": [
- "Attiva le notifiche."
+ "Provided by the customer": [
+ "Fornito dal cliente"
],
- "Measures": [
- "Misure"
+ "Attribute data is unavailable.": [
+ "I dati degli attributi non sono disponibili."
],
- "Ask the customer to take action.": [
- "Chiedi al cliente di intervenire."
+ "View details": [
+ "Vedi dettagli"
],
- "Describe the decision.": [
- "Descrivi la decisione."
+ "Review superseded AML decisions for this account, from newest to oldest.": [
+ "Esamina le decisioni AML sostituite per questo conto, dalla più recente alla meno recente."
],
- "Flag the current account state.": [
- "Contrassegna lo stato attuale del conto."
+ "Loading decision history…": [
+ "Caricamento della cronologia delle decisioni…"
],
- "Summary": [
- "Riepilogo"
+ "Decision history could not be loaded": [
+ "Impossibile caricare la cronologia delle decisioni"
],
- "Review and submit.": [
- "Rivedi e invia."
+ "Try loading the decision history again.": [
+ "Prova a caricare di nuovo la cronologia delle decisioni."
],
- "Decision for account:": [
- "Decisione per il conto:"
+ "No previous decisions": [
+ "Nessuna decisione precedente"
],
- "Decision for wallet:": [
- "Decisione per il portafoglio:"
+ "No superseded AML decisions have been recorded for this account.": [
+ "Non sono state registrate decisioni AML sostituite per questo conto."
],
- "Decision for bank account:": [
- "Decisione per il conto bancario:"
+ "Previous decisions": [
+ "Decisioni precedenti"
],
- "Search account": [
- "Cerca conto"
+ "The export could not be prepared. Try again.": [
+ "Non è stato possibile preparare l’esportazione. Riprova."
],
- "Failed to load account decisions.": [
- ""
+ "Failed to load accounts": [
+ "Impossibile caricare i conti"
],
- "Check account details": [
- "Controlla i dettagli del conto"
+ "Accounts": [
+ "Conti"
],
- "Account most recent decisions": [
- "Decisioni più recenti del conto"
+ "Review accounts known to the exchange for AML and KYC handling.": [
+ "Esamina i conti noti all’exchange per la gestione AML e KYC."
],
- "When": [
- "Quando"
+ "Export filtered accounts": [
+ "Esporta i conti filtrati"
],
- "LATEST": [
- "ULTIMA"
+ "Download CSV": [
+ "Scarica CSV"
],
- "ACTIVE": [
- "ATTIVA"
+ "Download Excel": [
+ "Scarica Excel"
],
- "Account not found": [
- "Conto non trovato"
+ "Preparing export…": [
+ "Preparazione dell’esportazione…"
],
- "There is no history known for this account yet.": [
- "Non è ancora nota alcuna cronologia per questo conto."
+ "Export failed": [
+ "Esportazione non riuscita"
],
- "You can make a decision for this account anyway.": [
- "Puoi comunque prendere una decisione per questo conto."
+ "Account filters": [
+ "Filtri dei conti"
],
- "Search": [
- "Cerca"
+ "Investigation": [
+ "Indagine"
],
- "IBAN": [
- "IBAN"
+ "All accounts": [
+ "Tutti i conti"
],
- "Taler Bank": [
- "Taler Bank"
+ "Not under investigation": [
+ "Non sotto indagine"
],
- "Wallet": [
- "Portafoglio"
+ "Risk": [
+ "Rischio"
],
- "Generic Payto:// URI": [
- "URI Payto:// generico"
+ "All risk levels": [
+ "Tutti i livelli di rischio"
],
- "Account type": [
- "Tipo di conto"
+ "Not high risk": [
+ "Senza rischio elevato"
],
- "Should be 52 characters.": [
- "Deve essere di 52 caratteri."
+ "File status": [
+ "Stato del fascicolo"
],
- "Failed to parse: %1$s": [
- "Impossibile analizzare: %1$s"
+ "All file statuses": [
+ "Tutti gli stati del fascicolo"
],
- "Address contains invalid characters.": [
- "L'indirizzo contiene caratteri non validi."
+ "Not open": [
+ "Non aperto"
],
- "Can't mix uppercased and lowercased characters.": [
- "Impossibile combinare caratteri maiuscoli e minuscoli."
+ "Clear filters": [
+ "Cancella filtri"
],
- "The addr checksum doesn't match.": [
- "Il checksum dell'indirizzo non corrisponde."
+ "Showing %1$s accounts · newest first": [
+ "Visualizzati %1$s conti · prima i più recenti"
],
- "Missing separator or address type.": [
- "Separatore o tipo di indirizzo mancante."
+ "AML and KYC accounts": [
+ "Conti AML e KYC"
],
- "Address should have less than 90 characters.": [
- "L'indirizzo deve avere meno di 90 caratteri."
+ "Account lifecycle": [
+ "Ciclo di vita del fascicolo"
],
- "Address should have more than 6 characters.": [
- "L'indirizzo deve avere più di 6 caratteri."
+ "Latest note": [
+ "Nota più recente"
],
- "Decoding issue.": [
- ""
+ "Copied": [
+ "Copiato"
],
- "Unsupported country.": [
- "Paese non supportato."
+ "Copy": [
+ "Copia"
],
- "IBANs have fewer than 34 characters.": [
- "Gli IBAN hanno meno di 34 caratteri."
+ "No matching accounts": [
+ "Nessun conto corrispondente"
],
- "IBANs have more than 4 characters.": [
- "Gli IBAN hanno più di 4 caratteri."
+ "No accounts yet": [
+ "Ancora nessun conto"
],
- "IBAN length is invalid for this country.": [
- "La lunghezza dell'IBAN non è valida per questo paese."
+ "No accounts match the selected filters.": [
+ "Nessun conto corrisponde ai filtri selezionati."
],
- "It should only contain numbers and letters.": [
- "Deve contenere solo numeri e lettere."
+ "The exchange has not recorded any AML or KYC accounts yet.": [
+ "L’exchange non ha ancora registrato alcun conto AML o KYC."
],
- "The checksum is wrong.": [
- "Il checksum è errato."
+ "This officer session is not authorized to list accounts.": [
+ "Questa sessione operatore non è autorizzata a elencare i conti."
],
- "The string should start with payto://": [
- "La stringa deve iniziare con payto://"
+ "The exchange does not recognize this officer session.": [
+ "L’exchange non riconosce questa sessione operatore."
],
- "After the target type it should follow a '/' with more information.": [
- "Dopo il tipo di destinazione deve seguire un '/' con ulteriori informazioni."
+ "This officer session is currently disabled.": [
+ "Questa sessione operatore è attualmente disabilitata."
],
- "The target type is not supported, only x-taler-bank, taler-reserve or iban": [
- "Il tipo di destinazione non è supportato, solo x-taler-bank, taler-reserve o iban"
+ "There are no matching accounts to export.": [
+ "Non ci sono conti corrispondenti da esportare."
],
- "IBAN is missing": [
- "L'IBAN è mancante"
+ "The exchange does not support the selected export format.": [
+ "L’exchange non supporta il formato di esportazione selezionato."
],
- "Bitcoin address is missing": [
- "L'indirizzo Bitcoin è mancante"
+ "This officer session is not authorized to export accounts.": [
+ "Questa sessione operatore non è autorizzata a esportare i conti."
],
- "Bank host and account is missing": [
- "L'host della banca e il conto sono mancanti"
+ "Dashboard": [
+ "Dashboard"
],
- "Exchange host and account is missing": [
- "L'host dell'Exchange e il conto sono mancanti"
+ "Review cases requiring attention, investigate accounts, and monitor AML reporting indicators.": [
+ ""
],
- "Ethereum address is missing": [
- "L'indirizzo Ethereum è mancante"
+ "Review case queue": [
+ ""
],
- "Cyclos address is missing": [
- "L'indirizzo Cyclos è mancante"
+ "Find credit, debit, and KYC authorization activity.": [
+ ""
],
- "Invalid IBAN: %1$s": [
- "IBAN non valido: %1$s"
+ "Statistics": [
+ "Statistiche"
],
- "Invalid BTC: %1$s": [
- "BTC non valido: %1$s"
+ "No reporting profile for this dialect": [
+ ""
],
- "Invalid reserve: %1$s": [
- "Riserva non valida: %1$s"
+ "The testing dialect does not define dashboard statistics. Select TOPS in development settings to inspect the TOPS reporting profile.": [
+ ""
],
- "Invalid host": [
- "Host non valido"
+ "Failed to load TOPS statistics.": [
+ ""
],
- "Invalid address": [
- "Indirizzo non valido"
+ "The available values are shown below. Missing values are not zero.": [
+ ""
],
- "Payto URI": [
- "URI Payto"
+ "Accounts open": [
+ "Conti aperti"
],
- "As defined by RFC 8905": [
- "Come definito dalla RFC 8905"
+ "New files last year": [
+ "Nuovi fascicoli nell'ultimo anno"
],
- "payto://": [
- "payto://"
+ "Closed files last year": [
+ "Fascicoli chiusi nell'ultimo anno"
],
- "International Bank Account Number": [
- "Numero di conto bancario internazionale"
+ "MROS substantiated": [
+ "MROS comprovate"
],
- "DE1231231231": [
- "DE1231231231"
+ "MROS simple": [
+ "MROS semplici"
],
- "Host": [
- "Host"
+ "High risk files": [
+ "Fascicoli ad alto rischio"
],
- "Exchange hostname": [
- "Hostname dell'Exchange"
+ "PEP files": [
+ "Fascicoli PEP"
],
- "exchange.taler.net": [
- "exchange.taler.net"
+ "Number of accounts that are opened": [
+ "Numero di conti aperti"
],
- "Remove last '/'": [
- "Rimuovi l'ultimo '/'"
+ "Number of new GwG files in the last year": [
+ "Numero di nuovi fascicoli GwG nell'ultimo anno"
],
- "Invalid value": [
- "Valore non valido"
+ "Number of GwG files closed in the last year": [
+ "Numero di fascicoli GwG chiusi nell'ultimo anno"
],
- "ID": [
- "ID"
+ "Number of MROS reports based on Art 9 Abs. 1 GwG (per year)": [
+ "Numero di segnalazioni MROS basate sull'Art. 9 cpv. 1 GwG (all'anno)"
],
- "Wallet reserve public key": [
- "Chiave pubblica di riserva del portafoglio"
+ "Number of MROS reports based on Art 305ter Abs. 2 StGB (per year)": [
+ "Numero di segnalazioni MROS basate sull'Art. 305ter cpv. 2 StGB (all'anno)"
],
- "abcdef1235": [
- "abcdef1235"
+ "Number of GwG files of high-risk customers": [
+ "Numero di fascicoli GwG di clienti ad alto rischio"
],
- "Should be 52 characters": [
- "Deve essere di 52 caratteri"
+ "Number of GwG files managed with “increased risk” due to PEP status": [
+ "Numero di fascicoli GwG gestiti con \"rischio aumentato\" a causa dello stato PEP"
],
- "Account": [
- "Conto"
+ "previous": [
+ "precedente"
],
- "Bank account identification": [
- "Identificazione del conto bancario"
+ "Decreased by": [
+ "Diminuito di"
],
- "DE123123123": [
- "DE123123123"
+ "Increased by": [
+ "Aumentato di"
],
- "Hostname": [
- "Hostname"
+ "The built-in event selection differs from the events derived from the proposed account state.": [
+ ""
],
- "Without the scheme, may include subpath: bank.com, bank.com/path/": [
- "Senza lo schema, può includere un sottopercorso: bank.com, bank.com/path/"
+ "Built-in events are derived from changes to the proposed account properties. They are stored for reporting and statistics; they do not notify the customer.": [
+ ""
],
- "bank.demo.taler.net": [
- "bank.demo.taler.net"
+ "Calculated": [
+ "Calcolato"
],
- "Invalid hostname": [
- "Hostname non valido"
+ "Events derived from proposed property changes and submitted information.": [
+ ""
],
- "Failed to load the account information.": [
+ "Other built-in events": [
""
],
- "Different form version": [
- "Versione del modulo differente"
+ "Operator-defined event names that are not part of the selected dialect.": [
+ ""
],
- "The collected information don't have the form version used.": [
- "Le informazioni raccolte non riportano la versione del modulo utilizzata."
+ "The completed form is attached to this AML decision as reviewed account information. It does not create a customer-facing measure.": [
+ ""
],
- "The collected information used the form version \"%1$s \" but is not available.": [
- "Le informazioni raccolte hanno usato la versione del modulo \"%1$s \" ma non è disponibile."
+ "Expiration": [
+ "Scadenza"
],
- "Case details": [
- "Dettagli del caso"
+ "Expiration date of the information filled in this form.": [
+ "Data di scadenza delle informazioni compilate in questo modulo."
],
- "Next event": [
- "Evento successivo"
+ "Only change this operator-defined JSON when the form documentation requires additional context.": [
+ ""
],
- "Previous event": [
- "Evento precedente"
+ "Invalid expiration": [
+ "Scadenza non valida"
],
- "Direction": [
- "Direzione"
+ "Attributes require an expiration date in the future or set to Never.": [
+ "Gli attributi richiedono una data di scadenza futura o devono essere impostati su «Mai»."
],
- "Credit": [
- "Credito"
+ "Include new information": [
+ "Includi nuove informazioni"
],
- "Debit": [
- "Debito"
+ "This step is optional. Select a form to attach newly reviewed AML/KYC information, or continue without one.": [
+ ""
],
- "KYC Auth": [
- "Autenticazione KYC"
+ "AML/KYC form": [
+ ""
],
- "Minimum amount": [
- "Importo minimo"
+ "Search AML/KYC forms": [
+ "Cerca moduli AML/KYC"
],
- "All amounts below the given threshold will be filtered.": [
- "Tutti gli importi inferiori alla soglia indicata verranno filtrati."
+ "Full name used in the payto URI when creating this previously unknown account.": [
+ ""
],
- "Failed to load the transfer list.": [
+ "Record the facts and reasoning needed to understand this decision in a later audit or review.": [
""
],
- "Select transaction type": [
- "Seleziona il tipo di transazione"
+ "Combine a customer check with an AML program, or use SKIP to run a program immediately. Context values must satisfy the selected check and program requirements.": [
+ ""
],
- "Please select a transaction type to show transactions.": [
- "Seleziona un tipo di transazione per mostrare le transazioni."
+ "Add custom measure": [
+ "Aggiungi misura personalizzata"
],
- "Transfers history for account": [
- "Cronologia dei trasferimenti per il conto"
+ "Save changes": [
+ ""
],
- "Transfers history": [
- "Cronologia dei trasferimenti"
+ "Use advanced measure editor": [
+ ""
],
- "No transfers yet.": [
- "Nessun trasferimento ancora."
+ "There is already a measure with that name": [
+ "Esiste già una misura con quel nome"
],
- "There are no transfers for this account.": [
- "Non ci sono trasferimenti per questo conto."
+ "Runs immediately for SKIP measures, or after a successful check. It may be omitted for a check that only presents or collects information.": [
+ ""
],
- "There are no transfers reported to the exchange with the current threshold.": [
- "Non ci sono trasferimenti segnalati all'Exchange con la soglia attuale."
+ "Missing check or program": [
+ "Verifica o programma mancante"
],
- "Date": [
- "Data"
+ "The customer-facing check to perform before the program. Leave empty to use SKIP and run the program immediately.": [
+ ""
],
- "Amount": [
- "Importo"
+ "Configuration values required by the selected check or program. Property names and value types must match the exchange configuration.": [
+ ""
],
- "sent": [
- "inviato"
+ "Field name": [
+ "Nome del campo"
],
- "received": [
- "ricevuto"
+ "Type": [
+ "Tipo"
],
- "to": [
- "a"
+ "string": [
+ "stringa"
],
- "from": [
- "da"
+ "number": [
+ "numero"
],
- "Welcome to the exchange configuration": [
- "Benvenuto nella configurazione dell'Exchange"
+ "boolean": [
+ "booleano"
],
- "Transfers": [
- "Trasferimenti"
+ "json": [
+ "json"
],
- "Profile": [
- "Profilo"
+ "There are unsatisfied inputs: %1$s": [
+ "Ci sono input non soddisfatti: %1$s"
],
- "Failed to load available measures.": [
- "Impossibile caricare le misure disponibili."
+ "Check \"%1$s\" is not available": [
+ ""
],
- "The officer session is invalid.": [
- "La sessione dell’addetto AML non è valida."
+ "There are missing inputs: %1$s": [
+ "Ci sono input mancanti: %1$s"
],
- "The measures endpoint was not found.": [
- "L’endpoint delle misure non è stato trovato."
+ "There are missing requirements: %1$s": [
+ "Ci sono requisiti mancanti: %1$s"
],
- "The officer session is disabled.": [
- "La sessione dell’addetto AML è disabilitata."
+ "Can't be empty": [
+ "Non può essere vuoto"
],
- "Failed to load the active AML decision.": [
- "Impossibile caricare la decisione AML attiva."
+ "Not a number": [
+ "Non è un numero"
],
- "The officer session signature is invalid.": [
- "La firma della sessione dell’addetto AML non è valida."
+ "It should be finite": [
+ "Deve essere finito"
],
- "The requested AML account or session was not found.": [
- "L’account AML o la sessione richiesta non è stato trovato."
+ "It should be either \"true\" or \"false\"": [
+ "Deve essere \"true\" o \"false\""
],
- "The officer session is disabled or the account state changed.": [
- "La sessione dell’addetto AML è disabilitata oppure lo stato dell’account è cambiato."
+ "Couldn't parse as json string: %1$s": [
+ "Impossibile analizzare come stringa json: %1$s"
],
- "Invalid expiration": [
- "Scadenza non valida"
+ "Description": [
+ "Descrizione"
],
- "Attributes require an expiration date in the future.": [
- "Gli attributi richiedono una data di scadenza futura."
+ "Inputs": [
+ "Input"
],
- "Too many SKIP measures": [
- "Troppe misure SKIP"
+ "Fallback": [
+ "Fallback"
],
- "At most one immediate measure may use the SKIP check.": [
- "Al massimo una misura immediata può usare il controllo SKIP."
+ "Selected pipeline": [
+ ""
],
- "Require all measures": [
- "Richiedi tutte le misure"
+ "Review how the exchange will execute this measure.": [
+ ""
],
- "Run all selected measures together instead of accepting any one of them.": [
- "Esegui insieme tutte le misure selezionate anziché accettarne una qualsiasi."
+ "Name of the verification measure": [
+ "Nome della misura di verifica"
],
- "Invalid custom properties": [
- "Proprietà personalizzate non valide"
+ "Read only": [
+ "Sola lettura"
],
- "Custom property names and values must be non-empty and names must be unique and different from built-in properties.": [
- "I nomi e i valori delle proprietà personalizzate non possono essere vuoti; i nomi devono essere univoci e diversi dalle proprietà integrate."
+ "Prevent the customer from changing the address": [
+ "Impedisce al cliente di modificare l'indirizzo"
],
- "Unknown measure": [
- "Misura sconosciuta"
+ "Customer actions after submission": [
+ ""
],
- "A rule or immediate action references a measure that is not available. Review the rules and measures before submitting.": [
- "Una regola o un’azione immediata fa riferimento a una misura non disponibile. Verifica le regole e le misure prima dell’invio."
+ "Immediate measures start as soon as this decision is accepted. A measure may show information, collect customer data, or run an AML program. Leave the selection empty when no immediate customer action is required.": [
+ ""
],
- "Requires investigation": [
- "Richiede un’indagine"
+ "Too many SKIP measures": [
+ "Troppe misure SKIP"
],
- "Collection event not found": [
- "Evento di raccolta non trovato"
+ "At most one immediate measure may use the SKIP check.": [
+ "Al massimo una misura immediata può usare il controllo SKIP."
],
- "There is no collection event with ID %1$s for this account.": [
- "Non esiste alcun evento di raccolta con ID %1$s per questo account."
+ "Custom measures": [
+ "Misure personalizzate"
],
- "Attributes unavailable": [
- "Attributi non disponibili"
+ "Measures defined only for this proposed decision.": [
+ ""
],
- "The collection event does not contain readable attributes.": [
- "L’evento di raccolta non contiene attributi leggibili."
+ "Edit": [
+ ""
],
- "Form identifier missing": [
- "Identificatore del modulo mancante"
+ "Reusable templates configured by the exchange operator": [
+ ""
],
- "The collected information does not identify the form used to create it.": [
- "Le informazioni raccolte non identificano il modulo utilizzato per crearle."
+ "Use as template": [
+ ""
],
- "Form not available": [
- "Modulo non disponibile"
+ "Selected measures begin immediately after the decision is accepted by the exchange.": [
+ ""
],
- "Form %1$s is not configured in this AML Web UI.": [
- "Il modulo %1$s non è configurato in questa interfaccia web AML."
+ "Session not found. Contact the administrator.": [
+ ""
],
- "The account was not found.": [
- "L’account non è stato trovato."
+ "The exchange rejected the decision because the officer session is disabled or the account has a newer decision. Reload the account before trying again.": [
+ ""
],
- "The account state changed. Reload it and try again.": [
- "Lo stato dell’account è cambiato. Ricaricalo e riprova."
+ "This decision records that an MROS report was filed. Confirm that the report has actually been submitted before continuing.": [
+ ""
],
- "The payto URI does not belong to this account. Return to the account search and start the decision again.": [
- "L’URI payto non appartiene a questo account. Torna alla ricerca degli account e avvia nuovamente la decisione."
+ "Confirm decision": [
+ "Conferma decisione"
],
- "This account has no active decision and its payto URI is unknown. Start the decision from the account search so the account type can be determined safely.": [
- "Questo account non ha una decisione attiva e il suo URI payto è sconosciuto. Avvia la decisione dalla ricerca degli account affinché il tipo di account possa essere determinato in modo sicuro."
+ "Unknown measure": [
+ "Misura sconosciuta"
],
- "Return to account": [
- "Torna all’account"
+ "A rule or immediate action references a measure that is not available. Review the rules and measures before submitting.": [
+ "Una regola o un’azione immediata fa riferimento a una misura non disponibile. Verifica le regole e le misure prima dell’invio."
],
- "threshold\u0004%1$s every %2$s": [
- "%1$s ogni %2$s"
+ "A custom measure references an unavailable check or program, lacks required context, or cannot provide the selected program inputs. Review the immediate measures before submitting.": [
+ ""
],
- "operation type\u0004Withdraw": [
- "Prelievo"
+ "Missing deadline": [
+ "Scadenza mancante"
],
- "operation type\u0004Deposit": [
- "Deposito"
+ "Set when the proposed rules expire and what should happen afterward.": [
+ ""
],
- "operation type\u0004Merge": [
- "Unione"
+ "Invalid rule expiration": [
+ "Scadenza delle regole non valida"
],
- "operation type\u0004Aggregate": [
- "Aggregazione"
+ "Rule expiration must be in the future or set to Never.": [
+ "La scadenza delle regole deve essere futura oppure impostata su «Mai»."
],
- "operation type\u0004Balance": [
- "Saldo"
+ "Missing rules": [
+ "Regole mancanti"
],
- "operation type\u0004Refund": [
- "Rimborso"
+ "A decision must contain the complete rule set that will apply to the account.": [
+ ""
],
- "operation type\u0004Close": [
- "Chiusura"
+ "Review the proposed rules. Hard blocks must be explicit, and Balance and Refund rules must use an instant timeframe.": [
+ "Controlla le regole proposte. I blocchi rigidi devono essere espliciti e le regole per saldo e rimborso devono usare un intervallo istantaneo."
],
- "operation type\u0004Transaction": [
- "Transazione"
- ]
- }
- },
- "domain": "messages",
- "plural_forms": "",
- "lang": "it",
- "completeness": 89
-};
-
-strings['fr'] = {
- "locale_data": {
- "messages": {
- "": {
- "domain": "messages",
- "lang": "fr",
- "plural_forms": ""
- },
- "Use testing dialect": [
- "Utiliser le dialecte de test"
+ "Immediate measures not reviewed": [
+ ""
],
- "Allow Insecure password": [
- "Autoriser un mot de passe non sécurisé"
+ "No measure will start when this decision is submitted.": [
+ ""
],
- "Keep session after reload": [
- "Conserver la session après rechargement"
+ "Review the account properties before submitting the decision.": [
+ ""
],
- "Don't compress request": [
- "Ne pas compresser la requête"
+ "Reporting events not reviewed": [
+ ""
],
- "Preferences": [
- "Préférences"
+ "Review which statistical events will be recorded with the decision.": [
+ ""
],
- "Password": [
- "Mot de passe"
+ "Case disposition incomplete": [
+ ""
],
- "Required": [
- "Requis"
+ "You must complete the justification section.": [
+ "Devi completare la sezione della giustificazione."
],
- "should have at least 12 characters": [
- "doit comporter au moins 12 caractères"
+ "Invalid attributes": [
+ "Attributi non validi"
],
- "should have lowercase and uppercase characters": [
- "doit comporter des minuscules et des majuscules"
+ "Correct the selected form or continue without attaching new customer information.": [
+ ""
],
- "should have numbers": [
- "doit comporter des chiffres"
+ "Justification": [
+ "Giustificazione"
],
- "should have at least one character which is not a number or letter": [
- "doit comporter au moins un caractère qui n'est ni un chiffre ni une lettre"
+ "Events": [
+ "Eventi"
],
- "Repeat password": [
- "Répéter le mot de passe"
+ "All entries made in this decision wizard will be lost. No change will be submitted to the exchange.": [
+ ""
],
- "doesn't match": [
- "ne correspond pas"
+ "Payto URI": [
+ "URI Payto"
],
- "Create": [
- "Créer"
+ "Decision steps": [
+ ""
],
- "Failed to unlock the session.": [
+ "Account properties": [
+ "Proprietà del conto"
+ ],
+ "Review the account state derived from the available information.": [
""
],
- "Authorization denied for this session. Contact the administrator.": [
+ "Review the statistical events recorded with this decision.": [
""
],
- "Unlock": [
- "Déverrouiller"
+ "Set operation thresholds, escalation measures, and expiration behavior.": [
+ ""
],
- "There are no rules for operations": [
- "Il n'y a aucune règle pour les opérations"
+ "Case disposition": [
+ ""
],
- "Add custom rule": [
- "Ajouter une règle personnalisée"
+ "Check the complete decision before signing and submitting it.": [
+ ""
],
- "Operation": [
- "Opération"
+ "Enter a valid HTTP or HTTPS URL.": [
+ ""
],
- "Threshold": [
- "Seuil"
+ "Development settings": [
+ "Impostazioni di sviluppo"
],
- "Escalation": [
- "Escalade"
+ "These browser-local settings are intended for development and troubleshooting.": [
+ ""
],
- "%1$s": [
- "%1$s"
+ "Changing the exchange reloads the application. The override is stored only in this browser.": [
+ ""
],
- "(all)": [
- "(tous)"
+ "Exchange base URL": [
+ "URL di base dell’exchange"
],
- "Since": [
- "Depuis"
+ "Leave empty to use the configured URL: %1$s": [
+ ""
],
- "Expired": [
- "Expiré"
+ "Leave empty to derive the exchange URL from this page.": [
+ ""
],
- "Expires": [
- "Expire"
+ "Currently connected to": [
+ ""
],
- "Successor measure": [
- "Mesure suivante"
+ "Apply and reload": [
+ ""
],
- "AML officer justification": [
- "Justification de l'agent AML"
+ "Use configured URL": [
+ ""
],
- "Default rules": [
- "Règles par défaut"
+ "Preferences": [
+ "Preferenze"
],
- "Forms": [
- "Formulaires"
+ "AML SPA dialect": [
+ ""
],
- "Name": [
- "Nom"
+ "Testing": [
+ ""
],
- "Check": [
- "Vérifier"
+ "Override how this web interface presents dialect-specific AML rules and properties. The override is stored only in this browser.": [
+ ""
],
- "Program": [
- "Programme"
+ "Fallback dialect for development and testing.": [
+ ""
],
- "Context": [
- "Contexte"
+ "TOPS": [
+ ""
],
- "Modify": [
- "Modifier"
+ "Taler Operations deployment for Swiss AML processes.": [
+ ""
],
- "Info": [
- "Info"
+ "File note": [
+ "Nota del fascicolo"
],
- "Will show information to the user.": [
- "Affichera des informations à l'utilisateur."
+ "Text": [
+ ""
],
- "Instant measures": [
- "Mesures instantanées"
+ "Customer label": [
+ "Etichetta del cliente"
],
- "Triggered immediately without customer interaction.": [
- "Déclenchées immédiatement sans interaction du client."
+ "Account open": [
+ "Conto aperto"
],
- "Input requirement": [
- "Exigence de saisie"
+ "Domestic PEP": [
+ "PEP nazionale"
],
- "Already completed.": [
- "Déjà complété."
+ "Whether the customer is a domestic politically exposed person.": [
+ ""
],
- "Waiting to be completed.": [
- "En attente d'être complété."
+ "Foreign PEP": [
+ "PEP estera"
],
- "Current active rules": [
- "Règles actives actuelles"
+ "Whether the customer is a foreign politically exposed person.": [
+ ""
],
- "There are no rules for this account yet.": [
- "Il n'y a pas encore de règles pour ce compte."
+ "International-organization PEP": [
+ "PEP di un’organizzazione internazionale"
],
- "New rule form": [
- "Nouveau formulaire de règle"
+ "Whether the customer is a politically exposed person associated with an international organization.": [
+ ""
],
- "Add": [
- "Ajouter"
+ "High-risk customer": [
+ "Cliente ad alto rischio"
],
- "Cancel": [
- "Annuler"
+ "High-risk country": [
+ "Paese ad alto rischio"
],
- "Basic plan": [
- "Forfait de base"
+ "Whether the customer is associated with a high-risk country.": [
+ ""
],
- "Premium": [
- "Premium"
+ "Account idle": [
+ "Conto inattivo"
],
- "E-commerce": [
- "Commerce électronique"
+ "Whether the account has been marked as idle.": [
+ ""
],
- "Point of Sale": [
- "Point de vente"
+ "Score from 0 (no match) to 1,000,000,000 (best match).": [
+ ""
],
- "Check rules": [
- "Vérifier les règles"
+ "Score from 0 (no supporting data) to 1,000,000,000 (highest confidence).": [
+ ""
],
- "The account is a wallet and there are bank account operation's limits which may trigger actions that are not required: %1$s": [
- "Le compte est un portefeuille numérique et il existe des limites d'opérations de compte bancaire susceptibles de déclencher des actions non requises : %1$s"
+ "Whether this account's sanction-list hit is treated as a false positive.": [
+ ""
],
- "The account isn't a wallet and there are wallet operation's limits which may trigger actions that are not required: %1$s": [
- "Le compte n'est pas un portefeuille numérique et il existe des limites d'opérations de portefeuille susceptibles de déclencher des actions non requises : %1$s"
+ "Recorded when an account changes to open.": [
+ ""
],
- "The account is a wallet and there are wallet operation's limits which are not limited: %1$s": [
- "Le compte est un portefeuille numérique et il existe des limites d'opérations de portefeuille qui ne sont pas limitées : %1$s"
+ "Recorded when an account changes from open to closed.": [
+ ""
],
- "New rules": [
- "Nouvelles règles"
+ "Recorded when an open account becomes classified as a high-risk customer.": [
+ ""
],
- "Reset rules to current state": [
- "Réinitialiser les règles à l'état actuel"
+ "Recorded when the high-risk customer classification is removed.": [
+ ""
],
- "Set rules to default": [
- "Rétablir les règles par défaut"
+ "Recorded when an open account becomes associated with a high-risk country.": [
+ ""
],
- "Freeze account": [
- "Geler le compte"
+ "High-risk country classification removed": [
+ ""
],
- "Behavior on rule expiration": [
- "Comportement à l'expiration de la règle"
+ "Recorded when the high-risk country classification is removed.": [
+ ""
],
- "Reset measure": [
- "Réinitialiser la mesure"
+ "PEP classification added": [
+ ""
],
- "Reset expiration": [
- "Réinitialiser l'expiration"
+ "Recorded when an open account becomes associated with any PEP category.": [
+ ""
],
- "Operation type": [
- "Type d'opération"
+ "Recorded when the account is no longer associated with any PEP category.": [
+ ""
],
- "Timeframe": [
- "Période"
+ "Foreign PEP classification added": [
+ ""
],
- "Exposed": [
- "Exposé"
+ "Recorded when an open account becomes associated with a foreign PEP.": [
+ ""
],
- "Is this limit communicated to the customer?": [
- "Cette limite est-elle communiquée au client ?"
+ "Foreign PEP classification removed": [
+ ""
],
- "Escalation measure": [
- "Mesure d'escalade"
+ "Recorded when the foreign PEP classification is removed.": [
+ ""
],
- "Measures that the customer will need to satisfy to apply for a new threshold.": [
- "Mesures que le client devra satisfaire pour demander un nouveau seuil."
+ "Domestic PEP classification added": [
+ ""
],
- "All measures": [
- "Toutes les mesures"
+ "Recorded when an open account becomes associated with a domestic PEP.": [
+ ""
],
- "Hint the customer that all measures should be completed": [
- "Indiquer au client que toutes les mesures doivent être complétées"
+ "Domestic PEP classification removed": [
+ ""
],
- "Expiration": [
- "Expiration"
+ "Recorded when the domestic PEP classification is removed.": [
+ ""
],
- "Predefined shortcuts": [
- "Raccourcis prédéfinis"
+ "Recorded when the international-organization PEP classification is removed.": [
+ ""
],
- "In a week": [
- "Dans une semaine"
+ "Simple suspicion reported to MROS": [
+ ""
],
- "In a month": [
- "Dans un mois"
+ "Recorded when a report is filed under Article 305ter paragraph 2 StGB.": [
+ ""
],
- "In a year": [
- "Dans un an"
+ "Recorded when a report is filed under Article 9 GwG.": [
+ ""
],
- "Never": [
- "Jamais"
+ "Recorded when a pending special clarification is concluded.": [
+ ""
],
- "Expiration date": [
- "Date d'expiration"
+ "Recorded when a previously concluded investigation returns to a non-concluded state.": [
+ ""
],
- "Until when are the new rules active.": [
- "Jusqu'à quand les nouvelles règles sont actives."
+ "Browser override": [
+ ""
],
- "Measure taken automatically upon expiration of the current decision.": [
- "Mesure prise automatiquement à l'expiration de la décision actuelle."
+ "Exchange identity, the active AML dialect, and the checks and programs available to AML decisions.": [
+ ""
],
- "Failed to load account information.": [
+ "Public information reported by this exchange.": [
""
],
- "Failed to load decision history.": [
+ "Base URL": [
""
],
- "Failed to load current legitimizations.": [
+ "Protocol": [
""
],
- "New decision": [
- "Nouvelle décision"
+ "Protocol version": [
+ ""
],
- "Show transfers": [
- "Afficher les transferts"
+ "Currency": [
+ ""
],
- "Failed to download report.": [
+ "AML dialect": [
""
],
- "Session not found. Contact the administrator.": [
+ "Canonical properties defined by the effective dialect.": [
""
],
- "The session is disabled. Contact the administrator.": [
+ "This dialect does not define derived events.": [
""
],
- "The server doesn't support PDF download. Contact the administrator.": [
+ "Checks, programs, root measures, and default rules reported by the exchange.": [
""
],
- "Case history for selected account": [
- "Historique des dossiers pour le compte sélectionné"
+ "%1$s entries": [
+ ""
],
- "ID:": [
- "ID :"
+ "No root measures are configured.": [
+ ""
],
- "Payto:": [
- "Payto :"
+ "No KYC checks are configured.": [
+ ""
],
- "Export as PDF": [
- "Exporter en PDF"
+ "No AML programs are configured.": [
+ ""
],
- "Export completed": [
- "Exportation terminée"
+ "No default AML rules are configured.": [
+ ""
],
- "Click here to save the file in your computer.": [
- "Cliquez ici pour enregistrer le fichier sur votre ordinateur."
+ "Built-in check that proceeds without collecting customer data.": [
+ ""
],
- "Under investigation": [
- "Sous enquête"
+ "Voluntary": [
+ ""
],
- "This account requires a manual review and is waiting for a decision to be made.": [
- "Ce compte nécessite un examen manuel et est en attente d'une décision."
+ "Session and access": [
+ "Sessione e accesso"
],
- "Collected information": [
- "Informations collectées"
+ "Review this officer's exchange access and manage the unlocked key in this browser.": [
+ "Controlla l’accesso di questo operatore all’exchange e gestisci la chiave sbloccata in questo browser."
],
- "Every attribute collection event (via form upload or KYC provider).": [
- "Chaque événement de collecte d'attributs (via téléversement de formulaire ou prestataire KYC)."
+ "Officer access": [
+ "Accesso dell’operatore"
],
- "No collected attributes for this account.": [
- "Aucun attribut collecté pour ce compte."
+ "Officer name": [
+ "Nome dell’operatore"
],
- "Current account properties": [
- "Propriétés actuelles du compte"
+ "Permissions": [
+ "Autorizzazioni"
],
- "No active decision found": [
- "Aucune décision active trouvée"
+ "Read-only": [
+ "Sola lettura"
],
- "There is no decision for this account yet. The account is limited by the default rules.": [
- "Aucune décision n'a encore été prise pour ce compte. Le compte est limité par les règles par défaut."
+ "Read and write": [
+ "Lettura e scrittura"
],
- "Previous AML decisions": [
- "Décisions AML précédentes"
+ "Session security": [
+ "Sicurezza della sessione"
],
- "No AML history found": [
- "Aucun historique AML trouvé"
+ "Lock the session when you leave this device unattended.": [
+ "Blocca la sessione quando lasci questo dispositivo incustodito."
],
- "Current active measures": [
- "Mesures actives actuelles"
+ "Lock now": [
+ "Blocca ora"
],
- "Now": [
- "Maintenant"
+ "Unlocked": [
+ "Sbloccata"
],
- "Lock session": [
- ""
+ "Locks automatically": [
+ "Blocco automatico"
],
- "Failed to load accounts": [
- ""
+ "Exact time": [
+ "Ora esatta"
],
- "High risk accounts. Only with custom rules.": [
- "Comptes à haut risque. Uniquement avec des règles personnalisées."
+ "Officer public key": [
+ "Chiave pubblica dell’operatore"
],
- "Account with custom rules.": [
- "Compte avec des règles personnalisées."
+ "Copy public key": [
+ "Copia chiave pubblica"
],
- "High risk accounts": [
- "Comptes à haut risque"
+ "Remove key from this browser": [
+ "Rimuovi la chiave da questo browser"
],
- "All known accounts.": [
- "Tous les comptes connus."
+ "Removing this key deletes the officer key from this browser. It does not revoke or change the officer's access at the exchange. Ask the exchange operator to revoke access if needed.": [
+ "La rimozione di questa chiave elimina la chiave dell’operatore da questo browser. Non revoca né modifica l’accesso dell’operatore all’exchange. Se necessario, chiedi all’operatore dell’exchange di revocare l’accesso."
],
- "High risk accounts under investigation. Only with custom rules.": [
- "Comptes à haut risque sous enquête. Uniquement avec des règles personnalisées."
+ "Remove key": [
+ "Rimuovi chiave"
],
- "Accounts under investigation. Only with custom rules.": [
- "Comptes sous enquête. Uniquement avec des règles personnalisées."
+ "Remove officer key?": [
+ "Rimuovere la chiave dell’operatore?"
],
- "High risk accounts under investigation.": [
- "Comptes à haut risque sous enquête."
+ "This deletes the officer key from this browser. You will need to create and enroll a new key to use the AML WebUI here again.": [
+ "Questa operazione elimina la chiave dell’operatore da questo browser. Dovrai creare e far registrare una nuova chiave per utilizzare nuovamente qui l’interfaccia web AML."
],
- "Accounts under investigation.": [
- "Comptes sous enquête."
+ "This does not revoke the officer at the exchange. Ask the exchange operator to revoke its access if the key may be compromised.": [
+ "Questa operazione non revoca l’operatore presso l’exchange. Chiedi all’operatore dell’exchange di revocarne l’accesso se la chiave potrebbe essere compromessa."
],
- "High risk accounts without investigation. Only with custom rules.": [
- "Comptes à haut risque sans enquête. Uniquement avec des règles personnalisées."
+ "Find account": [
+ "Trova conto"
],
- "Accounts without investigation. Only with custom rules.": [
- "Comptes sans enquête. Uniquement avec des règles personnalisées."
+ "Look up an account by its payto information or normalized payto hash.": [
+ "Cerca un conto usando le informazioni payto o l’hash payto normalizzato."
],
- "High risk accounts without investigation.": [
- "Comptes à haut risque sans enquête."
+ "Find by payto": [
+ "Cerca per payto"
],
- "Accounts without investigation.": [
- "Comptes sans enquête."
+ "Find by normalized payto hash": [
+ "Trova per hash payto normalizzato"
],
- "Failed to download": [
- ""
+ "Enter a valid 52-character normalized payto hash.": [
+ "Inserisci un hash payto normalizzato valido di 52 caratteri."
],
- "The format requested is not acceptable from the service provider.": [
- ""
+ "Open account": [
+ "Apri conto"
],
- "Authorization denied for this session.": [
- ""
+ "Failed to load account decisions.": [
+ "Impossibile caricare le decisioni del conto."
],
- "The session is disabled. Contact the administrator": [
- ""
+ "Failed to load the account history.": [
+ "Impossibile caricare la cronologia del conto."
],
- "Accounts": [
- "Comptes"
+ "This session signature is invalid, contact administrator or create a new one.": [
+ "La firma di questa sessione non è valida. Contatta l’amministratore o crea una nuova sessione."
],
- "Export as file": [
- "Exporter sous forme de fichier"
+ "The designated AML session is not known, contact administrator or create a new one.": [
+ "La sessione AML indicata non è nota. Contatta l’amministratore o creane una nuova."
],
- "No results": [
- "Aucun résultat"
+ "The designated AML session is not enabled, contact administrator or create a new one.": [
+ "La sessione AML indicata non è abilitata. Contatta l’amministratore o creane una nuova."
],
- "#": [
- "#"
+ "This account has an AML decision history. Open its case to review current rules, measures, attributes, and past decisions.": [
+ ""
],
- "Account Identification": [
- "Identification du compte"
+ "Active": [
+ ""
],
- "Open time": [
- "Heure d'ouverture"
+ "Account not found": [
+ "Conto non trovato"
],
- "Status": [
- "Statut"
+ "There is no history known for this account yet.": [
+ "Non è ancora nota alcuna cronologia per questo conto."
],
- "From %1$s %2$s To %3$s": [
- "De %1$s %2$s à %3$s"
+ "Search": [
+ "Cerca"
],
- "Since %1$s": [
- "Depuis %1$s"
+ "Taler Bank": [
+ "Taler Bank"
],
- "Not opened": [
- "Non ouvert"
+ "Wallet": [
+ "Portafoglio"
],
- "High risk": [
- "Haut risque"
+ "Generic Payto:// URI": [
+ "URI Payto:// generico"
],
- "With custom rules": [
- "Avec des règles personnalisées"
+ "Account type": [
+ "Tipo di conto"
],
- "Invalid account": [
- "Compte invalide"
+ "Should be 52 characters.": [
+ "Deve essere di 52 caratteri."
],
- "Search by ID": [
- "Rechercher par ID"
+ "Failed to parse: %1$s": [
+ "Impossibile analizzare: %1$s"
],
- "Under investigation: ": [
- "Sous enquête : "
+ "Address contains invalid characters.": [
+ "L'indirizzo contiene caratteri non validi."
],
- "High risk:": [
- "Haut risque :"
+ "Can't mix uppercased and lowercased characters.": [
+ "Impossibile combinare caratteri maiuscoli e minuscoli."
],
- "Custom rules:": [
- "Règles personnalisées :"
+ "The addr checksum doesn't match.": [
+ "Il checksum dell'indirizzo non corrisponde."
],
- "Dashboard": [
- "Tableau de bord"
+ "Missing separator or address type.": [
+ "Separatore o tipo di indirizzo mancante."
],
- "Failed to load TOPS statistics.": [
- ""
+ "Address should have less than 90 characters.": [
+ "L'indirizzo deve avere meno di 90 caratteri."
],
- "Statistics": [
- "Statistiques"
+ "Address should have more than 6 characters.": [
+ "L'indirizzo deve avere più di 6 caratteri."
],
- "Accounts open": [
- "Comptes ouverts"
+ "Decoding issue.": [
+ "Problema di decodifica."
],
- "New files last year": [
- "Nouveaux dossiers l'année dernière"
+ "Invalid data": [
+ "Dati non validi"
],
- "Closed files last year": [
- "Dossiers fermés l'année dernière"
+ "Unsupported country.": [
+ "Paese non supportato."
],
- "MROS substantiated": [
- "MROS motivés"
+ "IBANs have fewer than 34 characters.": [
+ "Gli IBAN hanno meno di 34 caratteri."
],
- "MROS simple": [
- "MROS simples"
+ "IBANs have more than 4 characters.": [
+ "Gli IBAN hanno più di 4 caratteri."
],
- "High risk files": [
- "Dossiers à haut risque"
+ "IBAN length is invalid for this country.": [
+ "La lunghezza dell'IBAN non è valida per questo paese."
],
- "PEP files": [
- "Dossiers PPE"
+ "It should only contain numbers and letters.": [
+ "Deve contenere solo numeri e lettere."
],
- "Number of accounts that are opened": [
- "Nombre de comptes ouverts"
+ "The checksum is wrong.": [
+ "Il checksum è errato."
],
- "Number of new GwG files in the last year": [
- "Nombre de nouveaux dossiers GwG au cours de la dernière année"
+ "The string should start with payto://": [
+ "La stringa deve iniziare con payto://"
],
- "Number of GwG files closed in the last year": [
- "Nombre de dossiers GwG fermés au cours de la dernière année"
+ "After the target type it should follow a '/' with more information.": [
+ "Dopo il tipo di destinazione deve seguire un '/' con ulteriori informazioni."
],
- "Number of MROS reports based on Art 9 Abs. 1 GwG (per year)": [
- "Nombre de déclarations MROS fondées sur l'art. 9 al. 1 GwG (par an)"
+ "The target type is not supported, only x-taler-bank, taler-reserve or iban": [
+ "Il tipo di destinazione non è supportato, solo x-taler-bank, taler-reserve o iban"
],
- "Number of MROS reports based on Art 305ter Abs. 2 StGB (per year)": [
- "Nombre de déclarations MROS fondées sur l'art. 305ter al. 2 StGB (par an)"
+ "IBAN is missing": [
+ "L'IBAN è mancante"
],
- "Number of GwG files of high-risk customers": [
- "Nombre de dossiers GwG de clients à haut risque"
+ "Bitcoin address is missing": [
+ "L'indirizzo Bitcoin è mancante"
],
- "Number of GwG files managed with “increased risk” due to PEP status": [
- "Nombre de dossiers GwG gérés avec un « risque accru » en raison du statut de PPE"
+ "Bank host and account is missing": [
+ "L'host della banca e il conto sono mancanti"
],
- "previous": [
- "précédent"
+ "Exchange host and account is missing": [
+ "L'host dell'Exchange e il conto sono mancanti"
],
- "Decreased by": [
- "Diminué de"
+ "Ethereum address is missing": [
+ "L'indirizzo Ethereum è mancante"
],
- "Increased by": [
- "Augmenté de"
+ "Cyclos address is missing": [
+ "L'indirizzo Cyclos è mancante"
],
- "Events": [
- "Événements"
+ "Void address is missing": [
+ "Manca l’indirizzo void"
],
- "The events will be triggered only after the decision has been confirmed.": [
- "Les événements ne seront déclenchés qu'après la confirmation de la décision."
+ "Invalid IBAN: %1$s": [
+ "IBAN non valido: %1$s"
],
- "Calculated": [
- "Calculé"
+ "Invalid BTC: %1$s": [
+ "BTC non valido: %1$s"
],
- "Events based on properties and new attributes that should be triggered": [
- "Événements basés sur des propriétés et de nouveaux attributs qui doivent être déclenchés"
+ "Invalid reserve: %1$s": [
+ "Riserva non valida: %1$s"
],
- "Others": [
- "Autres"
+ "Invalid host": [
+ "Host non valido"
],
- "Events that can be triggered manually": [
- "Événements pouvant être déclenchés manuellement"
+ "Invalid account": [
+ "Conto non valido"
],
- "Custom list": [
- "Liste personnalisée"
+ "Invalid address": [
+ "Indirizzo non valido"
],
- "Events without built-in support.": [
- "Événements sans prise en charge intégrée."
+ "As defined by RFC 8905": [
+ "Come definito dalla RFC 8905"
],
- "Complete the form": [
- "Compléter le formulaire"
+ "payto://": [
+ "payto://"
],
- "These measures will ask the customer for information.": [
- "Ces mesures demanderont des informations au client."
+ "International Bank Account Number": [
+ "Numero di conto bancario internazionale"
],
- "change form": [
- "modifier le formulaire"
+ "DE1231231231": [
+ "DE1231231231"
],
- "Expiration date of the information filled in this form.": [
- "Date d'expiration des informations saisies dans ce formulaire."
+ "Host": [
+ "Host"
],
- "Include new information": [
- "Inclure de nouvelles informations"
+ "Exchange hostname": [
+ "Hostname dell'Exchange"
],
- "Select a form to submit new information about the customer or continue to the next step": [
- "Sélectionnez un formulaire pour soumettre de nouvelles informations sur le client ou passez à l'étape suivante"
+ "exchange.taler.net": [
+ "exchange.taler.net"
],
- "Form:": [
- "Formulaire :"
+ "Remove last '/'": [
+ "Rimuovi l'ultimo '/'"
],
- "Justification": [
- "Justification"
+ "Invalid value": [
+ "Valore non valido"
],
- "Keep investigation?": [
- "Conserver l'enquête ?"
+ "ID": [
+ "ID"
],
- "Account holder": [
- "Titulaire du compte"
+ "Wallet reserve public key": [
+ "Chiave pubblica di riserva del portafoglio"
],
- "Full name of the account holder": [
- "Nom complet du titulaire du compte"
+ "abcdef1235": [
+ "abcdef1235"
],
- "loading...": [
- "chargement..."
+ "Should be 52 characters": [
+ "Deve essere di 52 caratteri"
],
- "Update": [
- "Modifier"
+ "Bank account identification": [
+ "Identificazione del conto bancario"
],
- "Remove": [
- "Supprimer"
+ "DE123123123": [
+ "DE123123123"
],
- "Configure verification type: %1$s": [
- "Configurer le type de vérification : %1$s"
+ "Hostname": [
+ "Hostname"
],
- "Show complete form": [
- "Afficher le formulaire complet"
+ "Without the scheme, may include subpath: bank.com, bank.com/path/": [
+ "Senza lo schema, può includere un sottopercorso: bank.com, bank.com/path/"
],
- "Configure measure": [
- "Configurer la mesure"
+ "bank.demo.taler.net": [
+ "bank.demo.taler.net"
],
- "Show as verification": [
- "Afficher comme vérification"
+ "Invalid hostname": [
+ "Hostname non valido"
],
- "There is already a measure with that name": [
- "Il existe déjà une mesure portant ce nom"
+ "Failed to load account information.": [
+ "Impossibile caricare le informazioni del conto."
],
- "Only required when no check is specified": [
- "Requis uniquement lorsqu'aucune vérification n'est spécifiée"
+ "Failed to load the account information.": [
+ ""
],
- "Missing check or program": [
- "Vérification ou programme manquant"
+ "Collection event not found": [
+ "Evento di raccolta non trovato"
],
- "Without a check the program will run automatically": [
- "Sans vérification, le programme s'exécutera automatiquement"
+ "There is no collection event with ID %1$s for this account.": [
+ "Non esiste alcun evento di raccolta con ID %1$s per questo account."
],
- "Field name": [
- "Nom du champ"
+ "Attributes unavailable": [
+ "Attributi non disponibili"
],
- "Type": [
- "Type"
+ "The collection event does not contain readable attributes.": [
+ "L’evento di raccolta non contiene attributi leggibili."
],
- "string": [
- "chaîne"
+ "Form identifier missing": [
+ "Identificatore del modulo mancante"
],
- "number": [
- "nombre"
+ "The collected information does not identify the form used to create it.": [
+ "Le informazioni raccolte non identificano il modulo utilizzato per crearle."
],
- "boolean": [
- "booléen"
+ "Form not available": [
+ "Modulo non disponibile"
],
- "json": [
- "json"
+ "Form %1$s is not configured in this AML Web UI.": [
+ "Il modulo %1$s non è configurato in questa interfaccia web AML."
],
- "Value": [
- "Valeur"
+ "Source": [
+ ""
],
- "There are unsatisfied inputs: %1$s": [
- "Il y a des entrées non satisfaites : %1$s"
+ "Different form version": [
+ "Versione del modulo differente"
],
- "There are missing inputs: %1$s": [
- "Il manque des entrées : %1$s"
+ "The collected information does not identify the form version used. The latest configured version is shown and field labels may differ from those used at collection time.": [
+ ""
],
- "There are missing requirements: %1$s": [
- "Il manque des exigences : %1$s"
+ "JSON view": [
+ ""
],
- "Can't be empty": [
- "Ne peut pas être vide"
+ "Incoming": [
+ ""
],
- "It should be a number": [
- "Cela doit être un nombre"
+ "Outgoing": [
+ ""
],
- "Not a number": [
- "Pas un nombre"
+ "KYC authorization": [
+ ""
],
- "It should be finite": [
- "Cela doit être fini"
+ "Wallet credits (P2P)": [
+ ""
],
- "It should be a safe integer": [
- "Cela doit être un entier sûr"
+ "Minimum amount": [
+ "Importo minimo"
],
- "It should be either \"true\" or \"false\"": [
- "Cela doit être soit « true » soit « false »"
+ "All amounts below the given threshold will be filtered.": [
+ "Tutti gli importi inferiori alla soglia indicata verranno filtrati."
],
- "Couldn't parse as json string: %1$s": [
- "Impossible d'analyser comme chaîne json : %1$s"
+ "Inspect successful P2P credits received by this wallet. Requests that were not paid are not shown.": [
+ ""
],
- "Description": [
- "Description"
+ "Inspect effective bank transfers observed by the exchange. Credit transfers are incoming, debit transfers are outgoing, and bounced or drain transfers are not included.": [
+ ""
],
- "Inputs": [
- "Entrées"
+ "Inspect effective transfers observed by the exchange. Incoming, outgoing, and KYC authorization entries are bank transfers. Wallet credits are successful P2P transfers into wallets.": [
+ ""
],
- "Output": [
- "Sortie"
+ "Failed to load the transfer list.": [
+ ""
],
- "Requires": [
- "Nécessite"
+ "Select transaction type": [
+ "Seleziona il tipo di transazione"
],
- "Fallback": [
- "Repli"
+ "Please select a transaction type to show transactions.": [
+ "Seleziona un tipo di transazione per mostrare le transazioni."
],
- "Name of the verification measure": [
- "Nom de la mesure de vérification"
+ "No transfers yet.": [
+ "Nessun trasferimento ancora."
],
- "Read only": [
- "Lecture seule"
+ "There are no transfers for this account.": [
+ "Non ci sono trasferimenti per questo conto."
],
- "Prevent the customer from changing the address": [
- "Empêcher le client de modifier l'adresse"
+ "There are no transfers reported to the exchange with the current threshold.": [
+ "Non ci sono trasferimenti segnalati all'Exchange con la soglia attuale."
],
- "Configure verification measure: \"%1$s\"": [
- "Configurer la mesure de vérification : « %1$s »"
+ "Unknown date": [
+ ""
],
- "Add custom measure": [
- "Ajouter une mesure personnalisée"
+ "Time": [
+ ""
],
- "Custom measures": [
- "Mesures personnalisées"
+ "Amount": [
+ "Importo"
],
- "Server measures": [
- "Mesures serveur"
+ "Unknown time": [
+ ""
],
- "New measures": [
- "Nouvelles mesures"
+ "sent": [
+ "inviato"
],
- "Measures that are available/executed directly after the decision is confirmed.": [
- "Mesures disponibles/exécutées directement après la confirmation de la décision."
+ "received": [
+ "ricevuto"
],
- "Reset to default": [
- "Réinitialiser par défaut"
+ "to": [
+ "a"
],
- "Properties": [
- "Propriétés"
+ "from": [
+ "da"
],
- "Custom properties": [
- "Propriétés personnalisées"
+ "This exchange is not compatible with the AML WebUI.": [
+ "Questo exchange non è compatibile con l’interfaccia web AML."
],
- "Add more properties that are not listed above.": [
- "Ajoutez d'autres propriétés qui ne sont pas listées ci-dessus."
+ "Officer identity and permissions require exchange protocol v40 or newer.": [
+ "L’identità e i permessi dell’operatore richiedono il protocollo exchange v40 o successivo."
],
- "New properties": [
- "Nouvelles propriétés"
+ "Verifying that this public key is enrolled by the exchange.": [
+ "Verifica che questa chiave pubblica sia registrata presso l’exchange."
],
- "Current note on the GwG file": [
- "Note actuelle sur le dossier GwG"
+ "Read-only officer access": [
+ "Accesso operatore in sola lettura"
],
- "Customer name or internal alias.": [
- "Nom du client ou alias interne."
+ "You can review AML information, but this officer key cannot submit decisions.": [
+ "Puoi consultare le informazioni AML, ma questa chiave dell’operatore non può inviare decisioni."
],
- "Is the account active for deposit and payments?": [
- "Le compte est-il actif pour les dépôts et les paiements ?"
+ "This officer key cannot create or submit AML decisions.": [
+ "Questa chiave dell’operatore non può creare né inviare decisioni AML."
],
- "Is the account idle?": [
- "Le compte est-il inactif ?"
+ "Return to account": [
+ "Torna all’account"
],
- "No operation for a period of time": [
- "Aucune opération pendant une période donnée"
+ "Failed to load the active AML decision.": [
+ "Impossibile caricare la decisione AML attiva."
],
- "Does account belong to a domestic PEP?": [
- "Le compte appartient-il à une PPE nationale ?"
+ "The account was not found.": [
+ "L’account non è stato trovato."
],
- "Does account belong to a foreign PEP?": [
- "Le compte appartient-il à une PPE étrangère ?"
+ "The account state changed. Reload it and try again.": [
+ "Lo stato dell’account è cambiato. Ricaricalo e riprova."
],
- "Does account belong to an international-organization PEP?": [
- "Le compte appartient-il à une PPE d'organisation internationale ?"
+ "The payto URI does not belong to this account. Return to the account search and start the decision again.": [
+ "L’URI payto non appartiene a questo account. Torna alla ricerca degli account e avvia nuovamente la decisione."
],
- "Does account belong to a high risk customer?": [
- "Le compte appartient-il à un client à haut risque ?"
+ "Session": [
+ "Sessione"
],
- "Does account belong to a person from a high risk country?": [
- "Le compte appartient-il à une personne originaire d'un pays à haut risque ?"
+ "AML navigation": [
+ "Navigazione AML"
],
- "The MROS reporting state for the account.": [
- "L'état de déclaration MROS du compte."
+ "Measures": [
+ "Misure"
],
- "None": [
- "Aucun"
+ "threshold\u0004%1$s every %2$s": [
+ "%1$s ogni %2$s"
],
- "Pending investigation": [
- "Enquête en attente"
+ "operation type\u0004Withdraw": [
+ "Prelievo"
],
- "Investigated without suspicion": [
- "Enquêté sans soupçon"
+ "operation type\u0004Deposit": [
+ "Deposito"
],
- "Reported simple suspicion": [
- "Soupçon simple signalé"
+ "operation type\u0004Merge": [
+ "Unione"
],
- "Reported substantiated suspicion": [
- "Soupçon fondé signalé"
+ "operation type\u0004Aggregate": [
+ "Aggregazione"
],
- "Informal reason why the AML investigation was triggered": [
- "Raison informelle du déclenchement de l'enquête AML"
+ "operation type\u0004Balance": [
+ "Saldo"
],
- "Identifies the sanction list entry that the account matched against": [
- "Identifie l'entrée de la liste de sanctions à laquelle le compte correspond"
+ "operation type\u0004Refund": [
+ "Rimborso"
],
- "Best match, does not mean it was a good match.": [
- "Meilleure correspondance, ne signifie pas que c'était une bonne correspondance."
+ "operation type\u0004Close": [
+ "Chiusura"
],
- "Score for how good the sanction list match was": [
- "Score de la qualité de la correspondance avec la liste de sanctions"
+ "operation type\u0004Transaction": [
+ "Transazione"
+ ]
+ }
+ },
+ "domain": "messages",
+ "plural_forms": "",
+ "lang": "it",
+ "completeness": 60
+};
+
+strings['fr'] = {
+ "locale_data": {
+ "messages": {
+ "": {
+ "domain": "messages",
+ "lang": "fr",
+ "plural_forms": ""
+ },
+ "Allow Insecure password": [
+ "Autoriser un mot de passe non sécurisé"
],
- "Score for how much supporting data we had for the sanction list match": [
- "Score de la quantité de données justificatives disponibles pour la correspondance avec la liste de sanctions"
+ "Keep session after reload": [
+ "Conserver la session après rechargement"
],
- "Suppress flagging this account when it creates a hit on a sanctions list, this is a false-positive": [
- "Supprimer le signalement de ce compte lorsqu'il correspond à une liste de sanctions ; il s'agit d'un faux positif"
+ "Don't compress request": [
+ "Ne pas compresser la requête"
],
- "Confirmation required": [
- "Confirmation requise"
+ "Lock session": [
+ "Verrouiller la session"
],
- "I want to check first!": [
- "Je veux d'abord vérifier !"
+ "Lock": [
+ "Verrouiller"
],
- "Confirm decision": [
- "Confirmer la décision"
+ "Password": [
+ "Mot de passe"
],
- "Missing deadline": [
- "Échéance manquante"
+ "Required": [
+ "Requis"
],
- "Deadline should specify when this rules ends and what is the next measures to apply after expiration.": [
- "L'échéance doit préciser quand cette règle se termine et quelles sont les prochaines mesures à appliquer après expiration."
+ "should have at least 12 characters": [
+ "doit comporter au moins 12 caractères"
],
- "Missing rules": [
- "Règles manquantes"
+ "should have lowercase and uppercase characters": [
+ "doit comporter des minuscules et des majuscules"
],
- "Can't make a decision without rules.": [
- "Impossible de prendre une décision sans règles."
+ "should have numbers": [
+ "doit comporter des chiffres"
],
- "Missing active measure": [
- "Mesure active manquante"
+ "should have at least one character which is not a number or letter": [
+ "doit comporter au moins un caractère qui n'est ni un chiffre ni une lettre"
],
- "You should specify in the measure section.": [
- "Vous devez le préciser dans la section des mesures."
+ "Repeat password": [
+ "Répéter le mot de passe"
],
- "No customer action required.": [
- "Aucune action du client requise."
+ "doesn't match": [
+ "ne correspond pas"
],
- "No active measure has been selected.": [
- "Aucune mesure active n'a été sélectionnée."
+ "Create": [
+ "Créer"
],
- "Missing properties": [
- "Propriétés manquantes"
+ "Wallet account": [
+ "Compte de portefeuille"
],
- "You should specify in the properties section.": [
- "Vous devez le préciser dans la section des propriétés."
+ "Bank account": [
+ "Compte bancaire"
],
- "Missing events": [
- "Événements manquants"
+ "Under investigation": [
+ "Sous enquête"
],
- "You should specify in the events section.": [
- "Vous devez le préciser dans la section des événements."
+ "High risk": [
+ "Risque élevé"
],
- "Missing justification": [
- "Justification manquante"
+ "Payment target type": [
+ ""
],
- "You must complete the justification section.": [
- "Vous devez compléter la section de justification."
+ "Account holder": [
+ "Titulaire du compte"
],
- "Invalid attributes": [
- "Attributs invalides"
+ "IBAN": [
+ "IBAN"
],
- "You should check form errors or submit a decision without attributes.": [
- "Vous devez vérifier les erreurs du formulaire ou soumettre une décision sans attributs."
+ "BIC": [
+ ""
],
- "Clear": [
- "Effacer"
+ "Bank": [
+ ""
],
- "Send decision": [
- "Envoyer la décision"
+ "Account": [
+ "Compte"
],
- "Prev": [
- "Précédent"
+ "Taler bank": [
+ "Banque Taler"
],
- "Next": [
- "Suivant"
+ "Cyclos": [
+ ""
],
- "Attributes": [
- "Attributs"
+ "Bitcoin address": [
+ ""
],
- "Add more information about the customer": [
- "Ajouter des informations supplémentaires sur le client"
+ "Reserve public key": [
+ ""
],
- "Rules": [
- "Règles"
+ "Bitcoin": [
+ ""
],
- "Set the limit of the operations": [
- "Définir la limite des opérations"
+ "Ethereum address": [
+ ""
],
- "Trigger notifications.": [
- "Déclencher des notifications."
+ "Ethereum": [
+ ""
],
- "Measures": [
- "Mesures"
+ "Exchange": [
+ ""
],
- "Ask the customer to take action.": [
- "Demander au client de prendre une mesure."
+ "Taler reserve": [
+ "Réserve Taler"
],
- "Describe the decision.": [
- "Décrire la décision."
+ "Taler reserve (HTTP)": [
+ ""
],
- "Flag the current account state.": [
- "Signaler l'état actuel du compte."
+ "Test account": [
+ "Compte de test"
],
- "Summary": [
- "Résumé"
+ "Account details unavailable": [
+ ""
],
- "Review and submit.": [
- "Vérifier et soumettre."
+ "Not opened": [
+ "Non ouvert"
],
- "Decision for account:": [
- "Décision pour le compte :"
+ "Opened:": [
+ "Ouvert :"
],
- "Decision for wallet:": [
- "Décision pour le portefeuille :"
+ "Closed:": [
+ "Fermé :"
],
- "Decision for bank account:": [
- "Décision pour le compte bancaire :"
+ "Closed": [
+ "Fermé"
],
- "Search account": [
- "Rechercher un compte"
+ "Open": [
+ "Ouvert"
],
- "Failed to load account decisions.": [
- ""
+ "No note": [
+ "Aucune note"
],
- "Check account details": [
- "Vérifier les détails du compte"
+ "Show full note": [
+ "Afficher la note complète"
],
- "Account most recent decisions": [
- "Décisions les plus récentes du compte"
+ "System information": [
+ "Information système"
],
- "When": [
- "Quand"
+ "Transactions remain below the threshold that opens an AML file.": [
+ "Les transactions restent sous le seuil d’ouverture d’un dossier AML."
],
- "LATEST": [
- "DERNIÈRE"
+ "Account case": [
+ "Dossier du compte"
],
- "ACTIVE": [
- "ACTIVE"
+ "Failed to download AML file.": [
+ "Échec du téléchargement du dossier AML."
],
- "Account not found": [
- "Compte introuvable"
+ "No AML file is available for this account.": [
+ "Aucun dossier AML n’est disponible pour ce compte."
],
- "There is no history known for this account yet.": [
- "Aucun historique connu pour ce compte pour l'instant."
+ "Authorization denied for this session. Contact the administrator.": [
+ "Autorisation refusée pour cette session. Contactez l’administrateur."
],
- "You can make a decision for this account anyway.": [
- "Vous pouvez tout de même prendre une décision pour ce compte."
+ "The account or session was not found.": [
+ "Le compte ou la session est introuvable."
],
- "Search": [
- "Rechercher"
+ "The session is disabled. Contact the administrator.": [
+ "La session est désactivée. Contactez l’administrateur."
],
- "IBAN": [
- "IBAN"
+ "The exchange does not support PDF reports.": [
+ "L’Exchange ne prend pas en charge les rapports PDF."
],
- "Taler Bank": [
- "Banque Taler"
+ "Read-only officers cannot create AML decisions.": [
+ "Les agents en lecture seule ne peuvent pas créer de décisions AML."
],
- "Wallet": [
- "Portefeuille numérique"
+ "A payto URI is required to create a new decision.": [
+ "Une URI payto est nécessaire pour créer une nouvelle décision."
],
- "Generic Payto:// URI": [
- "URI Payto:// générique"
+ "Back to accounts": [
+ "Retour aux comptes"
],
- "Account type": [
- "Type de compte"
+ "File no. %1$s": [
+ "Dossier nº %1$s"
],
- "Should be 52 characters.": [
- "Doit comporter 52 caractères."
+ "New decision": [
+ "Nouvelle décision"
],
- "Failed to parse: %1$s": [
- "Échec de l'analyse : %1$s"
+ "Download AML file (PDF)": [
+ "Télécharger le dossier AML (PDF)"
],
- "Address contains invalid characters.": [
- "L'adresse contient des caractères invalides."
+ "AML file download started.": [
+ "Le téléchargement du dossier AML a commencé."
],
- "Can't mix uppercased and lowercased characters.": [
- "Impossible de mélanger majuscules et minuscules."
+ "Try again": [
+ ""
],
- "The addr checksum doesn't match.": [
- "La somme de contrôle de l'adresse ne correspond pas."
+ "Account identifiers": [
+ "Identifiants du compte"
],
- "Missing separator or address type.": [
- "Séparateur ou type d'adresse manquant."
+ "Technical identifiers": [
+ "Identifiants techniques"
],
- "Address should have less than 90 characters.": [
- "L'adresse doit comporter moins de 90 caractères."
+ "Full payto URI": [
+ "URI payto complète"
],
- "Address should have more than 6 characters.": [
- "L'adresse doit comporter plus de 6 caractères."
+ "Unavailable": [
+ "Indisponible"
],
- "Decoding issue.": [
- ""
+ "Copy payto URI": [
+ "Copier l’URI payto"
],
- "Unsupported country.": [
- "Pays non pris en charge."
+ "Normalized payto hash": [
+ "Empreinte payto normalisée"
],
- "IBANs have fewer than 34 characters.": [
- "Les IBAN comportent moins de 34 caractères."
+ "Copy normalized payto hash": [
+ "Copier l’empreinte payto normalisée"
],
- "IBANs have more than 4 characters.": [
- "Les IBAN comportent plus de 4 caractères."
+ "Account case views": [
+ "Vues du dossier du compte"
],
- "IBAN length is invalid for this country.": [
- "La longueur de l’IBAN n’est pas valide pour ce pays."
+ "Overview": [
+ "Vue d’ensemble"
],
- "It should only contain numbers and letters.": [
- "Il ne doit contenir que des chiffres et des lettres."
+ "Transfers": [
+ "Transferts"
],
- "The checksum is wrong.": [
- "La somme de contrôle est incorrecte."
+ "Decision history": [
+ "Historique des décisions"
],
- "The string should start with payto://": [
- "La chaîne doit commencer par payto://"
+ "Close": [
+ "Fermer"
],
- "After the target type it should follow a '/' with more information.": [
- "Après le type de cible, un « / » doit être suivi d'informations supplémentaires."
+ "Cancel": [
+ "Annuler"
],
- "The target type is not supported, only x-taler-bank, taler-reserve or iban": [
- "Le type de cible n'est pas pris en charge, seuls x-taler-bank, taler-reserve ou iban le sont"
+ "AML officer enrollment request": [
+ "Demande d’enregistrement d’un agent AML"
],
- "IBAN is missing": [
- "L'IBAN est manquant"
+ "Please enroll this AML officer public key:\n\n%1$s": [
+ "Veuillez enregistrer cette clé publique d’agent AML :\n\n%1$s"
],
- "Bitcoin address is missing": [
- "L'adresse Bitcoin est manquante"
+ "Officer key awaiting enrollment": [
+ "Clé de l’agent AML en attente d’enregistrement"
],
- "Bank host and account is missing": [
- "L'hôte bancaire et le compte sont manquants"
+ "This browser has created an AML officer key, but the exchange has not granted it access. Ask the exchange operator or administrator to enroll the public key below.": [
+ "Ce navigateur a créé une clé d’agent AML, mais l’exchange ne lui a pas accordé l’accès. Demandez à l’opérateur ou à l’administrateur de l’exchange d’enregistrer la clé publique ci-dessous."
],
- "Exchange host and account is missing": [
- "L'hôte de l'exchange et le compte sont manquants"
+ "AML officer public key": [
+ "Clé publique de l’agent AML"
],
- "Ethereum address is missing": [
- "L'adresse Ethereum est manquante"
+ "Copy AML officer public key": [
+ "Copier la clé publique de l’agent AML"
],
- "Cyclos address is missing": [
- "L'adresse Cyclos est manquante"
+ "After the operator confirms enrollment, retry the access check.": [
+ "Une fois l’enregistrement confirmé par l’opérateur, relancez la vérification de l’accès."
],
- "Invalid IBAN: %1$s": [
- "IBAN invalide : %1$s"
+ "Retry access check": [
+ "Vérifier à nouveau l’accès"
],
- "Invalid BTC: %1$s": [
- "BTC invalide : %1$s"
+ "Checking officer access": [
+ "Vérification de l’accès de l’agent AML"
],
- "Invalid reserve: %1$s": [
- "Réserve invalide : %1$s"
+ "Last checked at %1$s": [
+ "Dernière vérification à %1$s"
],
- "Invalid host": [
- "Hôte invalide"
+ "Request enrollment": [
+ "Demander l’enregistrement"
],
- "Invalid address": [
- "Adresse invalide"
+ "Discard this key": [
+ "Supprimer cette clé"
],
- "Payto URI": [
- "URI Payto"
+ "Confirmation required": [
+ "Confirmation requise"
],
- "As defined by RFC 8905": [
- "Tel que défini par la RFC 8905"
+ "Discarding this key removes the officer session from this browser. You will need to create a new key to use the AML WebUI again.": [
+ "La suppression de cette clé retire la session de l’agent de ce navigateur. Vous devrez créer une nouvelle clé pour utiliser à nouveau l’interface web AML."
],
- "payto://": [
- "payto://"
+ "Failed to check AML officer access.": [
+ "Échec de la vérification de l’accès de l’agent AML."
],
- "International Bank Account Number": [
- "Numéro de compte bancaire international"
+ "This officer key cannot authenticate with the exchange. Retry the check or discard the key and create a new session.": [
+ "Cette clé d’agent ne permet pas de s’authentifier auprès de l’exchange. Réessayez la vérification ou supprimez la clé et créez une nouvelle session."
],
- "DE1231231231": [
- "DE1231231231"
+ "The exchange rejected the officer access check.": [
+ "L’exchange a refusé la vérification de l’accès de l’agent."
],
- "Host": [
- "Hôte"
+ "Technical details": [
+ "Détails techniques"
],
- "Exchange hostname": [
- "Nom d'hôte de l'exchange"
+ "Failed to unlock the session.": [
+ ""
],
- "exchange.taler.net": [
- "exchange.taler.net"
+ "Unlock": [
+ "Déverrouiller"
],
- "Remove last '/'": [
- "Retirer le « / » final"
+ "Forget session": [
+ "Supprimer la session"
],
- "Invalid value": [
- "Valeur invalide"
+ "There are no rules for operations": [
+ "Il n'y a aucune règle pour les opérations"
],
- "ID": [
- "ID"
+ "This means that no operation has any limit.": [
+ "Cela signifie qu’aucune opération n’est limitée."
],
- "Wallet reserve public key": [
- "Clé publique de réserve du portefeuille"
+ "Operation": [
+ "Opération"
],
- "abcdef1235": [
- "abcdef1235"
+ "Threshold": [
+ "Seuil"
],
- "Should be 52 characters": [
- "Doit comporter 52 caractères"
+ "Escalation": [
+ "Escalade"
],
- "Account": [
- "Compte"
+ "Visibility": [
+ "Visibilité"
],
- "Bank account identification": [
- "Identification du compte bancaire"
+ "Priority": [
+ "Priorité"
],
- "DE123123123": [
- "DE123123123"
+ "Actions": [
+ "Actions"
],
- "Hostname": [
- "Nom d'hôte"
+ "Block operation": [
+ "Bloquer l’opération"
],
- "Without the scheme, may include subpath: bank.com, bank.com/path/": [
- "Sans le schéma, peut inclure un sous-chemin : bank.com, bank.com/path/"
+ "All required:": [
+ "Toutes requises :"
],
- "bank.demo.taler.net": [
- "bank.demo.taler.net"
+ "Any one:": [
+ "Une au choix :"
],
- "Invalid hostname": [
- "Nom d'hôte invalide"
+ "Customer-visible": [
+ "Visible par le client"
],
- "Failed to load the account information.": [
- ""
+ "Internal": [
+ "Interne"
],
- "Different form version": [
- "Version de formulaire différente"
+ "Move %1$s rule up": [
+ "Déplacer la règle %1$s vers le haut"
],
- "The collected information don't have the form version used.": [
- "Les informations collectées n'indiquent pas la version du formulaire utilisée."
+ "Move %1$s rule down": [
+ "Déplacer la règle %1$s vers le bas"
],
- "The collected information used the form version \"%1$s \" but is not available.": [
- "Les informations collectées utilisaient la version de formulaire « %1$s » mais elle n'est pas disponible."
+ "Edit %1$s rule": [
+ "Modifier la règle %1$s"
],
- "Case details": [
- "Détails du dossier"
+ "Remove %1$s rule": [
+ "Supprimer la règle %1$s"
],
- "Next event": [
- "Événement suivant"
+ "AML officer justification": [
+ "Justification de l'agent AML"
],
- "Previous event": [
- "Événement précédent"
+ "No justification was recorded.": [
+ "Aucune justification n’a été enregistrée."
],
- "Direction": [
- "Direction"
+ "Operation rules": [
+ "Règles d’opération"
],
- "Credit": [
- "Crédit"
+ "Decision date": [
+ "Date de la décision"
],
- "Debit": [
- "Débit"
+ "Expired": [
+ "Expiré"
],
- "KYC Auth": [
- "Authentification KYC"
+ "Expires": [
+ "Expire"
],
- "Minimum amount": [
- "Montant minimum"
+ "Successor measure": [
+ "Mesure suivante"
],
- "All amounts below the given threshold will be filtered.": [
- "Tous les montants inférieurs au seuil donné seront filtrés."
+ "Exchange defaults": [
+ "Règles par défaut de l’Exchange"
],
- "Failed to load the transfer list.": [
- ""
+ "Forms": [
+ "Formulaires"
],
- "Select transaction type": [
- "Sélectionner le type de transaction"
+ "Measures used to gather information about the customer.": [
+ "Mesures utilisées pour recueillir des informations sur le client."
],
- "Please select a transaction type to show transactions.": [
- "Veuillez sélectionner un type de transaction pour afficher les transactions."
+ "Select": [
+ "Sélectionner"
],
- "Transfers history for account": [
- "Historique des transferts du compte"
+ "Name": [
+ "Nom"
],
- "Transfers history": [
- "Historique des transferts"
+ "Check": [
+ "Vérifier"
],
- "No transfers yet.": [
- "Aucun transfert pour l'instant."
+ "Program": [
+ "Programme"
],
- "There are no transfers for this account.": [
- "Il n'y a aucun transfert pour ce compte."
+ "Context": [
+ "Contexte"
],
- "There are no transfers reported to the exchange with the current threshold.": [
- "Il n'y a aucun transfert signalé à l'exchange avec le seuil actuel."
+ "Modify": [
+ "Modifier"
],
- "Date": [
- "Date"
+ "Instant measures": [
+ "Mesures instantanées"
],
- "Amount": [
- "Montant"
+ "Triggered immediately without customer interaction.": [
+ "Déclenchées immédiatement sans interaction du client."
],
- "sent": [
- "envoyé"
+ "Input requirement": [
+ "Exigence de saisie"
],
- "received": [
- "reçu"
+ "Started": [
+ "Commencée"
],
- "to": [
- "à"
+ "Status": [
+ "Statut"
],
- "from": [
- "de"
+ "Forbidden": [
+ "Interdite"
],
- "Welcome to the exchange configuration": [
- "Bienvenue dans la configuration de l'exchange"
+ "Completed": [
+ "Terminée"
],
- "Transfers": [
- "Transferts"
+ "Waiting for customer": [
+ "En attente du client"
],
- "Profile": [
- "Profil"
+ "The operation is categorically forbidden by this requirement.": [
+ "Cette exigence interdit catégoriquement l’opération."
],
- "Failed to load available measures.": [
- "Impossible de charger les mesures disponibles."
+ "All listed measures must be completed.": [
+ "Toutes les mesures indiquées doivent être accomplies."
],
- "The officer session is invalid.": [
- "La session de l’agent AML n’est pas valide."
+ "Any one listed measure may be completed.": [
+ "Une seule des mesures indiquées peut être accomplie."
],
- "The measures endpoint was not found.": [
- "Le point de terminaison des mesures est introuvable."
+ "Values may be derived from the selected AML/KYC form. Confirm them against the case record and change only values that require an officer override.": [
+ ""
],
- "The officer session is disabled.": [
- "La session de l’agent AML est désactivée."
+ "Invalid custom properties": [
+ "Propriétés personnalisées non valides"
],
- "Failed to load the active AML decision.": [
- "Impossible de charger la décision AML active."
+ "Custom property names and values must be non-empty and names must be unique and different from built-in properties.": [
+ "Les noms et les valeurs des propriétés personnalisées ne doivent pas être vides ; les noms doivent être uniques et différents des propriétés intégrées."
],
- "The officer session signature is invalid.": [
- "La signature de la session de l’agent AML n’est pas valide."
+ "Properties": [
+ "Propriétés"
],
- "The requested AML account or session was not found.": [
- "Le compte AML ou la session demandée est introuvable."
+ "Built-in property names are preserved when the decision is submitted.": [
+ ""
],
- "The officer session is disabled or the account state changed.": [
- "La session de l’agent AML est désactivée ou l’état du compte a changé."
+ "Custom properties": [
+ "Propriétés personnalisées"
],
- "Invalid expiration": [
- "Expiration non valide"
+ "Add more properties that are not listed above.": [
+ "Ajoutez d'autres propriétés qui ne sont pas listées ci-dessus."
],
- "Attributes require an expiration date in the future.": [
- "Les attributs nécessitent une date d’expiration future."
+ "New properties": [
+ "Nouvelles propriétés"
],
- "Too many SKIP measures": [
- "Trop de mesures SKIP"
+ "Value": [
+ "Valeur"
],
- "At most one immediate measure may use the SKIP check.": [
- "Une seule mesure immédiate au maximum peut utiliser le contrôle SKIP."
+ "Current note on the GwG file": [
+ "Note actuelle sur le dossier GwG"
],
- "Require all measures": [
- "Exiger toutes les mesures"
+ "Customer name or internal alias.": [
+ "Nom du client ou alias interne."
],
- "Run all selected measures together instead of accepting any one of them.": [
- "Exécuter ensemble toutes les mesures sélectionnées au lieu d’accepter n’importe laquelle d’entre elles."
+ "Is the account active for deposit and payments?": [
+ "Le compte est-il actif pour les dépôts et les paiements ?"
],
- "Invalid custom properties": [
- "Propriétés personnalisées non valides"
+ "Is the account idle?": [
+ "Le compte est-il inactif ?"
],
- "Custom property names and values must be non-empty and names must be unique and different from built-in properties.": [
- "Les noms et les valeurs des propriétés personnalisées ne doivent pas être vides ; les noms doivent être uniques et différents des propriétés intégrées."
+ "No operation for a period of time": [
+ "Aucune opération pendant une période donnée"
],
- "Unknown measure": [
- "Mesure inconnue"
+ "Does account belong to a domestic PEP?": [
+ "Le compte appartient-il à une PPE nationale ?"
],
- "A rule or immediate action references a measure that is not available. Review the rules and measures before submitting.": [
- "Une règle ou une action immédiate fait référence à une mesure indisponible. Vérifiez les règles et les mesures avant l’envoi."
+ "Does account belong to a foreign PEP?": [
+ "Le compte appartient-il à une PPE étrangère ?"
],
- "Requires investigation": [
- "Nécessite une enquête"
+ "Does account belong to an international-organization PEP?": [
+ "Le compte appartient-il à une PPE d'organisation internationale ?"
],
- "Collection event not found": [
- "Événement de collecte introuvable"
+ "Does account belong to a high risk customer?": [
+ "Le compte appartient-il à un client à haut risque ?"
],
- "There is no collection event with ID %1$s for this account.": [
- "Il n’existe aucun événement de collecte portant l’identifiant %1$s pour ce compte."
+ "Does account belong to a person from a high risk country?": [
+ "Le compte appartient-il à une personne originaire d'un pays à haut risque ?"
],
- "Attributes unavailable": [
- "Attributs indisponibles"
+ "The MROS reporting state for the account.": [
+ "L'état de déclaration MROS du compte."
],
- "The collection event does not contain readable attributes.": [
- "L’événement de collecte ne contient aucun attribut lisible."
+ "None": [
+ "Aucun"
],
- "Form identifier missing": [
- "Identifiant du formulaire manquant"
+ "Pending investigation": [
+ "Enquête en attente"
],
- "The collected information does not identify the form used to create it.": [
- "Les informations collectées n’indiquent pas le formulaire utilisé pour les créer."
+ "Investigated without suspicion": [
+ "Enquêté sans soupçon"
],
- "Form not available": [
- "Formulaire indisponible"
+ "Reported simple suspicion": [
+ "Soupçon simple signalé"
],
- "Form %1$s is not configured in this AML Web UI.": [
- "Le formulaire %1$s n’est pas configuré dans cette interface Web AML."
+ "Reported substantiated suspicion": [
+ "Soupçon fondé signalé"
],
- "The account was not found.": [
- "Le compte est introuvable."
+ "Informal reason why the AML investigation was triggered": [
+ "Raison informelle du déclenchement de l'enquête AML"
],
- "The account state changed. Reload it and try again.": [
- "L’état du compte a changé. Rechargez-le et réessayez."
+ "Identifies the sanction list entry that the account matched against": [
+ "Identifie l'entrée de la liste de sanctions à laquelle le compte correspond"
],
- "The payto URI does not belong to this account. Return to the account search and start the decision again.": [
- "L’URI payto n’appartient pas à ce compte. Revenez à la recherche de comptes et recommencez la décision."
+ "Best match, does not mean it was a good match.": [
+ "Meilleure correspondance, ne signifie pas que c'était une bonne correspondance."
],
- "This account has no active decision and its payto URI is unknown. Start the decision from the account search so the account type can be determined safely.": [
- "Ce compte n’a aucune décision active et son URI payto est inconnue. Lancez la décision depuis la recherche de comptes afin de déterminer le type de compte de manière sûre."
+ "Score for how good the sanction list match was": [
+ "Score de la qualité de la correspondance avec la liste de sanctions"
],
- "Return to account": [
- "Revenir au compte"
+ "Integer score from 0 (no match) to 1,000,000,000 (best match).": [
+ ""
],
- "threshold\u0004%1$s every %2$s": [
- "%1$s tous les %2$s"
+ "Score for how much supporting data we had for the sanction list match": [
+ "Score de la quantité de données justificatives disponibles pour la correspondance avec la liste de sanctions"
],
- "operation type\u0004Withdraw": [
- "Retrait"
+ "Integer score from 0 (no supporting data) to 1,000,000,000 (highest confidence).": [
+ ""
],
- "operation type\u0004Deposit": [
- "Dépôt"
+ "Suppress flagging this account when it creates a hit on a sanctions list, this is a false-positive": [
+ "Supprimer le signalement de ce compte lorsqu'il correspond à une liste de sanctions ; il s'agit d'un faux positif"
],
- "operation type\u0004Merge": [
- "Fusion"
+ "Expiration shortcuts": [
+ "Raccourcis d’expiration"
],
- "operation type\u0004Aggregate": [
- "Agrégation"
+ "In a week": [
+ "Dans une semaine"
],
- "operation type\u0004Balance": [
- "Solde"
+ "In a month": [
+ "Dans un mois"
],
- "operation type\u0004Refund": [
- "Remboursement"
+ "In a year": [
+ "Dans un an"
],
- "operation type\u0004Close": [
- "Fermer"
+ "Never": [
+ "Jamais"
],
- "operation type\u0004Transaction": [
- "Transaction"
- ]
- }
- },
- "domain": "messages",
- "plural_forms": "",
- "lang": "fr",
- "completeness": 89
-};
-
-strings['es'] = {
- "locale_data": {
- "messages": {
- "": {
- "domain": "messages",
- "lang": "es",
- "plural_forms": ""
- },
- "Use testing dialect": [
- "Usar dialecto de prueba"
+ "Failed to load available measures.": [
+ "Impossible de charger les mesures disponibles."
],
- "Allow Insecure password": [
- "Permitir contraseña insegura"
+ "The officer session is invalid.": [
+ "La session de l’agent AML n’est pas valide."
],
- "Keep session after reload": [
- "Mantener la sesión después de recargar"
+ "The measures endpoint was not found.": [
+ "Le point de terminaison des mesures est introuvable."
],
- "Don't compress request": [
- "No comprimir la solicitud"
+ "The officer session is disabled.": [
+ "La session de l’agent AML est désactivée."
],
- "Preferences": [
- "Preferencias"
+ "Edit proposed rule": [
+ "Modifier la règle proposée"
],
- "Password": [
- "Contraseña"
+ "Add proposed rule": [
+ "Ajouter une règle proposée"
],
- "Required": [
- "Requerido"
+ "Save rule": [
+ "Enregistrer la règle"
],
- "should have at least 12 characters": [
- "debe tener al menos 12 caracteres"
+ "Add rule": [
+ "Ajouter une règle"
],
- "should have lowercase and uppercase characters": [
- "debe tener letras minúsculas y mayúsculas"
+ "This complete rule set replaces the currently applied rules and exchange defaults until it expires. Higher rows take precedence.": [
+ "Cet ensemble complet remplace les règles actuellement appliquées et les règles par défaut de l’échange jusqu’à son expiration. Les lignes supérieures sont prioritaires."
],
- "should have numbers": [
- "debe tener números"
+ "Rules for another account type": [
+ "Règles pour un autre type de compte"
],
- "should have at least one character which is not a number or letter": [
- "debe tener al menos un carácter que no sea un número o una letra"
+ "These operations do not apply to this account type: %1$s.": [
+ "Ces opérations ne s’appliquent pas à ce type de compte : %1$s."
],
- "Repeat password": [
- "Repetir contraseña"
+ "Operations without limits": [
+ "Opérations sans limites"
],
- "doesn't match": [
- "no coincide"
+ "No proposed rule limits these operations: %1$s.": [
+ "Aucune règle proposée ne limite ces opérations : %1$s."
],
- "Create": [
- "Crear"
+ "Invalid proposed rules": [
+ "Règles proposées non valides"
],
- "Failed to unlock the session.": [
- ""
+ "Edit the highlighted rule set before continuing. Hard blocks cannot be combined with measures, and Balance and Refund rules must use an instant timeframe.": [
+ "Modifiez l’ensemble de règles signalé avant de continuer. Les blocages stricts ne peuvent pas être combinés avec des mesures, et les règles de solde et de remboursement doivent utiliser une période instantanée."
],
- "Authorization denied for this session. Contact the administrator.": [
- ""
+ "Remove proposed rule?": [
+ "Supprimer la règle proposée ?"
],
- "Unlock": [
- "Desbloquear"
+ "This is the final rule. Removing it leaves every applicable operation unlimited.": [
+ "Il s’agit de la dernière règle. Sa suppression laisse toutes les opérations applicables sans limite."
],
- "There are no rules for operations": [
- "No hay reglas para las operaciones"
+ "The rule will be removed from the proposed set.": [
+ "La règle sera supprimée de l’ensemble proposé."
],
- "Add custom rule": [
- "Añadir regla personalizada"
+ "Keep rule": [
+ "Conserver la règle"
],
- "Operation": [
- "Operación"
+ "Remove rule": [
+ "Supprimer la règle"
],
- "Threshold": [
- "Umbral"
+ "Replace proposed rules": [
+ "Remplacer les règles proposées"
],
- "Escalation": [
- "Escalamiento"
+ "Preview a complete replacement before applying it.": [
+ "Prévisualisez le remplacement complet avant de l’appliquer."
],
- "%1$s": [
- "%1$s"
+ "Currently applied": [
+ "Actuellement appliquées"
],
- "(all)": [
- "(todos)"
+ "E-commerce": [
+ "Commerce électronique"
],
- "Since": [
- "Desde"
+ "Point of Sale": [
+ "Point de vente"
],
- "Expired": [
- "Vencido"
+ "Basic plan": [
+ "Forfait de base"
],
- "Expires": [
- "Vence"
+ "Premium": [
+ "Premium"
],
- "Successor measure": [
- "Medida sucesora"
+ "Freeze account": [
+ "Geler le compte"
],
- "AML officer justification": [
- "Justificación del oficial de AML"
+ "Replacement preview": [
+ "Aperçu du remplacement"
],
- "Default rules": [
- "Reglas predeterminadas"
+ "Confirm account freeze": [
+ "Confirmer le gel du compte"
],
- "Forms": [
- "Formularios"
+ "Every applicable operation will receive a zero hard limit.": [
+ "Chaque opération applicable recevra une limite stricte de zéro."
],
- "Name": [
- "Nombre"
+ "Apply replacement": [
+ "Appliquer le remplacement"
],
- "Check": [
- "Verificar"
+ "Choose how long the proposed rules apply and what happens afterwards.": [
+ "Choisissez la durée d’application des règles proposées et ce qui se passe ensuite."
],
- "Program": [
- "Programa"
+ "The proposed rules never expire, so no successor action will run.": [
+ "Les règles proposées n’expirent jamais ; aucune action ultérieure ne sera donc exécutée."
],
- "Context": [
- "Contexto"
+ "Restore currently applied expiration": [
+ "Rétablir l’expiration actuellement appliquée"
],
- "Modify": [
- "Modificar"
+ "Operation type": [
+ "Type d'opération"
],
- "Info": [
- "Información"
+ "Timeframe": [
+ "Période"
],
- "Will show information to the user.": [
- "Mostrará información al usuario."
+ "Use Y, M, D, h, m or s after each number. Forever accumulates over the account's full history.": [
+ "Utilisez Y, M, D, h, m ou s après chaque nombre. « Toujours » cumule sur tout l’historique du compte."
],
- "Instant measures": [
- "Medidas instantáneas"
+ "Instant timeframe": [
+ "Période instantanée"
],
- "Triggered immediately without customer interaction.": [
- "Se activan de inmediato sin interacción del cliente."
+ "Balance and Refund limits apply to one balance or transaction, so their timeframe is fixed to zero.": [
+ "Les limites de solde et de remboursement s’appliquent à un solde ou à une transaction ; leur période est donc fixée à zéro."
],
- "Input requirement": [
- "Requisito de entrada"
+ "Exposed": [
+ "Exposé"
],
- "Already completed.": [
- "Ya completado."
+ "Is this limit communicated to the customer?": [
+ "Cette limite est-elle communiquée au client ?"
],
- "Waiting to be completed.": [
- "Esperando a ser completado."
+ "When the threshold is crossed": [
+ "Lorsque le seuil est franchi"
],
- "Current active rules": [
- "Reglas activas actuales"
+ "Require measures": [
+ "Exiger des mesures"
],
- "There are no rules for this account yet.": [
- "Aún no hay reglas para esta cuenta."
+ "Required measures": [
+ "Mesures requises"
],
- "New rule form": [
- "Formulario de nueva regla"
+ "Measures that the customer will need to satisfy to apply for a new threshold.": [
+ "Mesures que le client devra satisfaire pour demander un nouveau seuil."
],
- "Add": [
- "Añadir"
+ "All measures": [
+ "Toutes les mesures"
],
- "Cancel": [
- "Cancelar"
+ "Hint the customer that all measures should be completed": [
+ "Indiquer au client que toutes les mesures doivent être complétées"
],
- "Basic plan": [
- "Plan básico"
+ "Expiration date": [
+ "Date d'expiration"
],
- "Premium": [
- "Premium"
+ "Until when are the new rules active.": [
+ "Jusqu'à quand les nouvelles règles sont actives."
],
- "E-commerce": [
- "Comercio electrónico"
+ "Choose a future expiration date or Never.": [
+ "Choisissez une date d’expiration future ou « Jamais »."
],
- "Point of Sale": [
- "Punto de venta"
+ "After expiration": [
+ "Après l’expiration"
],
- "Check rules": [
- "Verificar reglas"
+ "Return to exchange defaults": [
+ "Revenir aux valeurs par défaut de l’échange"
],
- "The account is a wallet and there are bank account operation's limits which may trigger actions that are not required: %1$s": [
- "La cuenta es una cartera y existen límites de operaciones de cuenta bancaria que pueden activar acciones que no son necesarias: %1$s"
+ "Trigger a successor measure": [
+ "Déclencher une mesure ultérieure"
],
- "The account isn't a wallet and there are wallet operation's limits which may trigger actions that are not required: %1$s": [
- "La cuenta no es una cartera y existen límites de operaciones de cartera que pueden activar acciones que no son necesarias: %1$s"
+ "Measure taken automatically upon expiration of the current decision.": [
+ "Mesure prise automatiquement à l'expiration de la décision actuelle."
],
- "The account is a wallet and there are wallet operation's limits which are not limited: %1$s": [
- "La cuenta es una cartera y existen límites de operaciones de cartera que no están limitados: %1$s"
+ "This successor measure is no longer available.": [
+ "Cette mesure ultérieure n’est plus disponible."
],
- "New rules": [
- "Nuevas reglas"
+ "Case summary": [
+ "Résumé du dossier"
],
- "Reset rules to current state": [
- "Restablecer las reglas al estado actual"
+ "Current review state and the latest account activity.": [
+ "État actuel de l’examen et activité la plus récente du compte."
],
- "Set rules to default": [
- "Establecer reglas predeterminadas"
+ "Review status": [
+ "État de l’examen"
],
- "Freeze account": [
- "Congelar cuenta"
+ "Loading…": [
+ "Chargement…"
],
- "Behavior on rule expiration": [
- "Comportamiento al vencer la regla"
+ "Manual review required — waiting for an AML decision.": [
+ "Examen manuel requis — en attente d’une décision AML."
],
- "Reset measure": [
- "Restablecer medida"
+ "No manual review": [
+ "Aucun examen manuel"
],
- "Reset expiration": [
- "Restablecer vencimiento"
+ "Effective decision": [
+ "Décision en vigueur"
],
- "Operation type": [
- "Tipo de operación"
+ "Requirements": [
+ "Exigences"
],
- "Timeframe": [
- "Marco temporal"
+ "Latest collected information": [
+ "Dernières informations recueillies"
],
- "Exposed": [
- "Expuesto"
+ "Effective policy": [
+ "Politique en vigueur"
],
- "Is this limit communicated to the customer?": [
- "¿Se comunica este límite al cliente?"
+ "The AML decision and operation rules currently applied to this account.": [
+ "La décision AML et les règles d’opération actuellement appliquées à ce compte."
],
- "Escalation measure": [
- "Medida de escalamiento"
+ "Effective policy could not be loaded": [
+ "Impossible de charger la politique en vigueur"
],
- "Measures that the customer will need to satisfy to apply for a new threshold.": [
- "Medidas que el cliente deberá cumplir para solicitar un nuevo umbral."
+ "Exchange defaults apply": [
+ "Les règles par défaut de l’Exchange s’appliquent"
],
- "All measures": [
- "Todas las medidas"
+ "No AML officer decision is active for this account.": [
+ "Aucune décision d’un agent AML n’est active pour ce compte."
],
- "Hint the customer that all measures should be completed": [
- "Indicar al cliente que debe completar todas las medidas"
+ "Account type unavailable": [
+ "Type de compte indisponible"
],
- "Expiration": [
- "Vencimiento"
+ "Open this case from the account directory or payto search to see the applicable default rules.": [
+ "Ouvrez ce dossier depuis le répertoire des comptes ou la recherche payto pour afficher les règles par défaut applicables."
],
- "Predefined shortcuts": [
- "Atajos predefinidos"
+ "Default rules could not be loaded": [
+ "Impossible de charger les règles par défaut"
],
- "In a week": [
- "En una semana"
+ "Default rules": [
+ "Règles par défaut"
],
- "In a month": [
- "En un mes"
+ "Account assessment": [
+ "Évaluation du compte"
],
- "In a year": [
- "En un año"
+ "Properties recorded by AML officers for this account.": [
+ "Propriétés enregistrées par les agents AML pour ce compte."
],
- "Never": [
- "Nunca"
+ "Account assessment could not be loaded": [
+ "Impossible de charger l’évaluation du compte"
],
- "Expiration date": [
- "Fecha de vencimiento"
+ "Collected information": [
+ "Informations collectées"
],
- "Until when are the new rules active.": [
- "Hasta cuándo estarán activas las nuevas reglas."
+ "KYC information filed by the customer or an AML officer.": [
+ "Informations KYC déposées par le client ou un agent AML."
],
- "Measure taken automatically upon expiration of the current decision.": [
- "Medida tomada automáticamente al vencer la decisión actual."
+ "Collected information could not be loaded": [
+ "Impossible de charger les informations recueillies"
],
- "Failed to load account information.": [
- ""
+ "No collected information": [
+ "Aucune information recueillie"
],
- "Failed to load decision history.": [
- ""
+ "No KYC information has been collected for this account.": [
+ "Aucune information KYC n’a été recueillie pour ce compte."
],
- "Failed to load current legitimizations.": [
- ""
+ "Active requirements": [
+ "Exigences actives"
],
- "New decision": [
- "Nueva decisión"
+ "Measures the customer must complete under the current policy.": [
+ "Mesures que le client doit accomplir selon la politique actuelle."
],
- "Show transfers": [
- "Mostrar transferencias"
+ "Active requirements could not be loaded": [
+ "Impossible de charger les exigences actives"
],
- "Failed to download report.": [
- ""
+ "No active requirements": [
+ "Aucune exigence active"
],
- "Session not found. Contact the administrator.": [
- ""
+ "The customer has no active legitimization measures to complete.": [
+ "Le client n’a aucune mesure de légitimation active à accomplir."
],
- "The session is disabled. Contact the administrator.": [
- ""
+ "Officer decision": [
+ "Décision de l’agent"
],
- "The server doesn't support PDF download. Contact the administrator.": [
- ""
+ "Does not expire": [
+ "N’expire pas"
],
- "Case history for selected account": [
- "Historial del caso para la cuenta seleccionada"
+ "Waiting": [
+ "En attente"
],
- "ID:": [
- "ID:"
+ "More on later pages": [
+ "Autres éléments sur les pages suivantes"
],
- "Payto:": [
- "Payto:"
+ "Try loading this section again.": [
+ "Essayez de recharger cette section."
],
- "Export as PDF": [
- "Exportar como PDF"
+ "Retry": [
+ "Réessayer"
],
- "Export completed": [
- "Exportación completada"
+ "No account properties": [
+ "Aucune propriété de compte"
],
- "Click here to save the file in your computer.": [
- "Haz clic aquí para guardar el archivo en tu computadora."
+ "No assessment properties have been recorded for this account.": [
+ "Aucune propriété d’évaluation n’a été enregistrée pour ce compte."
],
- "Under investigation": [
- "Bajo investigación"
+ "Yes": [
+ "Oui"
],
- "This account requires a manual review and is waiting for a decision to be made.": [
- "Esta cuenta requiere una revisión manual y está a la espera de una decisión."
+ "No": [
+ "Non"
],
- "Collected information": [
- "Información recopilada"
+ "Unconfigured form": [
+ "Formulaire non configuré"
],
- "Every attribute collection event (via form upload or KYC provider).": [
- "Cada evento de recopilación de atributos (mediante carga de formulario o proveedor KYC)."
+ "Form not identified": [
+ "Formulaire non identifié"
],
- "No collected attributes for this account.": [
- "No hay atributos recopilados para esta cuenta."
+ "Filed by an AML officer": [
+ "Déposé par un agent AML"
],
- "Current account properties": [
- "Propiedades actuales de la cuenta"
+ "Provided by the customer": [
+ "Fourni par le client"
],
- "No active decision found": [
- "No se encontró ninguna decisión activa"
+ "Attribute data is unavailable.": [
+ "Les données d’attributs sont indisponibles."
],
- "There is no decision for this account yet. The account is limited by the default rules.": [
- "Aún no hay ninguna decisión para esta cuenta. La cuenta está limitada por las reglas predeterminadas."
+ "View details": [
+ "Voir les détails"
],
- "Previous AML decisions": [
- "Decisiones de AML anteriores"
+ "Review superseded AML decisions for this account, from newest to oldest.": [
+ "Examiner les décisions AML remplacées pour ce compte, de la plus récente à la plus ancienne."
],
- "No AML history found": [
- "No se encontró historial de AML"
+ "Loading decision history…": [
+ "Chargement de l’historique des décisions…"
],
- "Current active measures": [
- "Medidas activas actuales"
+ "Decision history could not be loaded": [
+ "Impossible de charger l’historique des décisions"
],
- "Now": [
- "Ahora"
+ "Try loading the decision history again.": [
+ "Essayez de charger à nouveau l’historique des décisions."
],
- "Lock session": [
- ""
+ "No previous decisions": [
+ "Aucune décision antérieure"
+ ],
+ "No superseded AML decisions have been recorded for this account.": [
+ "Aucune décision AML remplacée n’a été enregistrée pour ce compte."
+ ],
+ "Previous decisions": [
+ "Décisions antérieures"
+ ],
+ "The export could not be prepared. Try again.": [
+ "L’exportation n’a pas pu être préparée. Réessayez."
],
"Failed to load accounts": [
- ""
+ "Impossible de charger les comptes"
],
- "High risk accounts. Only with custom rules.": [
- "Cuentas de alto riesgo. Solo con reglas personalizadas."
+ "Accounts": [
+ "Comptes"
],
- "Account with custom rules.": [
- "Cuenta con reglas personalizadas."
+ "Review accounts known to the exchange for AML and KYC handling.": [
+ "Consultez les comptes connus de l’exchange pour leur traitement AML et KYC."
],
- "High risk accounts": [
- "Cuentas de alto riesgo"
+ "Export filtered accounts": [
+ "Exporter les comptes filtrés"
],
- "All known accounts.": [
- "Todas las cuentas conocidas."
+ "Download CSV": [
+ "Télécharger le CSV"
],
- "High risk accounts under investigation. Only with custom rules.": [
- "Cuentas de alto riesgo bajo investigación. Solo con reglas personalizadas."
+ "Download Excel": [
+ "Télécharger le fichier Excel"
],
- "Accounts under investigation. Only with custom rules.": [
- "Cuentas bajo investigación. Solo con reglas personalizadas."
+ "Preparing export…": [
+ "Préparation de l’exportation…"
],
- "High risk accounts under investigation.": [
- "Cuentas de alto riesgo bajo investigación."
+ "Export failed": [
+ "Échec de l’exportation"
],
- "Accounts under investigation.": [
- "Cuentas bajo investigación."
+ "Account filters": [
+ "Filtres des comptes"
],
- "High risk accounts without investigation. Only with custom rules.": [
- "Cuentas de alto riesgo sin investigación. Solo con reglas personalizadas."
+ "Investigation": [
+ "Enquête"
],
- "Accounts without investigation. Only with custom rules.": [
- "Cuentas sin investigación. Solo con reglas personalizadas."
+ "All accounts": [
+ "Tous les comptes"
],
- "High risk accounts without investigation.": [
- "Cuentas de alto riesgo sin investigación."
+ "Not under investigation": [
+ "Pas sous enquête"
],
- "Accounts without investigation.": [
- "Cuentas sin investigación."
+ "Risk": [
+ "Risque"
],
- "Failed to download": [
- ""
+ "All risk levels": [
+ "Tous les niveaux de risque"
],
- "The format requested is not acceptable from the service provider.": [
- ""
+ "Not high risk": [
+ "Sans risque élevé"
],
- "Authorization denied for this session.": [
- ""
+ "File status": [
+ "État du dossier"
],
- "The session is disabled. Contact the administrator": [
- ""
+ "All file statuses": [
+ "Tous les états du dossier"
],
- "Accounts": [
- "Cuentas"
+ "Not open": [
+ "Non ouvert"
],
- "Export as file": [
- "Exportar como archivo"
+ "Clear filters": [
+ "Effacer les filtres"
],
- "No results": [
- "Sin resultados"
+ "Showing %1$s accounts · newest first": [
+ "%1$s comptes affichés · les plus récents en premier"
],
- "#": [
- "#"
+ "AML and KYC accounts": [
+ "Comptes AML et KYC"
],
- "Account Identification": [
- "Identificación de la cuenta"
+ "Account lifecycle": [
+ "Cycle de vie du dossier"
],
- "Open time": [
- "Hora de apertura"
+ "Latest note": [
+ "Note la plus récente"
],
- "Status": [
- "Estado"
+ "Copied": [
+ "Copié"
],
- "From %1$s %2$s To %3$s": [
- "Desde %1$s %2$s Hasta %3$s"
+ "Copy": [
+ "Copier"
],
- "Since %1$s": [
- "Desde %1$s"
+ "No matching accounts": [
+ "Aucun compte correspondant"
],
- "Not opened": [
- "No abierta"
+ "No accounts yet": [
+ "Aucun compte pour le moment"
],
- "High risk": [
- "Alto riesgo"
+ "No accounts match the selected filters.": [
+ "Aucun compte ne correspond aux filtres sélectionnés."
],
- "With custom rules": [
- "Con reglas personalizadas"
+ "The exchange has not recorded any AML or KYC accounts yet.": [
+ "L’exchange n’a encore enregistré aucun compte AML ou KYC."
],
- "Invalid account": [
- "Cuenta inválida"
+ "This officer session is not authorized to list accounts.": [
+ "Cette session d’agent n’est pas autorisée à répertorier les comptes."
],
- "Search by ID": [
- "Buscar por ID"
+ "The exchange does not recognize this officer session.": [
+ "L’exchange ne reconnaît pas cette session d’agent."
],
- "Under investigation: ": [
- "Bajo investigación: "
+ "This officer session is currently disabled.": [
+ "Cette session d’agent est actuellement désactivée."
],
- "High risk:": [
- "Alto riesgo:"
+ "There are no matching accounts to export.": [
+ "Aucun compte correspondant ne peut être exporté."
],
- "Custom rules:": [
- "Reglas personalizadas:"
+ "The exchange does not support the selected export format.": [
+ "L’exchange ne prend pas en charge le format d’exportation sélectionné."
+ ],
+ "This officer session is not authorized to export accounts.": [
+ "Cette session d’agent n’est pas autorisée à exporter les comptes."
],
"Dashboard": [
- "Panel"
+ "Tableau de bord"
],
- "Failed to load TOPS statistics.": [
+ "Review cases requiring attention, investigate accounts, and monitor AML reporting indicators.": [
+ ""
+ ],
+ "Review case queue": [
+ ""
+ ],
+ "Find credit, debit, and KYC authorization activity.": [
""
],
"Statistics": [
- "Estadísticas"
+ "Statistiques"
+ ],
+ "No reporting profile for this dialect": [
+ ""
+ ],
+ "The testing dialect does not define dashboard statistics. Select TOPS in development settings to inspect the TOPS reporting profile.": [
+ ""
+ ],
+ "Failed to load TOPS statistics.": [
+ ""
+ ],
+ "The available values are shown below. Missing values are not zero.": [
+ ""
],
"Accounts open": [
- "Cuentas abiertas"
+ "Comptes ouverts"
],
"New files last year": [
- "Expedientes nuevos el año pasado"
+ "Nouveaux dossiers l'année dernière"
],
"Closed files last year": [
- "Expedientes cerrados el año pasado"
+ "Dossiers fermés l'année dernière"
],
"MROS substantiated": [
- "MROS fundamentados"
+ "MROS motivés"
],
"MROS simple": [
"MROS simples"
],
"High risk files": [
- "Expedientes de alto riesgo"
+ "Dossiers à haut risque"
],
"PEP files": [
- "Expedientes PEP"
+ "Dossiers PPE"
],
"Number of accounts that are opened": [
- "Número de cuentas abiertas"
+ "Nombre de comptes ouverts"
],
"Number of new GwG files in the last year": [
- "Número de expedientes GwG nuevos en el último año"
+ "Nombre de nouveaux dossiers GwG au cours de la dernière année"
],
"Number of GwG files closed in the last year": [
- "Número de expedientes GwG cerrados en el último año"
+ "Nombre de dossiers GwG fermés au cours de la dernière année"
],
"Number of MROS reports based on Art 9 Abs. 1 GwG (per year)": [
- "Número de informes MROS basados en el Art. 9 Abs. 1 GwG (por año)"
+ "Nombre de déclarations MROS fondées sur l'art. 9 al. 1 GwG (par an)"
],
"Number of MROS reports based on Art 305ter Abs. 2 StGB (per year)": [
- "Número de informes MROS basados en el Art. 305ter Abs. 2 StGB (por año)"
+ "Nombre de déclarations MROS fondées sur l'art. 305ter al. 2 StGB (par an)"
],
"Number of GwG files of high-risk customers": [
- "Número de expedientes GwG de clientes de alto riesgo"
+ "Nombre de dossiers GwG de clients à haut risque"
],
"Number of GwG files managed with “increased risk” due to PEP status": [
- "Número de expedientes GwG gestionados con «riesgo incrementado» debido al estado de PEP"
+ "Nombre de dossiers GwG gérés avec un « risque accru » en raison du statut de PPE"
],
"previous": [
- "anterior"
+ "précédent"
],
"Decreased by": [
- "Disminuyó en"
+ "Diminué de"
],
"Increased by": [
- "Aumentó en"
+ "Augmenté de"
],
- "Events": [
- "Eventos"
+ "The built-in event selection differs from the events derived from the proposed account state.": [
+ ""
],
- "The events will be triggered only after the decision has been confirmed.": [
- "Los eventos solo se activarán después de que se confirme la decisión."
+ "Built-in events are derived from changes to the proposed account properties. They are stored for reporting and statistics; they do not notify the customer.": [
+ ""
],
"Calculated": [
- "Calculado"
- ],
- "Events based on properties and new attributes that should be triggered": [
- "Eventos basados en propiedades y nuevos atributos que deben activarse"
- ],
- "Others": [
- "Otros"
- ],
- "Events that can be triggered manually": [
- "Eventos que se pueden activar manualmente"
+ "Calculé"
],
- "Custom list": [
- "Lista personalizada"
+ "Events derived from proposed property changes and submitted information.": [
+ ""
],
- "Events without built-in support.": [
- "Eventos sin soporte incorporado."
+ "Other built-in events": [
+ ""
],
- "Complete the form": [
- "Completar el formulario"
+ "Operator-defined event names that are not part of the selected dialect.": [
+ ""
],
- "These measures will ask the customer for information.": [
- "Estas medidas solicitarán información al cliente."
+ "The completed form is attached to this AML decision as reviewed account information. It does not create a customer-facing measure.": [
+ ""
],
- "change form": [
- "cambiar formulario"
+ "Expiration": [
+ "Expiration"
],
"Expiration date of the information filled in this form.": [
- "Fecha de vencimiento de la información completada en este formulario."
- ],
- "Include new information": [
- "Incluir nueva información"
+ "Date d'expiration des informations saisies dans ce formulaire."
],
- "Select a form to submit new information about the customer or continue to the next step": [
- "Selecciona un formulario para enviar nueva información sobre el cliente o continúa al siguiente paso"
+ "Only change this operator-defined JSON when the form documentation requires additional context.": [
+ ""
],
- "Form:": [
- "Formulario:"
+ "Invalid expiration": [
+ "Expiration non valide"
],
- "Justification": [
- "Justificación"
+ "Attributes require an expiration date in the future or set to Never.": [
+ "Les attributs nécessitent une date d’expiration future ou doivent être définis sur « Jamais »."
],
- "Keep investigation?": [
- "¿Mantener investigación?"
+ "Include new information": [
+ "Inclure de nouvelles informations"
],
- "Account holder": [
- "Titular de la cuenta"
+ "This step is optional. Select a form to attach newly reviewed AML/KYC information, or continue without one.": [
+ ""
],
- "Full name of the account holder": [
- "Nombre completo del titular de la cuenta"
+ "AML/KYC form": [
+ ""
],
- "loading...": [
- "cargando..."
+ "Search AML/KYC forms": [
+ "Rechercher des formulaires AML/KYC"
],
- "Update": [
- "Actualizar"
+ "Full name used in the payto URI when creating this previously unknown account.": [
+ ""
],
- "Remove": [
- "Quitar"
+ "Record the facts and reasoning needed to understand this decision in a later audit or review.": [
+ ""
],
- "Configure verification type: %1$s": [
- "Configurar tipo de verificación: %1$s"
+ "Combine a customer check with an AML program, or use SKIP to run a program immediately. Context values must satisfy the selected check and program requirements.": [
+ ""
],
- "Show complete form": [
- "Mostrar formulario completo"
+ "Add custom measure": [
+ "Ajouter une mesure personnalisée"
],
- "Configure measure": [
- "Configurar medida"
+ "Save changes": [
+ ""
],
- "Show as verification": [
- "Mostrar como verificación"
+ "Use advanced measure editor": [
+ ""
],
"There is already a measure with that name": [
- "Ya existe una medida con ese nombre"
+ "Il existe déjà une mesure portant ce nom"
],
- "Only required when no check is specified": [
- "Solo se requiere cuando no se especifica ninguna verificación"
+ "Runs immediately for SKIP measures, or after a successful check. It may be omitted for a check that only presents or collects information.": [
+ ""
],
"Missing check or program": [
- "Falta la verificación o el programa"
+ "Vérification ou programme manquant"
+ ],
+ "The customer-facing check to perform before the program. Leave empty to use SKIP and run the program immediately.": [
+ ""
],
- "Without a check the program will run automatically": [
- "Sin una verificación, el programa se ejecutará automáticamente"
+ "Configuration values required by the selected check or program. Property names and value types must match the exchange configuration.": [
+ ""
],
"Field name": [
- "Nombre del campo"
+ "Nom du champ"
],
"Type": [
- "Tipo"
+ "Type"
],
"string": [
- "cadena"
+ "chaîne"
],
"number": [
- "número"
+ "nombre"
],
"boolean": [
- "booleano"
+ "booléen"
],
"json": [
"json"
],
- "Value": [
- "Valor"
- ],
"There are unsatisfied inputs: %1$s": [
- "Hay entradas no satisfechas: %1$s"
+ "Il y a des entrées non satisfaites : %1$s"
+ ],
+ "Check \"%1$s\" is not available": [
+ ""
],
"There are missing inputs: %1$s": [
- "Faltan entradas: %1$s"
+ "Il manque des entrées : %1$s"
],
"There are missing requirements: %1$s": [
- "Faltan requisitos: %1$s"
+ "Il manque des exigences : %1$s"
],
"Can't be empty": [
- "No puede estar vacío"
- ],
- "It should be a number": [
- "Debe ser un número"
+ "Ne peut pas être vide"
],
"Not a number": [
- "No es un número"
+ "Pas un nombre"
],
"It should be finite": [
- "Debe ser finito"
- ],
- "It should be a safe integer": [
- "Debe ser un entero seguro"
+ "Cela doit être fini"
],
"It should be either \"true\" or \"false\"": [
- "Debe ser \"true\" o \"false\""
+ "Cela doit être soit « true » soit « false »"
],
"Couldn't parse as json string: %1$s": [
- "No se pudo interpretar como cadena json: %1$s"
+ "Impossible d'analyser comme chaîne json : %1$s"
],
"Description": [
- "Descripción"
+ "Description"
],
"Inputs": [
- "Entradas"
+ "Entrées"
],
- "Output": [
- "Salida"
+ "Fallback": [
+ "Repli"
],
- "Requires": [
- "Requiere"
+ "Selected pipeline": [
+ ""
],
- "Fallback": [
- "Alternativa"
+ "Review how the exchange will execute this measure.": [
+ ""
],
"Name of the verification measure": [
- "Nombre de la medida de verificación"
+ "Nom de la mesure de vérification"
],
"Read only": [
- "Solo lectura"
+ "Lecture seule"
],
"Prevent the customer from changing the address": [
- "Impedir que el cliente cambie la dirección"
+ "Empêcher le client de modifier l'adresse"
],
- "Configure verification measure: \"%1$s\"": [
- "Configurar medida de verificación: \"%1$s\""
+ "Customer actions after submission": [
+ ""
],
- "Add custom measure": [
- "Añadir medida personalizada"
+ "Immediate measures start as soon as this decision is accepted. A measure may show information, collect customer data, or run an AML program. Leave the selection empty when no immediate customer action is required.": [
+ ""
+ ],
+ "Too many SKIP measures": [
+ "Trop de mesures SKIP"
+ ],
+ "At most one immediate measure may use the SKIP check.": [
+ "Une seule mesure immédiate au maximum peut utiliser le contrôle SKIP."
],
"Custom measures": [
- "Medidas personalizadas"
+ "Mesures personnalisées"
],
- "Server measures": [
- "Medidas del servidor"
+ "Measures defined only for this proposed decision.": [
+ ""
],
- "New measures": [
- "Nuevas medidas"
+ "Edit": [
+ ""
],
- "Measures that are available/executed directly after the decision is confirmed.": [
- "Medidas disponibles/ejecutadas directamente después de confirmar la decisión."
+ "Reusable templates configured by the exchange operator": [
+ ""
],
- "Reset to default": [
- "Restablecer a los valores predeterminados"
+ "Use as template": [
+ ""
],
- "Properties": [
- "Propiedades"
+ "Selected measures begin immediately after the decision is accepted by the exchange.": [
+ ""
],
- "Custom properties": [
- "Propiedades personalizadas"
+ "Session not found. Contact the administrator.": [
+ ""
],
- "Add more properties that are not listed above.": [
- "Añade más propiedades que no estén listadas arriba."
+ "The exchange rejected the decision because the officer session is disabled or the account has a newer decision. Reload the account before trying again.": [
+ ""
],
- "New properties": [
- "Nuevas propiedades"
+ "This decision records that an MROS report was filed. Confirm that the report has actually been submitted before continuing.": [
+ ""
],
- "Current note on the GwG file": [
- "Nota actual del expediente GwG"
+ "Confirm decision": [
+ "Confirmer la décision"
],
- "Customer name or internal alias.": [
- "Nombre del cliente o alias interno."
+ "Unknown measure": [
+ "Mesure inconnue"
],
- "Is the account active for deposit and payments?": [
- "¿Está la cuenta activa para depósitos y pagos?"
+ "A rule or immediate action references a measure that is not available. Review the rules and measures before submitting.": [
+ "Une règle ou une action immédiate fait référence à une mesure indisponible. Vérifiez les règles et les mesures avant l’envoi."
],
- "Is the account idle?": [
- "¿Está la cuenta inactiva?"
+ "A custom measure references an unavailable check or program, lacks required context, or cannot provide the selected program inputs. Review the immediate measures before submitting.": [
+ ""
],
- "No operation for a period of time": [
- "Sin operaciones durante un período de tiempo"
+ "Missing deadline": [
+ "Échéance manquante"
],
- "Does account belong to a domestic PEP?": [
- "¿Pertenece la cuenta a un PEP nacional?"
+ "Set when the proposed rules expire and what should happen afterward.": [
+ ""
],
- "Does account belong to a foreign PEP?": [
- "¿Pertenece la cuenta a un PEP extranjero?"
+ "Invalid rule expiration": [
+ "Expiration des règles non valide"
],
- "Does account belong to an international-organization PEP?": [
- "¿Pertenece la cuenta a un PEP de organización internacional?"
+ "Rule expiration must be in the future or set to Never.": [
+ "L’expiration des règles doit être future ou définie sur « Jamais »."
],
- "Does account belong to a high risk customer?": [
- "¿Pertenece la cuenta a un cliente de alto riesgo?"
+ "Missing rules": [
+ "Règles manquantes"
],
- "Does account belong to a person from a high risk country?": [
- "¿Pertenece la cuenta a una persona de un país de alto riesgo?"
+ "A decision must contain the complete rule set that will apply to the account.": [
+ ""
+ ],
+ "Review the proposed rules. Hard blocks must be explicit, and Balance and Refund rules must use an instant timeframe.": [
+ "Vérifiez les règles proposées. Les blocages stricts doivent être explicites, et les règles de solde et de remboursement doivent utiliser une période instantanée."
+ ],
+ "Immediate measures not reviewed": [
+ ""
+ ],
+ "No measure will start when this decision is submitted.": [
+ ""
+ ],
+ "Review the account properties before submitting the decision.": [
+ ""
+ ],
+ "Reporting events not reviewed": [
+ ""
+ ],
+ "Review which statistical events will be recorded with the decision.": [
+ ""
+ ],
+ "Case disposition incomplete": [
+ ""
+ ],
+ "You must complete the justification section.": [
+ "Vous devez compléter la section de justification."
+ ],
+ "Invalid attributes": [
+ "Attributs invalides"
+ ],
+ "Correct the selected form or continue without attaching new customer information.": [
+ ""
+ ],
+ "Justification": [
+ "Justification"
+ ],
+ "Events": [
+ "Événements"
+ ],
+ "All entries made in this decision wizard will be lost. No change will be submitted to the exchange.": [
+ ""
+ ],
+ "Payto URI": [
+ "URI Payto"
+ ],
+ "Decision steps": [
+ ""
+ ],
+ "Account properties": [
+ "Propriétés du compte"
+ ],
+ "Review the account state derived from the available information.": [
+ ""
+ ],
+ "Review the statistical events recorded with this decision.": [
+ ""
+ ],
+ "Set operation thresholds, escalation measures, and expiration behavior.": [
+ ""
+ ],
+ "Case disposition": [
+ ""
+ ],
+ "Check the complete decision before signing and submitting it.": [
+ ""
+ ],
+ "Enter a valid HTTP or HTTPS URL.": [
+ ""
+ ],
+ "Development settings": [
+ "Paramètres de développement"
+ ],
+ "These browser-local settings are intended for development and troubleshooting.": [
+ ""
+ ],
+ "Changing the exchange reloads the application. The override is stored only in this browser.": [
+ ""
+ ],
+ "Exchange base URL": [
+ "URL de base de l’exchange"
+ ],
+ "Leave empty to use the configured URL: %1$s": [
+ ""
+ ],
+ "Leave empty to derive the exchange URL from this page.": [
+ ""
+ ],
+ "Currently connected to": [
+ ""
+ ],
+ "Apply and reload": [
+ ""
+ ],
+ "Use configured URL": [
+ ""
+ ],
+ "Preferences": [
+ "Préférences"
+ ],
+ "AML SPA dialect": [
+ ""
+ ],
+ "Testing": [
+ ""
+ ],
+ "Override how this web interface presents dialect-specific AML rules and properties. The override is stored only in this browser.": [
+ ""
+ ],
+ "Fallback dialect for development and testing.": [
+ ""
+ ],
+ "TOPS": [
+ ""
+ ],
+ "Taler Operations deployment for Swiss AML processes.": [
+ ""
+ ],
+ "File note": [
+ "Note au dossier"
+ ],
+ "Text": [
+ ""
+ ],
+ "Customer label": [
+ "Libellé du client"
+ ],
+ "Account open": [
+ "Compte ouvert"
+ ],
+ "Domestic PEP": [
+ "PPE nationale"
+ ],
+ "Whether the customer is a domestic politically exposed person.": [
+ ""
+ ],
+ "Foreign PEP": [
+ "PPE étrangère"
+ ],
+ "Whether the customer is a foreign politically exposed person.": [
+ ""
+ ],
+ "International-organization PEP": [
+ "PPE d’une organisation internationale"
+ ],
+ "Whether the customer is a politically exposed person associated with an international organization.": [
+ ""
+ ],
+ "High-risk customer": [
+ "Client à haut risque"
+ ],
+ "High-risk country": [
+ "Pays à haut risque"
+ ],
+ "Whether the customer is associated with a high-risk country.": [
+ ""
+ ],
+ "Account idle": [
+ "Compte inactif"
+ ],
+ "Whether the account has been marked as idle.": [
+ ""
+ ],
+ "Score from 0 (no match) to 1,000,000,000 (best match).": [
+ ""
+ ],
+ "Score from 0 (no supporting data) to 1,000,000,000 (highest confidence).": [
+ ""
+ ],
+ "Whether this account's sanction-list hit is treated as a false positive.": [
+ ""
+ ],
+ "Recorded when an account changes to open.": [
+ ""
+ ],
+ "Recorded when an account changes from open to closed.": [
+ ""
+ ],
+ "Recorded when an open account becomes classified as a high-risk customer.": [
+ ""
+ ],
+ "Recorded when the high-risk customer classification is removed.": [
+ ""
+ ],
+ "Recorded when an open account becomes associated with a high-risk country.": [
+ ""
+ ],
+ "High-risk country classification removed": [
+ ""
+ ],
+ "Recorded when the high-risk country classification is removed.": [
+ ""
+ ],
+ "PEP classification added": [
+ ""
+ ],
+ "Recorded when an open account becomes associated with any PEP category.": [
+ ""
+ ],
+ "Recorded when the account is no longer associated with any PEP category.": [
+ ""
+ ],
+ "Foreign PEP classification added": [
+ ""
+ ],
+ "Recorded when an open account becomes associated with a foreign PEP.": [
+ ""
+ ],
+ "Foreign PEP classification removed": [
+ ""
+ ],
+ "Recorded when the foreign PEP classification is removed.": [
+ ""
+ ],
+ "Domestic PEP classification added": [
+ ""
+ ],
+ "Recorded when an open account becomes associated with a domestic PEP.": [
+ ""
+ ],
+ "Domestic PEP classification removed": [
+ ""
+ ],
+ "Recorded when the domestic PEP classification is removed.": [
+ ""
+ ],
+ "Recorded when the international-organization PEP classification is removed.": [
+ ""
+ ],
+ "Simple suspicion reported to MROS": [
+ ""
+ ],
+ "Recorded when a report is filed under Article 305ter paragraph 2 StGB.": [
+ ""
+ ],
+ "Recorded when a report is filed under Article 9 GwG.": [
+ ""
+ ],
+ "Recorded when a pending special clarification is concluded.": [
+ ""
+ ],
+ "Recorded when a previously concluded investigation returns to a non-concluded state.": [
+ ""
+ ],
+ "Browser override": [
+ ""
+ ],
+ "Exchange identity, the active AML dialect, and the checks and programs available to AML decisions.": [
+ ""
+ ],
+ "Public information reported by this exchange.": [
+ ""
+ ],
+ "Base URL": [
+ ""
+ ],
+ "Protocol": [
+ ""
+ ],
+ "Protocol version": [
+ ""
+ ],
+ "Currency": [
+ ""
+ ],
+ "AML dialect": [
+ ""
+ ],
+ "Canonical properties defined by the effective dialect.": [
+ ""
+ ],
+ "This dialect does not define derived events.": [
+ ""
+ ],
+ "Checks, programs, root measures, and default rules reported by the exchange.": [
+ ""
+ ],
+ "%1$s entries": [
+ ""
+ ],
+ "No root measures are configured.": [
+ ""
+ ],
+ "No KYC checks are configured.": [
+ ""
+ ],
+ "No AML programs are configured.": [
+ ""
+ ],
+ "No default AML rules are configured.": [
+ ""
+ ],
+ "Built-in check that proceeds without collecting customer data.": [
+ ""
+ ],
+ "Voluntary": [
+ ""
+ ],
+ "Session and access": [
+ "Session et accès"
+ ],
+ "Review this officer's exchange access and manage the unlocked key in this browser.": [
+ "Vérifiez l’accès de cet agent à l’exchange et gérez la clé déverrouillée dans ce navigateur."
+ ],
+ "Officer access": [
+ "Accès de l’agent"
+ ],
+ "Officer name": [
+ "Nom de l’agent"
+ ],
+ "Permissions": [
+ "Autorisations"
+ ],
+ "Read-only": [
+ "Lecture seule"
+ ],
+ "Read and write": [
+ "Lecture et écriture"
+ ],
+ "Session security": [
+ "Sécurité de la session"
+ ],
+ "Lock the session when you leave this device unattended.": [
+ "Verrouillez la session lorsque vous laissez cet appareil sans surveillance."
+ ],
+ "Lock now": [
+ "Verrouiller maintenant"
+ ],
+ "Unlocked": [
+ "Déverrouillée"
+ ],
+ "Locks automatically": [
+ "Verrouillage automatique"
+ ],
+ "Exact time": [
+ "Heure exacte"
+ ],
+ "Officer public key": [
+ "Clé publique de l’agent"
+ ],
+ "Copy public key": [
+ "Copier la clé publique"
+ ],
+ "Remove key from this browser": [
+ "Supprimer la clé de ce navigateur"
+ ],
+ "Removing this key deletes the officer key from this browser. It does not revoke or change the officer's access at the exchange. Ask the exchange operator to revoke access if needed.": [
+ "La suppression de cette clé efface la clé de l’agent de ce navigateur. Elle ne révoque ni ne modifie l’accès de l’agent auprès de l’exchange. Demandez à l’opérateur de l’exchange de révoquer l’accès si nécessaire."
+ ],
+ "Remove key": [
+ "Supprimer la clé"
+ ],
+ "Remove officer key?": [
+ "Supprimer la clé de l’agent ?"
+ ],
+ "This deletes the officer key from this browser. You will need to create and enroll a new key to use the AML WebUI here again.": [
+ "Ceci efface la clé de l’agent de ce navigateur. Vous devrez créer et faire inscrire une nouvelle clé pour réutiliser l’interface web AML ici."
+ ],
+ "This does not revoke the officer at the exchange. Ask the exchange operator to revoke its access if the key may be compromised.": [
+ "Ceci ne révoque pas l’agent auprès de l’exchange. Demandez à l’opérateur de l’exchange de révoquer son accès si la clé est susceptible d’être compromise."
+ ],
+ "Find account": [
+ "Rechercher un compte"
+ ],
+ "Look up an account by its payto information or normalized payto hash.": [
+ "Recherchez un compte à partir de ses informations payto ou de son empreinte payto normalisée."
+ ],
+ "Find by payto": [
+ "Rechercher par payto"
+ ],
+ "Find by normalized payto hash": [
+ "Rechercher par empreinte payto normalisée"
+ ],
+ "Enter a valid 52-character normalized payto hash.": [
+ "Saisissez une empreinte payto normalisée valide de 52 caractères."
+ ],
+ "Open account": [
+ "Ouvrir le compte"
+ ],
+ "Failed to load account decisions.": [
+ "Impossible de charger les décisions du compte."
+ ],
+ "Failed to load the account history.": [
+ "Impossible de charger l’historique du compte."
+ ],
+ "This session signature is invalid, contact administrator or create a new one.": [
+ "La signature de cette session n’est pas valide. Contactez l’administrateur ou créez-en une nouvelle."
+ ],
+ "The designated AML session is not known, contact administrator or create a new one.": [
+ "La session AML indiquée est inconnue. Contactez l’administrateur ou créez-en une nouvelle."
+ ],
+ "The designated AML session is not enabled, contact administrator or create a new one.": [
+ "La session AML indiquée n’est pas activée. Contactez l’administrateur ou créez-en une nouvelle."
+ ],
+ "This account has an AML decision history. Open its case to review current rules, measures, attributes, and past decisions.": [
+ ""
+ ],
+ "Active": [
+ ""
+ ],
+ "Account not found": [
+ "Compte introuvable"
+ ],
+ "There is no history known for this account yet.": [
+ "Aucun historique connu pour ce compte pour l'instant."
+ ],
+ "Search": [
+ "Rechercher"
+ ],
+ "Taler Bank": [
+ "Banque Taler"
+ ],
+ "Wallet": [
+ "Portefeuille numérique"
+ ],
+ "Generic Payto:// URI": [
+ "URI Payto:// générique"
+ ],
+ "Account type": [
+ "Type de compte"
+ ],
+ "Should be 52 characters.": [
+ "Doit comporter 52 caractères."
+ ],
+ "Failed to parse: %1$s": [
+ "Échec de l'analyse : %1$s"
+ ],
+ "Address contains invalid characters.": [
+ "L'adresse contient des caractères invalides."
+ ],
+ "Can't mix uppercased and lowercased characters.": [
+ "Impossible de mélanger majuscules et minuscules."
+ ],
+ "The addr checksum doesn't match.": [
+ "La somme de contrôle de l'adresse ne correspond pas."
+ ],
+ "Missing separator or address type.": [
+ "Séparateur ou type d'adresse manquant."
+ ],
+ "Address should have less than 90 characters.": [
+ "L'adresse doit comporter moins de 90 caractères."
+ ],
+ "Address should have more than 6 characters.": [
+ "L'adresse doit comporter plus de 6 caractères."
+ ],
+ "Decoding issue.": [
+ "Problème de décodage."
+ ],
+ "Invalid data": [
+ "Données non valides"
+ ],
+ "Unsupported country.": [
+ "Pays non pris en charge."
+ ],
+ "IBANs have fewer than 34 characters.": [
+ "Les IBAN comportent moins de 34 caractères."
+ ],
+ "IBANs have more than 4 characters.": [
+ "Les IBAN comportent plus de 4 caractères."
+ ],
+ "IBAN length is invalid for this country.": [
+ "La longueur de l’IBAN n’est pas valide pour ce pays."
+ ],
+ "It should only contain numbers and letters.": [
+ "Il ne doit contenir que des chiffres et des lettres."
+ ],
+ "The checksum is wrong.": [
+ "La somme de contrôle est incorrecte."
+ ],
+ "The string should start with payto://": [
+ "La chaîne doit commencer par payto://"
+ ],
+ "After the target type it should follow a '/' with more information.": [
+ "Après le type de cible, un « / » doit être suivi d'informations supplémentaires."
+ ],
+ "The target type is not supported, only x-taler-bank, taler-reserve or iban": [
+ "Le type de cible n'est pas pris en charge, seuls x-taler-bank, taler-reserve ou iban le sont"
+ ],
+ "IBAN is missing": [
+ "L'IBAN est manquant"
+ ],
+ "Bitcoin address is missing": [
+ "L'adresse Bitcoin est manquante"
+ ],
+ "Bank host and account is missing": [
+ "L'hôte bancaire et le compte sont manquants"
+ ],
+ "Exchange host and account is missing": [
+ "L'hôte de l'exchange et le compte sont manquants"
+ ],
+ "Ethereum address is missing": [
+ "L'adresse Ethereum est manquante"
+ ],
+ "Cyclos address is missing": [
+ "L'adresse Cyclos est manquante"
+ ],
+ "Void address is missing": [
+ "L’adresse void est manquante"
+ ],
+ "Invalid IBAN: %1$s": [
+ "IBAN invalide : %1$s"
+ ],
+ "Invalid BTC: %1$s": [
+ "BTC invalide : %1$s"
+ ],
+ "Invalid reserve: %1$s": [
+ "Réserve invalide : %1$s"
+ ],
+ "Invalid host": [
+ "Hôte invalide"
+ ],
+ "Invalid account": [
+ "Compte invalide"
+ ],
+ "Invalid address": [
+ "Adresse invalide"
+ ],
+ "As defined by RFC 8905": [
+ "Tel que défini par la RFC 8905"
+ ],
+ "payto://": [
+ "payto://"
+ ],
+ "International Bank Account Number": [
+ "Numéro de compte bancaire international"
+ ],
+ "DE1231231231": [
+ "DE1231231231"
+ ],
+ "Host": [
+ "Hôte"
+ ],
+ "Exchange hostname": [
+ "Nom d'hôte de l'exchange"
+ ],
+ "exchange.taler.net": [
+ "exchange.taler.net"
+ ],
+ "Remove last '/'": [
+ "Retirer le « / » final"
+ ],
+ "Invalid value": [
+ "Valeur invalide"
+ ],
+ "ID": [
+ "ID"
+ ],
+ "Wallet reserve public key": [
+ "Clé publique de réserve du portefeuille"
+ ],
+ "abcdef1235": [
+ "abcdef1235"
+ ],
+ "Should be 52 characters": [
+ "Doit comporter 52 caractères"
+ ],
+ "Bank account identification": [
+ "Identification du compte bancaire"
+ ],
+ "DE123123123": [
+ "DE123123123"
+ ],
+ "Hostname": [
+ "Nom d'hôte"
+ ],
+ "Without the scheme, may include subpath: bank.com, bank.com/path/": [
+ "Sans le schéma, peut inclure un sous-chemin : bank.com, bank.com/path/"
+ ],
+ "bank.demo.taler.net": [
+ "bank.demo.taler.net"
+ ],
+ "Invalid hostname": [
+ "Nom d'hôte invalide"
+ ],
+ "Failed to load account information.": [
+ "Impossible de charger les informations du compte."
+ ],
+ "Failed to load the account information.": [
+ ""
+ ],
+ "Collection event not found": [
+ "Événement de collecte introuvable"
+ ],
+ "There is no collection event with ID %1$s for this account.": [
+ "Il n’existe aucun événement de collecte portant l’identifiant %1$s pour ce compte."
+ ],
+ "Attributes unavailable": [
+ "Attributs indisponibles"
+ ],
+ "The collection event does not contain readable attributes.": [
+ "L’événement de collecte ne contient aucun attribut lisible."
+ ],
+ "Form identifier missing": [
+ "Identifiant du formulaire manquant"
+ ],
+ "The collected information does not identify the form used to create it.": [
+ "Les informations collectées n’indiquent pas le formulaire utilisé pour les créer."
+ ],
+ "Form not available": [
+ "Formulaire indisponible"
+ ],
+ "Form %1$s is not configured in this AML Web UI.": [
+ "Le formulaire %1$s n’est pas configuré dans cette interface Web AML."
+ ],
+ "Source": [
+ ""
+ ],
+ "Different form version": [
+ "Version de formulaire différente"
+ ],
+ "The collected information does not identify the form version used. The latest configured version is shown and field labels may differ from those used at collection time.": [
+ ""
+ ],
+ "JSON view": [
+ ""
+ ],
+ "Incoming": [
+ ""
+ ],
+ "Outgoing": [
+ ""
+ ],
+ "KYC authorization": [
+ ""
+ ],
+ "Wallet credits (P2P)": [
+ ""
+ ],
+ "Minimum amount": [
+ "Montant minimum"
+ ],
+ "All amounts below the given threshold will be filtered.": [
+ "Tous les montants inférieurs au seuil donné seront filtrés."
+ ],
+ "Inspect successful P2P credits received by this wallet. Requests that were not paid are not shown.": [
+ ""
+ ],
+ "Inspect effective bank transfers observed by the exchange. Credit transfers are incoming, debit transfers are outgoing, and bounced or drain transfers are not included.": [
+ ""
+ ],
+ "Inspect effective transfers observed by the exchange. Incoming, outgoing, and KYC authorization entries are bank transfers. Wallet credits are successful P2P transfers into wallets.": [
+ ""
+ ],
+ "Failed to load the transfer list.": [
+ ""
+ ],
+ "Select transaction type": [
+ "Sélectionner le type de transaction"
+ ],
+ "Please select a transaction type to show transactions.": [
+ "Veuillez sélectionner un type de transaction pour afficher les transactions."
+ ],
+ "No transfers yet.": [
+ "Aucun transfert pour l'instant."
+ ],
+ "There are no transfers for this account.": [
+ "Il n'y a aucun transfert pour ce compte."
+ ],
+ "There are no transfers reported to the exchange with the current threshold.": [
+ "Il n'y a aucun transfert signalé à l'exchange avec le seuil actuel."
+ ],
+ "Unknown date": [
+ ""
+ ],
+ "Time": [
+ ""
+ ],
+ "Amount": [
+ "Montant"
+ ],
+ "Unknown time": [
+ ""
+ ],
+ "sent": [
+ "envoyé"
+ ],
+ "received": [
+ "reçu"
+ ],
+ "to": [
+ "à"
+ ],
+ "from": [
+ "de"
+ ],
+ "This exchange is not compatible with the AML WebUI.": [
+ "Cet exchange n’est pas compatible avec l’interface Web AML."
+ ],
+ "Officer identity and permissions require exchange protocol v40 or newer.": [
+ "L’identité et les autorisations de l’agent nécessitent le protocole d’exchange v40 ou une version ultérieure."
+ ],
+ "Verifying that this public key is enrolled by the exchange.": [
+ "Vérification de l’inscription de cette clé publique auprès de l’exchange."
+ ],
+ "Read-only officer access": [
+ "Accès d’agent en lecture seule"
+ ],
+ "You can review AML information, but this officer key cannot submit decisions.": [
+ "Vous pouvez consulter les informations AML, mais cette clé d’agent ne peut pas soumettre de décisions."
+ ],
+ "This officer key cannot create or submit AML decisions.": [
+ "Cette clé d’agent ne peut pas créer ni soumettre de décisions AML."
+ ],
+ "Return to account": [
+ "Revenir au compte"
+ ],
+ "Failed to load the active AML decision.": [
+ "Impossible de charger la décision AML active."
+ ],
+ "The account was not found.": [
+ "Le compte est introuvable."
+ ],
+ "The account state changed. Reload it and try again.": [
+ "L’état du compte a changé. Rechargez-le et réessayez."
+ ],
+ "The payto URI does not belong to this account. Return to the account search and start the decision again.": [
+ "L’URI payto n’appartient pas à ce compte. Revenez à la recherche de comptes et recommencez la décision."
+ ],
+ "Session": [
+ "Session"
+ ],
+ "AML navigation": [
+ "Navigation AML"
+ ],
+ "Measures": [
+ "Mesures"
+ ],
+ "threshold\u0004%1$s every %2$s": [
+ "%1$s tous les %2$s"
+ ],
+ "operation type\u0004Withdraw": [
+ "Retrait"
+ ],
+ "operation type\u0004Deposit": [
+ "Dépôt"
+ ],
+ "operation type\u0004Merge": [
+ "Fusion"
+ ],
+ "operation type\u0004Aggregate": [
+ "Agrégation"
+ ],
+ "operation type\u0004Balance": [
+ "Solde"
+ ],
+ "operation type\u0004Refund": [
+ "Remboursement"
+ ],
+ "operation type\u0004Close": [
+ "Fermer"
+ ],
+ "operation type\u0004Transaction": [
+ "Transaction"
+ ]
+ }
+ },
+ "domain": "messages",
+ "plural_forms": "",
+ "lang": "fr",
+ "completeness": 60
+};
+
+strings['es'] = {
+ "locale_data": {
+ "messages": {
+ "": {
+ "domain": "messages",
+ "lang": "es",
+ "plural_forms": ""
+ },
+ "Allow Insecure password": [
+ "Permitir contraseña insegura"
+ ],
+ "Keep session after reload": [
+ "Mantener la sesión después de recargar"
+ ],
+ "Don't compress request": [
+ "No comprimir la solicitud"
+ ],
+ "Lock session": [
+ "Bloquear sesión"
+ ],
+ "Lock": [
+ "Bloquear"
+ ],
+ "Password": [
+ "Contraseña"
+ ],
+ "Required": [
+ "Requerido"
+ ],
+ "should have at least 12 characters": [
+ "debe tener al menos 12 caracteres"
+ ],
+ "should have lowercase and uppercase characters": [
+ "debe tener letras minúsculas y mayúsculas"
+ ],
+ "should have numbers": [
+ "debe tener números"
+ ],
+ "should have at least one character which is not a number or letter": [
+ "debe tener al menos un carácter que no sea un número o una letra"
+ ],
+ "Repeat password": [
+ "Repetir contraseña"
+ ],
+ "doesn't match": [
+ "no coincide"
+ ],
+ "Create": [
+ "Crear"
+ ],
+ "Wallet account": [
+ "Cuenta de cartera"
+ ],
+ "Bank account": [
+ "Cuenta bancaria"
+ ],
+ "Under investigation": [
+ "Bajo investigación"
+ ],
+ "High risk": [
+ "Alto riesgo"
+ ],
+ "Payment target type": [
+ ""
+ ],
+ "Account holder": [
+ "Titular de la cuenta"
+ ],
+ "IBAN": [
+ "IBAN"
+ ],
+ "BIC": [
+ ""
+ ],
+ "Bank": [
+ ""
+ ],
+ "Account": [
+ "Cuenta"
+ ],
+ "Taler bank": [
+ "Banco Taler"
+ ],
+ "Cyclos": [
+ ""
+ ],
+ "Bitcoin address": [
+ ""
+ ],
+ "Reserve public key": [
+ ""
+ ],
+ "Bitcoin": [
+ ""
+ ],
+ "Ethereum address": [
+ ""
+ ],
+ "Ethereum": [
+ ""
+ ],
+ "Exchange": [
+ ""
+ ],
+ "Taler reserve": [
+ "Reserva de Taler"
+ ],
+ "Taler reserve (HTTP)": [
+ ""
+ ],
+ "Test account": [
+ "Cuenta de prueba"
+ ],
+ "Account details unavailable": [
+ ""
+ ],
+ "Not opened": [
+ "No abierto"
+ ],
+ "Opened:": [
+ "Abierto:"
+ ],
+ "Closed:": [
+ "Cerrado:"
+ ],
+ "Closed": [
+ "Cerrado"
+ ],
+ "Open": [
+ "Abierto"
+ ],
+ "No note": [
+ "Sin nota"
+ ],
+ "Show full note": [
+ "Mostrar la nota completa"
+ ],
+ "System information": [
+ "Información del sistema"
+ ],
+ "Transactions remain below the threshold that opens an AML file.": [
+ "Las transacciones siguen por debajo del umbral que abre un expediente de AML."
+ ],
+ "Account case": [
+ "Caso de cuenta"
+ ],
+ "Failed to download AML file.": [
+ "No se pudo descargar el archivo AML."
+ ],
+ "No AML file is available for this account.": [
+ "No hay ningún archivo AML disponible para esta cuenta."
+ ],
+ "Authorization denied for this session. Contact the administrator.": [
+ "Autorización denegada para esta sesión. Póngase en contacto con el administrador."
+ ],
+ "The account or session was not found.": [
+ "No se encontró la cuenta o la sesión."
+ ],
+ "The session is disabled. Contact the administrator.": [
+ "La sesión está deshabilitada. Póngase en contacto con el administrador."
+ ],
+ "The exchange does not support PDF reports.": [
+ "El Exchange no admite informes PDF."
+ ],
+ "Read-only officers cannot create AML decisions.": [
+ "Los responsables con acceso de solo lectura no pueden crear decisiones de AML."
+ ],
+ "A payto URI is required to create a new decision.": [
+ "Se requiere un URI payto para crear una nueva decisión."
+ ],
+ "Back to accounts": [
+ "Volver a las cuentas"
+ ],
+ "File no. %1$s": [
+ "Expediente n.º %1$s"
+ ],
+ "New decision": [
+ "Nueva decisión"
+ ],
+ "Download AML file (PDF)": [
+ "Descargar archivo AML (PDF)"
+ ],
+ "AML file download started.": [
+ "Se ha iniciado la descarga del archivo AML."
+ ],
+ "Try again": [
+ ""
+ ],
+ "Account identifiers": [
+ "Identificadores de la cuenta"
+ ],
+ "Technical identifiers": [
+ "Identificadores técnicos"
+ ],
+ "Full payto URI": [
+ "URI payto completo"
+ ],
+ "Unavailable": [
+ "No disponible"
+ ],
+ "Copy payto URI": [
+ "Copiar URI payto"
+ ],
+ "Normalized payto hash": [
+ "Hash payto normalizado"
+ ],
+ "Copy normalized payto hash": [
+ "Copiar hash payto normalizado"
+ ],
+ "Account case views": [
+ "Vistas del caso de la cuenta"
+ ],
+ "Overview": [
+ "Resumen"
+ ],
+ "Transfers": [
+ "Transferencias"
+ ],
+ "Decision history": [
+ "Historial de decisiones"
+ ],
+ "Close": [
+ "Cerrar"
+ ],
+ "Cancel": [
+ "Cancelar"
+ ],
+ "AML officer enrollment request": [
+ "Solicitud de registro de oficial de AML"
+ ],
+ "Please enroll this AML officer public key:\n\n%1$s": [
+ "Registre esta clave pública del oficial de AML:\n\n%1$s"
+ ],
+ "Officer key awaiting enrollment": [
+ "Clave del oficial de AML pendiente de registro"
+ ],
+ "This browser has created an AML officer key, but the exchange has not granted it access. Ask the exchange operator or administrator to enroll the public key below.": [
+ "Este navegador ha creado una clave de oficial de AML, pero el exchange no le ha concedido acceso. Pida al operador o administrador del exchange que registre la clave pública que aparece a continuación."
+ ],
+ "AML officer public key": [
+ "Clave pública del oficial de AML"
+ ],
+ "Copy AML officer public key": [
+ "Copiar la clave pública del agente AML"
+ ],
+ "After the operator confirms enrollment, retry the access check.": [
+ "Una vez que el operador confirme el registro, vuelva a comprobar el acceso."
+ ],
+ "Retry access check": [
+ "Volver a comprobar el acceso"
+ ],
+ "Checking officer access": [
+ "Comprobando el acceso del oficial de AML"
+ ],
+ "Last checked at %1$s": [
+ "Última comprobación a las %1$s"
+ ],
+ "Request enrollment": [
+ "Solicitar registro"
+ ],
+ "Discard this key": [
+ "Descartar esta clave"
+ ],
+ "Confirmation required": [
+ "Confirmación requerida"
+ ],
+ "Discarding this key removes the officer session from this browser. You will need to create a new key to use the AML WebUI again.": [
+ "Al descartar esta clave, se elimina de este navegador la sesión del oficial de AML. Deberá crear una clave nueva para volver a utilizar la interfaz web de AML."
+ ],
+ "Failed to check AML officer access.": [
+ "No se pudo comprobar el acceso del responsable de AML."
+ ],
+ "This officer key cannot authenticate with the exchange. Retry the check or discard the key and create a new session.": [
+ "Esta clave de responsable no puede autenticarse en el exchange. Vuelva a intentar la comprobación o descarte la clave y cree una sesión nueva."
+ ],
+ "The exchange rejected the officer access check.": [
+ "El exchange rechazó la comprobación de acceso del responsable."
+ ],
+ "Technical details": [
+ "Detalles técnicos"
+ ],
+ "Failed to unlock the session.": [
+ ""
+ ],
+ "Unlock": [
+ "Desbloquear"
+ ],
+ "Forget session": [
+ "Olvidar sesión"
+ ],
+ "There are no rules for operations": [
+ "No hay reglas para las operaciones"
+ ],
+ "This means that no operation has any limit.": [
+ "Esto significa que ninguna operación tiene límites."
+ ],
+ "Operation": [
+ "Operación"
+ ],
+ "Threshold": [
+ "Umbral"
+ ],
+ "Escalation": [
+ "Escalamiento"
+ ],
+ "Visibility": [
+ "Visibilidad"
+ ],
+ "Priority": [
+ "Prioridad"
+ ],
+ "Actions": [
+ "Acciones"
+ ],
+ "Block operation": [
+ "Bloquear operación"
+ ],
+ "All required:": [
+ "Todas obligatorias:"
+ ],
+ "Any one:": [
+ "Cualquiera:"
+ ],
+ "Customer-visible": [
+ "Visible para el cliente"
+ ],
+ "Internal": [
+ "Interno"
+ ],
+ "Move %1$s rule up": [
+ "Subir la regla %1$s"
+ ],
+ "Move %1$s rule down": [
+ "Bajar la regla %1$s"
+ ],
+ "Edit %1$s rule": [
+ "Editar la regla %1$s"
+ ],
+ "Remove %1$s rule": [
+ "Eliminar la regla %1$s"
+ ],
+ "AML officer justification": [
+ "Justificación del oficial de AML"
+ ],
+ "No justification was recorded.": [
+ "No se registró ninguna justificación."
+ ],
+ "Operation rules": [
+ "Reglas de operación"
+ ],
+ "Decision date": [
+ "Fecha de la decisión"
+ ],
+ "Expired": [
+ "Vencido"
+ ],
+ "Expires": [
+ "Vence"
+ ],
+ "Successor measure": [
+ "Medida sucesora"
+ ],
+ "Exchange defaults": [
+ "Valores predeterminados del Exchange"
+ ],
+ "Forms": [
+ "Formularios"
+ ],
+ "Measures used to gather information about the customer.": [
+ "Medidas utilizadas para recopilar información sobre el cliente."
+ ],
+ "Select": [
+ "Seleccionar"
+ ],
+ "Name": [
+ "Nombre"
+ ],
+ "Check": [
+ "Verificar"
+ ],
+ "Program": [
+ "Programa"
+ ],
+ "Context": [
+ "Contexto"
+ ],
+ "Modify": [
+ "Modificar"
+ ],
+ "Instant measures": [
+ "Medidas instantáneas"
+ ],
+ "Triggered immediately without customer interaction.": [
+ "Se activan de inmediato sin interacción del cliente."
+ ],
+ "Input requirement": [
+ "Requisito de entrada"
+ ],
+ "Started": [
+ "Iniciado"
+ ],
+ "Status": [
+ "Estado"
+ ],
+ "Forbidden": [
+ "Prohibido"
+ ],
+ "Completed": [
+ "Completado"
+ ],
+ "Waiting for customer": [
+ "Esperando al cliente"
+ ],
+ "The operation is categorically forbidden by this requirement.": [
+ "Esta exigencia prohíbe categóricamente la operación."
+ ],
+ "All listed measures must be completed.": [
+ "Deben completarse todas las medidas indicadas."
+ ],
+ "Any one listed measure may be completed.": [
+ "Puede completarse cualquiera de las medidas indicadas."
+ ],
+ "Values may be derived from the selected AML/KYC form. Confirm them against the case record and change only values that require an officer override.": [
+ ""
+ ],
+ "Invalid custom properties": [
+ "Propiedades personalizadas no válidas"
+ ],
+ "Custom property names and values must be non-empty and names must be unique and different from built-in properties.": [
+ "Los nombres y valores de las propiedades personalizadas no pueden estar vacíos; los nombres deben ser únicos y diferentes de las propiedades integradas."
+ ],
+ "Properties": [
+ "Propiedades"
+ ],
+ "Built-in property names are preserved when the decision is submitted.": [
+ ""
+ ],
+ "Custom properties": [
+ "Propiedades personalizadas"
+ ],
+ "Add more properties that are not listed above.": [
+ "Añade más propiedades que no estén listadas arriba."
+ ],
+ "New properties": [
+ "Nuevas propiedades"
+ ],
+ "Value": [
+ "Valor"
+ ],
+ "Current note on the GwG file": [
+ "Nota actual del expediente GwG"
+ ],
+ "Customer name or internal alias.": [
+ "Nombre del cliente o alias interno."
+ ],
+ "Is the account active for deposit and payments?": [
+ "¿Está la cuenta activa para depósitos y pagos?"
+ ],
+ "Is the account idle?": [
+ "¿Está la cuenta inactiva?"
+ ],
+ "No operation for a period of time": [
+ "Sin operaciones durante un período de tiempo"
+ ],
+ "Does account belong to a domestic PEP?": [
+ "¿Pertenece la cuenta a un PEP nacional?"
+ ],
+ "Does account belong to a foreign PEP?": [
+ "¿Pertenece la cuenta a un PEP extranjero?"
+ ],
+ "Does account belong to an international-organization PEP?": [
+ "¿Pertenece la cuenta a un PEP de organización internacional?"
+ ],
+ "Does account belong to a high risk customer?": [
+ "¿Pertenece la cuenta a un cliente de alto riesgo?"
+ ],
+ "Does account belong to a person from a high risk country?": [
+ "¿Pertenece la cuenta a una persona de un país de alto riesgo?"
+ ],
+ "The MROS reporting state for the account.": [
+ "El estado de informe MROS de la cuenta."
+ ],
+ "None": [
+ "Ninguno"
+ ],
+ "Pending investigation": [
+ "Investigación pendiente"
+ ],
+ "Investigated without suspicion": [
+ "Investigado sin sospecha"
+ ],
+ "Reported simple suspicion": [
+ "Sospecha simple informada"
+ ],
+ "Reported substantiated suspicion": [
+ "Sospecha fundamentada informada"
+ ],
+ "Informal reason why the AML investigation was triggered": [
+ "Motivo informal por el que se activó la investigación de AML"
+ ],
+ "Identifies the sanction list entry that the account matched against": [
+ "Identifica la entrada de la lista de sanciones con la que coincidió la cuenta"
+ ],
+ "Best match, does not mean it was a good match.": [
+ "Mejor coincidencia, no significa que fue una buena coincidencia."
+ ],
+ "Score for how good the sanction list match was": [
+ "Puntaje de qué tan buena fue la coincidencia con la lista de sanciones"
+ ],
+ "Integer score from 0 (no match) to 1,000,000,000 (best match).": [
+ ""
+ ],
+ "Score for how much supporting data we had for the sanction list match": [
+ "Puntaje de cuántos datos de respaldo teníamos para la coincidencia con la lista de sanciones"
+ ],
+ "Integer score from 0 (no supporting data) to 1,000,000,000 (highest confidence).": [
+ ""
+ ],
+ "Suppress flagging this account when it creates a hit on a sanctions list, this is a false-positive": [
+ "Suprimir la marcación de esta cuenta cuando genera una coincidencia en una lista de sanciones; es un falso positivo"
+ ],
+ "Expiration shortcuts": [
+ "Atajos de caducidad"
+ ],
+ "In a week": [
+ "En una semana"
+ ],
+ "In a month": [
+ "En un mes"
+ ],
+ "In a year": [
+ "En un año"
+ ],
+ "Never": [
+ "Nunca"
+ ],
+ "Failed to load available measures.": [
+ "No se pudieron cargar las medidas disponibles."
+ ],
+ "The officer session is invalid.": [
+ "La sesión del responsable de AML no es válida."
+ ],
+ "The measures endpoint was not found.": [
+ "No se encontró el punto de acceso de las medidas."
+ ],
+ "The officer session is disabled.": [
+ "La sesión del responsable de AML está deshabilitada."
+ ],
+ "Edit proposed rule": [
+ "Editar regla propuesta"
+ ],
+ "Add proposed rule": [
+ "Añadir regla propuesta"
+ ],
+ "Save rule": [
+ "Guardar regla"
+ ],
+ "Add rule": [
+ "Añadir regla"
+ ],
+ "This complete rule set replaces the currently applied rules and exchange defaults until it expires. Higher rows take precedence.": [
+ "Este conjunto completo de reglas sustituye las reglas aplicadas actualmente y las predeterminadas del intercambio hasta que caduque. Las filas superiores tienen prioridad."
+ ],
+ "Rules for another account type": [
+ "Reglas para otro tipo de cuenta"
+ ],
+ "These operations do not apply to this account type: %1$s.": [
+ "Estas operaciones no se aplican a este tipo de cuenta: %1$s."
+ ],
+ "Operations without limits": [
+ "Operaciones sin límites"
+ ],
+ "No proposed rule limits these operations: %1$s.": [
+ "Ninguna regla propuesta limita estas operaciones: %1$s."
+ ],
+ "Invalid proposed rules": [
+ "Reglas propuestas no válidas"
+ ],
+ "Edit the highlighted rule set before continuing. Hard blocks cannot be combined with measures, and Balance and Refund rules must use an instant timeframe.": [
+ "Edite el conjunto de reglas resaltado antes de continuar. Los bloqueos estrictos no pueden combinarse con medidas, y las reglas de saldo y reembolso deben usar un período instantáneo."
+ ],
+ "Remove proposed rule?": [
+ "¿Eliminar la regla propuesta?"
+ ],
+ "This is the final rule. Removing it leaves every applicable operation unlimited.": [
+ "Esta es la última regla. Al eliminarla, todas las operaciones aplicables quedarán sin límite."
+ ],
+ "The rule will be removed from the proposed set.": [
+ "La regla se eliminará del conjunto propuesto."
+ ],
+ "Keep rule": [
+ "Conservar regla"
+ ],
+ "Remove rule": [
+ "Eliminar regla"
+ ],
+ "Replace proposed rules": [
+ "Sustituir reglas propuestas"
+ ],
+ "Preview a complete replacement before applying it.": [
+ "Previsualice la sustitución completa antes de aplicarla."
+ ],
+ "Currently applied": [
+ "Aplicadas actualmente"
+ ],
+ "E-commerce": [
+ "Comercio electrónico"
+ ],
+ "Point of Sale": [
+ "Punto de venta"
+ ],
+ "Basic plan": [
+ "Plan básico"
+ ],
+ "Premium": [
+ "Premium"
+ ],
+ "Freeze account": [
+ "Congelar cuenta"
+ ],
+ "Replacement preview": [
+ "Vista previa de la sustitución"
+ ],
+ "Confirm account freeze": [
+ "Confirmar bloqueo de la cuenta"
+ ],
+ "Every applicable operation will receive a zero hard limit.": [
+ "Cada operación aplicable recibirá un límite estricto de cero."
+ ],
+ "Apply replacement": [
+ "Aplicar sustitución"
+ ],
+ "Choose how long the proposed rules apply and what happens afterwards.": [
+ "Elija cuánto tiempo se aplican las reglas propuestas y qué sucede después."
+ ],
+ "The proposed rules never expire, so no successor action will run.": [
+ "Las reglas propuestas no caducan, por lo que no se ejecutará ninguna acción posterior."
+ ],
+ "Restore currently applied expiration": [
+ "Restaurar la caducidad aplicada actualmente"
+ ],
+ "Operation type": [
+ "Tipo de operación"
+ ],
+ "Timeframe": [
+ "Marco temporal"
+ ],
+ "Use Y, M, D, h, m or s after each number. Forever accumulates over the account's full history.": [
+ "Use Y, M, D, h, m o s después de cada número. «Para siempre» acumula todo el historial de la cuenta."
+ ],
+ "Instant timeframe": [
+ "Período instantáneo"
+ ],
+ "Balance and Refund limits apply to one balance or transaction, so their timeframe is fixed to zero.": [
+ "Los límites de saldo y reembolso se aplican a un saldo o una transacción, por lo que su período se fija en cero."
+ ],
+ "Exposed": [
+ "Expuesto"
+ ],
+ "Is this limit communicated to the customer?": [
+ "¿Se comunica este límite al cliente?"
+ ],
+ "When the threshold is crossed": [
+ "Cuando se supera el umbral"
+ ],
+ "Require measures": [
+ "Exigir medidas"
+ ],
+ "Required measures": [
+ "Medidas obligatorias"
+ ],
+ "Measures that the customer will need to satisfy to apply for a new threshold.": [
+ "Medidas que el cliente deberá cumplir para solicitar un nuevo umbral."
+ ],
+ "All measures": [
+ "Todas las medidas"
+ ],
+ "Hint the customer that all measures should be completed": [
+ "Indicar al cliente que debe completar todas las medidas"
+ ],
+ "Expiration date": [
+ "Fecha de vencimiento"
+ ],
+ "Until when are the new rules active.": [
+ "Hasta cuándo estarán activas las nuevas reglas."
+ ],
+ "Choose a future expiration date or Never.": [
+ "Elija una fecha de caducidad futura o «Nunca»."
+ ],
+ "After expiration": [
+ "Después de la caducidad"
+ ],
+ "Return to exchange defaults": [
+ "Volver a los valores predeterminados del intercambio"
+ ],
+ "Trigger a successor measure": [
+ "Activar una medida sucesora"
+ ],
+ "Measure taken automatically upon expiration of the current decision.": [
+ "Medida tomada automáticamente al vencer la decisión actual."
+ ],
+ "This successor measure is no longer available.": [
+ "Esta medida sucesora ya no está disponible."
+ ],
+ "Case summary": [
+ "Resumen del caso"
+ ],
+ "Current review state and the latest account activity.": [
+ "Estado actual de la revisión y actividad más reciente de la cuenta."
+ ],
+ "Review status": [
+ "Estado de revisión"
+ ],
+ "Loading…": [
+ "Cargando…"
+ ],
+ "Manual review required — waiting for an AML decision.": [
+ "Se requiere una revisión manual: a la espera de una decisión AML."
+ ],
+ "No manual review": [
+ "Sin revisión manual"
+ ],
+ "Effective decision": [
+ "Decisión vigente"
+ ],
+ "Requirements": [
+ "Requisitos"
+ ],
+ "Latest collected information": [
+ "Última información recopilada"
+ ],
+ "Effective policy": [
+ "Política vigente"
+ ],
+ "The AML decision and operation rules currently applied to this account.": [
+ "La decisión AML y las reglas de operación que se aplican actualmente a esta cuenta."
+ ],
+ "Effective policy could not be loaded": [
+ "No se pudo cargar la política vigente"
+ ],
+ "Exchange defaults apply": [
+ "Se aplican los valores predeterminados del Exchange"
+ ],
+ "No AML officer decision is active for this account.": [
+ "No hay ninguna decisión activa de un agente AML para esta cuenta."
+ ],
+ "Account type unavailable": [
+ "Tipo de cuenta no disponible"
+ ],
+ "Open this case from the account directory or payto search to see the applicable default rules.": [
+ "Abra este caso desde el directorio de cuentas o la búsqueda payto para ver las reglas predeterminadas aplicables."
+ ],
+ "Default rules could not be loaded": [
+ "No se pudieron cargar las reglas predeterminadas"
+ ],
+ "Default rules": [
+ "Reglas predeterminadas"
+ ],
+ "Account assessment": [
+ "Evaluación de la cuenta"
+ ],
+ "Properties recorded by AML officers for this account.": [
+ "Propiedades registradas por agentes AML para esta cuenta."
+ ],
+ "Account assessment could not be loaded": [
+ "No se pudo cargar la evaluación de la cuenta"
+ ],
+ "Collected information": [
+ "Información recopilada"
+ ],
+ "KYC information filed by the customer or an AML officer.": [
+ "Información KYC presentada por el cliente o un agente AML."
+ ],
+ "Collected information could not be loaded": [
+ "No se pudo cargar la información recopilada"
+ ],
+ "No collected information": [
+ "Sin información recopilada"
+ ],
+ "No KYC information has been collected for this account.": [
+ "No se ha recopilado información KYC para esta cuenta."
+ ],
+ "Active requirements": [
+ "Requisitos activos"
+ ],
+ "Measures the customer must complete under the current policy.": [
+ "Medidas que el cliente debe completar según la política actual."
+ ],
+ "Active requirements could not be loaded": [
+ "No se pudieron cargar los requisitos activos"
+ ],
+ "No active requirements": [
+ "Sin requisitos activos"
+ ],
+ "The customer has no active legitimization measures to complete.": [
+ "El cliente no tiene medidas de legitimación activas que completar."
+ ],
+ "Officer decision": [
+ "Decisión del agente"
+ ],
+ "Does not expire": [
+ "No caduca"
+ ],
+ "Waiting": [
+ "En espera"
+ ],
+ "More on later pages": [
+ "Hay más en las páginas siguientes"
+ ],
+ "Try loading this section again.": [
+ "Intente cargar esta sección de nuevo."
+ ],
+ "Retry": [
+ "Reintentar"
+ ],
+ "No account properties": [
+ "Sin propiedades de cuenta"
+ ],
+ "No assessment properties have been recorded for this account.": [
+ "No se han registrado propiedades de evaluación para esta cuenta."
+ ],
+ "Yes": [
+ "Sí"
+ ],
+ "No": [
+ "No"
+ ],
+ "Unconfigured form": [
+ "Formulario no configurado"
+ ],
+ "Form not identified": [
+ "Formulario no identificado"
+ ],
+ "Filed by an AML officer": [
+ "Presentado por un agente AML"
+ ],
+ "Provided by the customer": [
+ "Proporcionado por el cliente"
+ ],
+ "Attribute data is unavailable.": [
+ "Los datos de atributos no están disponibles."
+ ],
+ "View details": [
+ "Ver detalles"
+ ],
+ "Review superseded AML decisions for this account, from newest to oldest.": [
+ "Revisar las decisiones AML sustituidas de esta cuenta, de la más reciente a la más antigua."
+ ],
+ "Loading decision history…": [
+ "Cargando el historial de decisiones…"
+ ],
+ "Decision history could not be loaded": [
+ "No se pudo cargar el historial de decisiones"
+ ],
+ "Try loading the decision history again.": [
+ "Intente cargar de nuevo el historial de decisiones."
+ ],
+ "No previous decisions": [
+ "Sin decisiones anteriores"
+ ],
+ "No superseded AML decisions have been recorded for this account.": [
+ "No se han registrado decisiones AML sustituidas para esta cuenta."
+ ],
+ "Previous decisions": [
+ "Decisiones anteriores"
+ ],
+ "The export could not be prepared. Try again.": [
+ "No se pudo preparar la exportación. Inténtelo de nuevo."
+ ],
+ "Failed to load accounts": [
+ "No se pudieron cargar las cuentas"
+ ],
+ "Accounts": [
+ "Cuentas"
+ ],
+ "Review accounts known to the exchange for AML and KYC handling.": [
+ "Revise las cuentas conocidas por el exchange para la gestión de AML y KYC."
+ ],
+ "Export filtered accounts": [
+ "Exportar las cuentas filtradas"
+ ],
+ "Download CSV": [
+ "Descargar CSV"
+ ],
+ "Download Excel": [
+ "Descargar Excel"
+ ],
+ "Preparing export…": [
+ "Preparando la exportación…"
+ ],
+ "Export failed": [
+ "La exportación ha fallado"
+ ],
+ "Account filters": [
+ "Filtros de cuentas"
+ ],
+ "Investigation": [
+ "Investigación"
+ ],
+ "All accounts": [
+ "Todas las cuentas"
+ ],
+ "Not under investigation": [
+ "No está bajo investigación"
+ ],
+ "Risk": [
+ "Riesgo"
+ ],
+ "All risk levels": [
+ "Todos los niveles de riesgo"
+ ],
+ "Not high risk": [
+ "Sin alto riesgo"
+ ],
+ "File status": [
+ "Estado del expediente"
+ ],
+ "All file statuses": [
+ "Todos los estados del expediente"
+ ],
+ "Not open": [
+ "No abierto"
+ ],
+ "Clear filters": [
+ "Borrar filtros"
+ ],
+ "Showing %1$s accounts · newest first": [
+ "Se muestran %1$s cuentas · las más recientes primero"
+ ],
+ "AML and KYC accounts": [
+ "Cuentas de AML y KYC"
+ ],
+ "Account lifecycle": [
+ "Ciclo de vida del expediente"
+ ],
+ "Latest note": [
+ "Nota más reciente"
+ ],
+ "Copied": [
+ "Copiado"
+ ],
+ "Copy": [
+ "Copiar"
+ ],
+ "No matching accounts": [
+ "No hay cuentas coincidentes"
+ ],
+ "No accounts yet": [
+ "Aún no hay cuentas"
+ ],
+ "No accounts match the selected filters.": [
+ "Ninguna cuenta coincide con los filtros seleccionados."
+ ],
+ "The exchange has not recorded any AML or KYC accounts yet.": [
+ "El exchange aún no ha registrado ninguna cuenta de AML o KYC."
+ ],
+ "This officer session is not authorized to list accounts.": [
+ "Esta sesión de agente no está autorizada para listar cuentas."
+ ],
+ "The exchange does not recognize this officer session.": [
+ "El exchange no reconoce esta sesión de agente."
+ ],
+ "This officer session is currently disabled.": [
+ "Esta sesión de agente está deshabilitada actualmente."
+ ],
+ "There are no matching accounts to export.": [
+ "No hay cuentas coincidentes para exportar."
+ ],
+ "The exchange does not support the selected export format.": [
+ "El exchange no admite el formato de exportación seleccionado."
+ ],
+ "This officer session is not authorized to export accounts.": [
+ "Esta sesión de agente no está autorizada para exportar cuentas."
+ ],
+ "Dashboard": [
+ "Panel"
+ ],
+ "Review cases requiring attention, investigate accounts, and monitor AML reporting indicators.": [
+ ""
+ ],
+ "Review case queue": [
+ ""
+ ],
+ "Find credit, debit, and KYC authorization activity.": [
+ ""
+ ],
+ "Statistics": [
+ "Estadísticas"
+ ],
+ "No reporting profile for this dialect": [
+ ""
+ ],
+ "The testing dialect does not define dashboard statistics. Select TOPS in development settings to inspect the TOPS reporting profile.": [
+ ""
+ ],
+ "Failed to load TOPS statistics.": [
+ ""
+ ],
+ "The available values are shown below. Missing values are not zero.": [
+ ""
+ ],
+ "Accounts open": [
+ "Cuentas abiertas"
+ ],
+ "New files last year": [
+ "Expedientes nuevos el año pasado"
+ ],
+ "Closed files last year": [
+ "Expedientes cerrados el año pasado"
+ ],
+ "MROS substantiated": [
+ "MROS fundamentados"
+ ],
+ "MROS simple": [
+ "MROS simples"
+ ],
+ "High risk files": [
+ "Expedientes de alto riesgo"
+ ],
+ "PEP files": [
+ "Expedientes PEP"
+ ],
+ "Number of accounts that are opened": [
+ "Número de cuentas abiertas"
+ ],
+ "Number of new GwG files in the last year": [
+ "Número de expedientes GwG nuevos en el último año"
+ ],
+ "Number of GwG files closed in the last year": [
+ "Número de expedientes GwG cerrados en el último año"
+ ],
+ "Number of MROS reports based on Art 9 Abs. 1 GwG (per year)": [
+ "Número de informes MROS basados en el Art. 9 Abs. 1 GwG (por año)"
+ ],
+ "Number of MROS reports based on Art 305ter Abs. 2 StGB (per year)": [
+ "Número de informes MROS basados en el Art. 305ter Abs. 2 StGB (por año)"
+ ],
+ "Number of GwG files of high-risk customers": [
+ "Número de expedientes GwG de clientes de alto riesgo"
+ ],
+ "Number of GwG files managed with “increased risk” due to PEP status": [
+ "Número de expedientes GwG gestionados con «riesgo incrementado» debido al estado de PEP"
+ ],
+ "previous": [
+ "anterior"
+ ],
+ "Decreased by": [
+ "Disminuyó en"
+ ],
+ "Increased by": [
+ "Aumentó en"
+ ],
+ "The built-in event selection differs from the events derived from the proposed account state.": [
+ ""
+ ],
+ "Built-in events are derived from changes to the proposed account properties. They are stored for reporting and statistics; they do not notify the customer.": [
+ ""
+ ],
+ "Calculated": [
+ "Calculado"
+ ],
+ "Events derived from proposed property changes and submitted information.": [
+ ""
+ ],
+ "Other built-in events": [
+ ""
+ ],
+ "Operator-defined event names that are not part of the selected dialect.": [
+ ""
+ ],
+ "The completed form is attached to this AML decision as reviewed account information. It does not create a customer-facing measure.": [
+ ""
+ ],
+ "Expiration": [
+ "Vencimiento"
+ ],
+ "Expiration date of the information filled in this form.": [
+ "Fecha de vencimiento de la información completada en este formulario."
+ ],
+ "Only change this operator-defined JSON when the form documentation requires additional context.": [
+ ""
+ ],
+ "Invalid expiration": [
+ "Caducidad no válida"
+ ],
+ "Attributes require an expiration date in the future or set to Never.": [
+ "Los atributos requieren una fecha de caducidad futura o deben configurarse como «Nunca»."
+ ],
+ "Include new information": [
+ "Incluir nueva información"
+ ],
+ "This step is optional. Select a form to attach newly reviewed AML/KYC information, or continue without one.": [
+ ""
+ ],
+ "AML/KYC form": [
+ ""
+ ],
+ "Search AML/KYC forms": [
+ "Buscar formularios AML/KYC"
+ ],
+ "Full name used in the payto URI when creating this previously unknown account.": [
+ ""
+ ],
+ "Record the facts and reasoning needed to understand this decision in a later audit or review.": [
+ ""
+ ],
+ "Combine a customer check with an AML program, or use SKIP to run a program immediately. Context values must satisfy the selected check and program requirements.": [
+ ""
+ ],
+ "Add custom measure": [
+ "Añadir medida personalizada"
+ ],
+ "Save changes": [
+ ""
+ ],
+ "Use advanced measure editor": [
+ ""
+ ],
+ "There is already a measure with that name": [
+ "Ya existe una medida con ese nombre"
+ ],
+ "Runs immediately for SKIP measures, or after a successful check. It may be omitted for a check that only presents or collects information.": [
+ ""
+ ],
+ "Missing check or program": [
+ "Falta la verificación o el programa"
+ ],
+ "The customer-facing check to perform before the program. Leave empty to use SKIP and run the program immediately.": [
+ ""
+ ],
+ "Configuration values required by the selected check or program. Property names and value types must match the exchange configuration.": [
+ ""
+ ],
+ "Field name": [
+ "Nombre del campo"
+ ],
+ "Type": [
+ "Tipo"
+ ],
+ "string": [
+ "cadena"
+ ],
+ "number": [
+ "número"
+ ],
+ "boolean": [
+ "booleano"
+ ],
+ "json": [
+ "json"
+ ],
+ "There are unsatisfied inputs: %1$s": [
+ "Hay entradas no satisfechas: %1$s"
+ ],
+ "Check \"%1$s\" is not available": [
+ ""
+ ],
+ "There are missing inputs: %1$s": [
+ "Faltan entradas: %1$s"
+ ],
+ "There are missing requirements: %1$s": [
+ "Faltan requisitos: %1$s"
+ ],
+ "Can't be empty": [
+ "No puede estar vacío"
+ ],
+ "Not a number": [
+ "No es un número"
+ ],
+ "It should be finite": [
+ "Debe ser finito"
+ ],
+ "It should be either \"true\" or \"false\"": [
+ "Debe ser \"true\" o \"false\""
+ ],
+ "Couldn't parse as json string: %1$s": [
+ "No se pudo interpretar como cadena json: %1$s"
+ ],
+ "Description": [
+ "Descripción"
+ ],
+ "Inputs": [
+ "Entradas"
+ ],
+ "Fallback": [
+ "Alternativa"
+ ],
+ "Selected pipeline": [
+ ""
+ ],
+ "Review how the exchange will execute this measure.": [
+ ""
+ ],
+ "Name of the verification measure": [
+ "Nombre de la medida de verificación"
+ ],
+ "Read only": [
+ "Solo lectura"
+ ],
+ "Prevent the customer from changing the address": [
+ "Impedir que el cliente cambie la dirección"
+ ],
+ "Customer actions after submission": [
+ ""
+ ],
+ "Immediate measures start as soon as this decision is accepted. A measure may show information, collect customer data, or run an AML program. Leave the selection empty when no immediate customer action is required.": [
+ ""
+ ],
+ "Too many SKIP measures": [
+ "Demasiadas medidas SKIP"
+ ],
+ "At most one immediate measure may use the SKIP check.": [
+ "Como máximo una medida inmediata puede usar la comprobación SKIP."
+ ],
+ "Custom measures": [
+ "Medidas personalizadas"
+ ],
+ "Measures defined only for this proposed decision.": [
+ ""
+ ],
+ "Edit": [
+ ""
+ ],
+ "Reusable templates configured by the exchange operator": [
+ ""
+ ],
+ "Use as template": [
+ ""
+ ],
+ "Selected measures begin immediately after the decision is accepted by the exchange.": [
+ ""
+ ],
+ "Session not found. Contact the administrator.": [
+ ""
+ ],
+ "The exchange rejected the decision because the officer session is disabled or the account has a newer decision. Reload the account before trying again.": [
+ ""
+ ],
+ "This decision records that an MROS report was filed. Confirm that the report has actually been submitted before continuing.": [
+ ""
+ ],
+ "Confirm decision": [
+ "Confirmar decisión"
+ ],
+ "Unknown measure": [
+ "Medida desconocida"
+ ],
+ "A rule or immediate action references a measure that is not available. Review the rules and measures before submitting.": [
+ "Una regla o acción inmediata hace referencia a una medida que no está disponible. Revise las reglas y las medidas antes de enviar."
+ ],
+ "A custom measure references an unavailable check or program, lacks required context, or cannot provide the selected program inputs. Review the immediate measures before submitting.": [
+ ""
+ ],
+ "Missing deadline": [
+ "Falta el plazo"
+ ],
+ "Set when the proposed rules expire and what should happen afterward.": [
+ ""
+ ],
+ "Invalid rule expiration": [
+ "Caducidad de reglas no válida"
+ ],
+ "Rule expiration must be in the future or set to Never.": [
+ "La caducidad de las reglas debe estar en el futuro o establecerse en «Nunca»."
+ ],
+ "Missing rules": [
+ "Faltan reglas"
+ ],
+ "A decision must contain the complete rule set that will apply to the account.": [
+ ""
+ ],
+ "Review the proposed rules. Hard blocks must be explicit, and Balance and Refund rules must use an instant timeframe.": [
+ "Revise las reglas propuestas. Los bloqueos estrictos deben ser explícitos, y las reglas de saldo y reembolso deben usar un período instantáneo."
+ ],
+ "Immediate measures not reviewed": [
+ ""
+ ],
+ "No measure will start when this decision is submitted.": [
+ ""
+ ],
+ "Review the account properties before submitting the decision.": [
+ ""
+ ],
+ "Reporting events not reviewed": [
+ ""
+ ],
+ "Review which statistical events will be recorded with the decision.": [
+ ""
+ ],
+ "Case disposition incomplete": [
+ ""
+ ],
+ "You must complete the justification section.": [
+ "Debes completar la sección de justificación."
+ ],
+ "Invalid attributes": [
+ "Atributos inválidos"
+ ],
+ "Correct the selected form or continue without attaching new customer information.": [
+ ""
+ ],
+ "Justification": [
+ "Justificación"
+ ],
+ "Events": [
+ "Eventos"
+ ],
+ "All entries made in this decision wizard will be lost. No change will be submitted to the exchange.": [
+ ""
+ ],
+ "Payto URI": [
+ "URI Payto"
+ ],
+ "Decision steps": [
+ ""
+ ],
+ "Account properties": [
+ "Propiedades de la cuenta"
+ ],
+ "Review the account state derived from the available information.": [
+ ""
+ ],
+ "Review the statistical events recorded with this decision.": [
+ ""
+ ],
+ "Set operation thresholds, escalation measures, and expiration behavior.": [
+ ""
+ ],
+ "Case disposition": [
+ ""
+ ],
+ "Check the complete decision before signing and submitting it.": [
+ ""
+ ],
+ "Enter a valid HTTP or HTTPS URL.": [
+ ""
+ ],
+ "Development settings": [
+ "Configuración de desarrollo"
+ ],
+ "These browser-local settings are intended for development and troubleshooting.": [
+ ""
+ ],
+ "Changing the exchange reloads the application. The override is stored only in this browser.": [
+ ""
+ ],
+ "Exchange base URL": [
+ "URL base del exchange"
+ ],
+ "Leave empty to use the configured URL: %1$s": [
+ ""
+ ],
+ "Leave empty to derive the exchange URL from this page.": [
+ ""
+ ],
+ "Currently connected to": [
+ ""
+ ],
+ "Apply and reload": [
+ ""
+ ],
+ "Use configured URL": [
+ ""
+ ],
+ "Preferences": [
+ "Preferencias"
+ ],
+ "AML SPA dialect": [
+ ""
+ ],
+ "Testing": [
+ ""
+ ],
+ "Override how this web interface presents dialect-specific AML rules and properties. The override is stored only in this browser.": [
+ ""
+ ],
+ "Fallback dialect for development and testing.": [
+ ""
+ ],
+ "TOPS": [
+ ""
+ ],
+ "Taler Operations deployment for Swiss AML processes.": [
+ ""
+ ],
+ "File note": [
+ "Nota del expediente"
+ ],
+ "Text": [
+ ""
+ ],
+ "Customer label": [
+ "Etiqueta del cliente"
+ ],
+ "Account open": [
+ "Cuenta abierta"
+ ],
+ "Domestic PEP": [
+ "PEP nacional"
+ ],
+ "Whether the customer is a domestic politically exposed person.": [
+ ""
+ ],
+ "Foreign PEP": [
+ "PEP extranjera"
+ ],
+ "Whether the customer is a foreign politically exposed person.": [
+ ""
+ ],
+ "International-organization PEP": [
+ "PEP de una organización internacional"
+ ],
+ "Whether the customer is a politically exposed person associated with an international organization.": [
+ ""
+ ],
+ "High-risk customer": [
+ "Cliente de alto riesgo"
+ ],
+ "High-risk country": [
+ "País de alto riesgo"
+ ],
+ "Whether the customer is associated with a high-risk country.": [
+ ""
+ ],
+ "Account idle": [
+ "Cuenta inactiva"
+ ],
+ "Whether the account has been marked as idle.": [
+ ""
+ ],
+ "Score from 0 (no match) to 1,000,000,000 (best match).": [
+ ""
+ ],
+ "Score from 0 (no supporting data) to 1,000,000,000 (highest confidence).": [
+ ""
+ ],
+ "Whether this account's sanction-list hit is treated as a false positive.": [
+ ""
+ ],
+ "Recorded when an account changes to open.": [
+ ""
+ ],
+ "Recorded when an account changes from open to closed.": [
+ ""
+ ],
+ "Recorded when an open account becomes classified as a high-risk customer.": [
+ ""
+ ],
+ "Recorded when the high-risk customer classification is removed.": [
+ ""
+ ],
+ "Recorded when an open account becomes associated with a high-risk country.": [
+ ""
+ ],
+ "High-risk country classification removed": [
+ ""
+ ],
+ "Recorded when the high-risk country classification is removed.": [
+ ""
+ ],
+ "PEP classification added": [
+ ""
+ ],
+ "Recorded when an open account becomes associated with any PEP category.": [
+ ""
+ ],
+ "Recorded when the account is no longer associated with any PEP category.": [
+ ""
+ ],
+ "Foreign PEP classification added": [
+ ""
+ ],
+ "Recorded when an open account becomes associated with a foreign PEP.": [
+ ""
+ ],
+ "Foreign PEP classification removed": [
+ ""
+ ],
+ "Recorded when the foreign PEP classification is removed.": [
+ ""
+ ],
+ "Domestic PEP classification added": [
+ ""
+ ],
+ "Recorded when an open account becomes associated with a domestic PEP.": [
+ ""
+ ],
+ "Domestic PEP classification removed": [
+ ""
+ ],
+ "Recorded when the domestic PEP classification is removed.": [
+ ""
+ ],
+ "Recorded when the international-organization PEP classification is removed.": [
+ ""
+ ],
+ "Simple suspicion reported to MROS": [
+ ""
+ ],
+ "Recorded when a report is filed under Article 305ter paragraph 2 StGB.": [
+ ""
+ ],
+ "Recorded when a report is filed under Article 9 GwG.": [
+ ""
+ ],
+ "Recorded when a pending special clarification is concluded.": [
+ ""
+ ],
+ "Recorded when a previously concluded investigation returns to a non-concluded state.": [
+ ""
+ ],
+ "Browser override": [
+ ""
+ ],
+ "Exchange identity, the active AML dialect, and the checks and programs available to AML decisions.": [
+ ""
+ ],
+ "Public information reported by this exchange.": [
+ ""
+ ],
+ "Base URL": [
+ ""
+ ],
+ "Protocol": [
+ ""
+ ],
+ "Protocol version": [
+ ""
+ ],
+ "Currency": [
+ ""
+ ],
+ "AML dialect": [
+ ""
+ ],
+ "Canonical properties defined by the effective dialect.": [
+ ""
+ ],
+ "This dialect does not define derived events.": [
+ ""
+ ],
+ "Checks, programs, root measures, and default rules reported by the exchange.": [
+ ""
+ ],
+ "%1$s entries": [
+ ""
+ ],
+ "No root measures are configured.": [
+ ""
+ ],
+ "No KYC checks are configured.": [
+ ""
+ ],
+ "No AML programs are configured.": [
+ ""
+ ],
+ "No default AML rules are configured.": [
+ ""
+ ],
+ "Built-in check that proceeds without collecting customer data.": [
+ ""
+ ],
+ "Voluntary": [
+ ""
+ ],
+ "Session and access": [
+ "Sesión y acceso"
+ ],
+ "Review this officer's exchange access and manage the unlocked key in this browser.": [
+ "Revise el acceso de este responsable al exchange y gestione la clave desbloqueada en este navegador."
+ ],
+ "Officer access": [
+ "Acceso del responsable"
+ ],
+ "Officer name": [
+ "Nombre del responsable"
+ ],
+ "Permissions": [
+ "Permisos"
+ ],
+ "Read-only": [
+ "Solo lectura"
+ ],
+ "Read and write": [
+ "Lectura y escritura"
+ ],
+ "Session security": [
+ "Seguridad de la sesión"
+ ],
+ "Lock the session when you leave this device unattended.": [
+ "Bloquee la sesión cuando deje este dispositivo desatendido."
+ ],
+ "Lock now": [
+ "Bloquear ahora"
+ ],
+ "Unlocked": [
+ "Desbloqueada"
+ ],
+ "Locks automatically": [
+ "Bloqueo automático"
+ ],
+ "Exact time": [
+ "Hora exacta"
+ ],
+ "Officer public key": [
+ "Clave pública del responsable"
+ ],
+ "Copy public key": [
+ "Copiar clave pública"
+ ],
+ "Remove key from this browser": [
+ "Eliminar la clave de este navegador"
+ ],
+ "Removing this key deletes the officer key from this browser. It does not revoke or change the officer's access at the exchange. Ask the exchange operator to revoke access if needed.": [
+ "Eliminar esta clave borra la clave del responsable de este navegador. No revoca ni modifica el acceso del responsable en el exchange. Si es necesario, solicite al operador del exchange que revoque el acceso."
+ ],
+ "Remove key": [
+ "Eliminar clave"
+ ],
+ "Remove officer key?": [
+ "¿Eliminar la clave del responsable?"
+ ],
+ "This deletes the officer key from this browser. You will need to create and enroll a new key to use the AML WebUI here again.": [
+ "Esto borra la clave del responsable de este navegador. Deberá crear y registrar una nueva clave para volver a utilizar aquí la interfaz web de AML."
+ ],
+ "This does not revoke the officer at the exchange. Ask the exchange operator to revoke its access if the key may be compromised.": [
+ "Esto no revoca al responsable en el exchange. Solicite al operador del exchange que revoque su acceso si la clave pudiera estar comprometida."
+ ],
+ "Find account": [
+ "Buscar cuenta"
+ ],
+ "Look up an account by its payto information or normalized payto hash.": [
+ "Busque una cuenta por su información payto o por su hash payto normalizado."
+ ],
+ "Find by payto": [
+ "Buscar por payto"
+ ],
+ "Find by normalized payto hash": [
+ "Buscar por hash payto normalizado"
+ ],
+ "Enter a valid 52-character normalized payto hash.": [
+ "Introduzca un hash payto normalizado válido de 52 caracteres."
+ ],
+ "Open account": [
+ "Abrir cuenta"
+ ],
+ "Failed to load account decisions.": [
+ "No se pudieron cargar las decisiones de la cuenta."
+ ],
+ "Failed to load the account history.": [
+ "No se pudo cargar el historial de la cuenta."
+ ],
+ "This session signature is invalid, contact administrator or create a new one.": [
+ "La firma de esta sesión no es válida. Póngase en contacto con el administrador o cree una nueva."
+ ],
+ "The designated AML session is not known, contact administrator or create a new one.": [
+ "La sesión AML indicada es desconocida. Póngase en contacto con el administrador o cree una nueva."
+ ],
+ "The designated AML session is not enabled, contact administrator or create a new one.": [
+ "La sesión AML indicada no está habilitada. Póngase en contacto con el administrador o cree una nueva."
+ ],
+ "This account has an AML decision history. Open its case to review current rules, measures, attributes, and past decisions.": [
+ ""
+ ],
+ "Active": [
+ ""
+ ],
+ "Account not found": [
+ "Cuenta no encontrada"
+ ],
+ "There is no history known for this account yet.": [
+ "Aún no hay historial conocido para esta cuenta."
+ ],
+ "Search": [
+ "Buscar"
+ ],
+ "Taler Bank": [
+ "Taler Bank"
+ ],
+ "Wallet": [
+ "Cartera"
+ ],
+ "Generic Payto:// URI": [
+ "URI genérica Payto://"
+ ],
+ "Account type": [
+ "Tipo de cuenta"
+ ],
+ "Should be 52 characters.": [
+ "Debe tener 52 caracteres."
+ ],
+ "Failed to parse: %1$s": [
+ "No se pudo interpretar: %1$s"
+ ],
+ "Address contains invalid characters.": [
+ "La dirección contiene caracteres inválidos."
+ ],
+ "Can't mix uppercased and lowercased characters.": [
+ "No se pueden mezclar mayúsculas y minúsculas."
+ ],
+ "The addr checksum doesn't match.": [
+ "La suma de verificación de la dirección no coincide."
+ ],
+ "Missing separator or address type.": [
+ "Falta el separador o el tipo de dirección."
+ ],
+ "Address should have less than 90 characters.": [
+ "La dirección debe tener menos de 90 caracteres."
+ ],
+ "Address should have more than 6 characters.": [
+ "La dirección debe tener más de 6 caracteres."
+ ],
+ "Decoding issue.": [
+ "Problema de decodificación."
+ ],
+ "Invalid data": [
+ "Datos no válidos"
+ ],
+ "Unsupported country.": [
+ "País no compatible."
+ ],
+ "IBANs have fewer than 34 characters.": [
+ "Los IBAN tienen menos de 34 caracteres."
+ ],
+ "IBANs have more than 4 characters.": [
+ "Los IBAN tienen más de 4 caracteres."
+ ],
+ "IBAN length is invalid for this country.": [
+ "La longitud del IBAN no es válida para este país."
+ ],
+ "It should only contain numbers and letters.": [
+ "Solo debe contener números y letras."
+ ],
+ "The checksum is wrong.": [
+ "La suma de verificación es incorrecta."
+ ],
+ "The string should start with payto://": [
+ "La cadena debe comenzar con payto://"
+ ],
+ "After the target type it should follow a '/' with more information.": [
+ "Después del tipo de destino debe seguir un '/' con más información."
+ ],
+ "The target type is not supported, only x-taler-bank, taler-reserve or iban": [
+ "El tipo de destino no es compatible, solo x-taler-bank, taler-reserve o iban"
+ ],
+ "IBAN is missing": [
+ "Falta el IBAN"
+ ],
+ "Bitcoin address is missing": [
+ "Falta la dirección de Bitcoin"
+ ],
+ "Bank host and account is missing": [
+ "Falta el host y la cuenta del banco"
+ ],
+ "Exchange host and account is missing": [
+ "Falta el host y la cuenta del exchange"
+ ],
+ "Ethereum address is missing": [
+ "Falta la dirección de Ethereum"
+ ],
+ "Cyclos address is missing": [
+ "Falta la dirección de Cyclos"
+ ],
+ "Void address is missing": [
+ "Falta la dirección void"
+ ],
+ "Invalid IBAN: %1$s": [
+ "IBAN inválido: %1$s"
+ ],
+ "Invalid BTC: %1$s": [
+ "BTC inválido: %1$s"
+ ],
+ "Invalid reserve: %1$s": [
+ "Reserva inválida: %1$s"
+ ],
+ "Invalid host": [
+ "Host inválido"
+ ],
+ "Invalid account": [
+ "Cuenta inválida"
+ ],
+ "Invalid address": [
+ "Dirección inválida"
+ ],
+ "As defined by RFC 8905": [
+ "Según se define en el RFC 8905"
+ ],
+ "payto://": [
+ "payto://"
+ ],
+ "International Bank Account Number": [
+ "Número de cuenta bancaria internacional"
+ ],
+ "DE1231231231": [
+ "DE1231231231"
+ ],
+ "Host": [
+ "Host"
+ ],
+ "Exchange hostname": [
+ "Nombre de host del exchange"
+ ],
+ "exchange.taler.net": [
+ "exchange.taler.net"
+ ],
+ "Remove last '/'": [
+ "Quitar el último '/'"
+ ],
+ "Invalid value": [
+ "Valor inválido"
+ ],
+ "ID": [
+ "ID"
+ ],
+ "Wallet reserve public key": [
+ "Clave pública de reserva de la cartera"
+ ],
+ "abcdef1235": [
+ "abcdef1235"
+ ],
+ "Should be 52 characters": [
+ "Debe tener 52 caracteres"
+ ],
+ "Bank account identification": [
+ "Identificación de la cuenta bancaria"
+ ],
+ "DE123123123": [
+ "DE123123123"
+ ],
+ "Hostname": [
+ "Nombre de host"
+ ],
+ "Without the scheme, may include subpath: bank.com, bank.com/path/": [
+ "Sin el esquema, puede incluir subruta: bank.com, bank.com/path/"
+ ],
+ "bank.demo.taler.net": [
+ "bank.demo.taler.net"
+ ],
+ "Invalid hostname": [
+ "Nombre de host inválido"
+ ],
+ "Failed to load account information.": [
+ "No se pudo cargar la información de la cuenta."
+ ],
+ "Failed to load the account information.": [
+ ""
+ ],
+ "Collection event not found": [
+ "No se encontró el evento de recopilación"
+ ],
+ "There is no collection event with ID %1$s for this account.": [
+ "No hay ningún evento de recopilación con el ID %1$s para esta cuenta."
+ ],
+ "Attributes unavailable": [
+ "Atributos no disponibles"
+ ],
+ "The collection event does not contain readable attributes.": [
+ "El evento de recopilación no contiene atributos legibles."
+ ],
+ "Form identifier missing": [
+ "Falta el identificador del formulario"
+ ],
+ "The collected information does not identify the form used to create it.": [
+ "La información recopilada no identifica el formulario utilizado para crearla."
+ ],
+ "Form not available": [
+ "Formulario no disponible"
+ ],
+ "Form %1$s is not configured in this AML Web UI.": [
+ "El formulario %1$s no está configurado en esta interfaz web de AML."
+ ],
+ "Source": [
+ ""
+ ],
+ "Different form version": [
+ "Versión de formulario diferente"
+ ],
+ "The collected information does not identify the form version used. The latest configured version is shown and field labels may differ from those used at collection time.": [
+ ""
+ ],
+ "JSON view": [
+ ""
+ ],
+ "Incoming": [
+ ""
+ ],
+ "Outgoing": [
+ ""
+ ],
+ "KYC authorization": [
+ ""
+ ],
+ "Wallet credits (P2P)": [
+ ""
+ ],
+ "Minimum amount": [
+ "Monto mínimo"
+ ],
+ "All amounts below the given threshold will be filtered.": [
+ "Se filtrarán todos los montos por debajo del umbral indicado."
+ ],
+ "Inspect successful P2P credits received by this wallet. Requests that were not paid are not shown.": [
+ ""
+ ],
+ "Inspect effective bank transfers observed by the exchange. Credit transfers are incoming, debit transfers are outgoing, and bounced or drain transfers are not included.": [
+ ""
+ ],
+ "Inspect effective transfers observed by the exchange. Incoming, outgoing, and KYC authorization entries are bank transfers. Wallet credits are successful P2P transfers into wallets.": [
+ ""
+ ],
+ "Failed to load the transfer list.": [
+ ""
+ ],
+ "Select transaction type": [
+ "Selecciona el tipo de transacción"
+ ],
+ "Please select a transaction type to show transactions.": [
+ "Selecciona un tipo de transacción para mostrar las transacciones."
+ ],
+ "No transfers yet.": [
+ "Aún no hay transferencias."
+ ],
+ "There are no transfers for this account.": [
+ "No hay transferencias para esta cuenta."
+ ],
+ "There are no transfers reported to the exchange with the current threshold.": [
+ "No hay transferencias informadas al exchange con el umbral actual."
+ ],
+ "Unknown date": [
+ ""
+ ],
+ "Time": [
+ ""
+ ],
+ "Amount": [
+ "Monto"
+ ],
+ "Unknown time": [
+ ""
+ ],
+ "sent": [
+ "enviado"
+ ],
+ "received": [
+ "recibido"
+ ],
+ "to": [
+ "a"
+ ],
+ "from": [
+ "de"
+ ],
+ "This exchange is not compatible with the AML WebUI.": [
+ "Este exchange no es compatible con la interfaz web de AML."
+ ],
+ "Officer identity and permissions require exchange protocol v40 or newer.": [
+ "La identidad y los permisos del responsable requieren el protocolo del exchange v40 o posterior."
+ ],
+ "Verifying that this public key is enrolled by the exchange.": [
+ "Comprobando que esta clave pública esté registrada en el exchange."
+ ],
+ "Read-only officer access": [
+ "Acceso de responsable de solo lectura"
+ ],
+ "You can review AML information, but this officer key cannot submit decisions.": [
+ "Puede revisar la información AML, pero esta clave de responsable no puede enviar decisiones."
+ ],
+ "This officer key cannot create or submit AML decisions.": [
+ "Esta clave de responsable no puede crear ni enviar decisiones de AML."
+ ],
+ "Return to account": [
+ "Volver a la cuenta"
+ ],
+ "Failed to load the active AML decision.": [
+ "No se pudo cargar la decisión AML activa."
+ ],
+ "The account was not found.": [
+ "No se encontró la cuenta."
+ ],
+ "The account state changed. Reload it and try again.": [
+ "El estado de la cuenta ha cambiado. Vuelva a cargarla e inténtelo de nuevo."
+ ],
+ "The payto URI does not belong to this account. Return to the account search and start the decision again.": [
+ "El URI payto no pertenece a esta cuenta. Vuelva a la búsqueda de cuentas e inicie de nuevo la decisión."
+ ],
+ "Session": [
+ "Sesión"
+ ],
+ "AML navigation": [
+ "Navegación AML"
+ ],
+ "Measures": [
+ "Medidas"
+ ],
+ "threshold\u0004%1$s every %2$s": [
+ "%1$s cada %2$s"
+ ],
+ "operation type\u0004Withdraw": [
+ "Retirada"
+ ],
+ "operation type\u0004Deposit": [
+ "Depósito"
+ ],
+ "operation type\u0004Merge": [
+ "Fusión"
+ ],
+ "operation type\u0004Aggregate": [
+ "Agregación"
+ ],
+ "operation type\u0004Balance": [
+ "Saldo"
+ ],
+ "operation type\u0004Refund": [
+ "Reembolso"
+ ],
+ "operation type\u0004Close": [
+ "Cerrar"
+ ],
+ "operation type\u0004Transaction": [
+ "Transacción"
+ ]
+ }
+ },
+ "domain": "messages",
+ "plural_forms": "",
+ "lang": "es",
+ "completeness": 60
+};
+
+strings['en'] = {
+ "locale_data": {
+ "messages": {
+ "": {
+ "domain": "messages",
+ "lang": "en",
+ "plural_forms": "nplurals=2; plural=(n != 1);"
+ },
+ "Allow Insecure password": [
+ "Allow Insecure password"
],
- "The MROS reporting state for the account.": [
- "El estado de informe MROS de la cuenta."
+ "Keep session after reload": [
+ "Keep session after reload"
],
- "None": [
- "Ninguno"
+ "Don't compress request": [
+ "Don't compress request"
],
- "Pending investigation": [
- "Investigación pendiente"
+ "Lock session": [
+ "Lock session"
],
- "Investigated without suspicion": [
- "Investigado sin sospecha"
+ "Lock": [
+ "Lock"
],
- "Reported simple suspicion": [
- "Sospecha simple informada"
+ "Password": [
+ "Password"
],
- "Reported substantiated suspicion": [
- "Sospecha fundamentada informada"
+ "Required": [
+ "Required"
],
- "Informal reason why the AML investigation was triggered": [
- "Motivo informal por el que se activó la investigación de AML"
+ "should have at least 12 characters": [
+ "should have at least 12 characters"
],
- "Identifies the sanction list entry that the account matched against": [
- "Identifica la entrada de la lista de sanciones con la que coincidió la cuenta"
+ "should have lowercase and uppercase characters": [
+ "should have lowercase and uppercase characters"
],
- "Best match, does not mean it was a good match.": [
- "Mejor coincidencia, no significa que fue una buena coincidencia."
+ "should have numbers": [
+ "should have numbers"
],
- "Score for how good the sanction list match was": [
- "Puntaje de qué tan buena fue la coincidencia con la lista de sanciones"
+ "should have at least one character which is not a number or letter": [
+ "should have at least one character which is not a number or letter"
],
- "Score for how much supporting data we had for the sanction list match": [
- "Puntaje de cuántos datos de respaldo teníamos para la coincidencia con la lista de sanciones"
+ "Repeat password": [
+ "Repeat password"
],
- "Suppress flagging this account when it creates a hit on a sanctions list, this is a false-positive": [
- "Suprimir la marcación de esta cuenta cuando genera una coincidencia en una lista de sanciones; es un falso positivo"
+ "doesn't match": [
+ "doesn't match"
],
- "Confirmation required": [
- "Confirmación requerida"
+ "Create session": [
+ "Create session"
],
- "I want to check first!": [
- "¡Quiero verificar primero!"
+ "Create": [
+ "Create"
],
- "Confirm decision": [
- "Confirmar decisión"
+ "Wallet account": [
+ "Wallet account"
],
- "Missing deadline": [
- "Falta el plazo"
+ "Bank account": [
+ "Bank account"
],
- "Deadline should specify when this rules ends and what is the next measures to apply after expiration.": [
- "El plazo debe especificar cuándo terminan estas reglas y cuáles son las siguientes medidas a aplicar tras el vencimiento."
+ "Under investigation": [
+ "Under investigation"
],
- "Missing rules": [
- "Faltan reglas"
+ "High risk": [
+ "High risk"
],
- "Can't make a decision without rules.": [
- "No se puede tomar una decisión sin reglas."
+ "Payment target type": [
+ ""
],
- "Missing active measure": [
- "Falta la medida activa"
+ "Account holder": [
+ "Account holder"
],
- "You should specify in the measure section.": [
- "Debes especificarlo en la sección de medidas."
+ "IBAN": [
+ "IBAN"
],
- "No customer action required.": [
- "No se requiere ninguna acción del cliente."
+ "BIC": [
+ "BIC"
],
- "No active measure has been selected.": [
- "No se ha seleccionado ninguna medida activa."
+ "Bank": [
+ "Bank"
],
- "Missing properties": [
- "Faltan propiedades"
+ "Account": [
+ "Account"
],
- "You should specify in the properties section.": [
- "Debes especificarlo en la sección de propiedades."
+ "Taler bank": [
+ "Taler bank"
],
- "Missing events": [
- "Faltan eventos"
+ "Cyclos": [
+ "Cyclos"
],
- "You should specify in the events section.": [
- "Debes especificarlo en la sección de eventos."
+ "Bitcoin address": [
+ "Bitcoin address"
],
- "Missing justification": [
- "Falta la justificación"
+ "Reserve public key": [
+ "Reserve public key"
],
- "You must complete the justification section.": [
- "Debes completar la sección de justificación."
+ "Bitcoin": [
+ "Bitcoin"
],
- "Invalid attributes": [
- "Atributos inválidos"
+ "Ethereum address": [
+ "Ethereum address"
],
- "You should check form errors or submit a decision without attributes.": [
- "Debes revisar los errores del formulario o enviar una decisión sin atributos."
+ "Ethereum": [
+ "Ethereum"
],
- "Clear": [
- "Limpiar"
+ "Exchange": [
+ "Exchange"
],
- "Send decision": [
- "Enviar decisión"
+ "Taler reserve": [
+ "Taler reserve"
],
- "Prev": [
- "Anterior"
+ "Taler reserve (HTTP)": [
+ "Taler reserve (HTTP)"
],
- "Next": [
- "Siguiente"
+ "Test account": [
+ "Test account"
],
- "Attributes": [
- "Atributos"
+ "Account details unavailable": [
+ "Account details unavailable"
],
- "Add more information about the customer": [
- "Añadir más información sobre el cliente"
+ "Not opened": [
+ "Not opened"
],
- "Rules": [
- "Reglas"
+ "Opened:": [
+ "Opened:"
],
- "Set the limit of the operations": [
- "Establecer el límite de las operaciones"
+ "Closed:": [
+ "Closed:"
],
- "Trigger notifications.": [
- "Activar notificaciones."
+ "Closed": [
+ "Closed"
],
- "Measures": [
- "Medidas"
+ "Open": [
+ "Open"
],
- "Ask the customer to take action.": [
- "Pedir al cliente que tome una acción."
+ "No note": [
+ "No note"
],
- "Describe the decision.": [
- "Describir la decisión."
+ "Show full note": [
+ "Show full note"
],
- "Flag the current account state.": [
- "Marcar el estado actual de la cuenta."
+ "System information": [
+ "System information"
],
- "Summary": [
- "Resumen"
+ "Transactions remain below the threshold that opens an AML file.": [
+ "Transactions remain below the threshold that opens an AML file."
],
- "Review and submit.": [
- "Revisar y enviar."
+ "Account case": [
+ "Account case"
],
- "Decision for account:": [
- "Decisión para la cuenta:"
+ "Failed to download AML file.": [
+ "Failed to download AML file."
],
- "Decision for wallet:": [
- "Decisión para la cartera:"
+ "No AML file is available for this account.": [
+ "No AML file is available for this account."
],
- "Decision for bank account:": [
- "Decisión para la cuenta bancaria:"
+ "Authorization denied for this session. Contact the administrator.": [
+ "Authorization denied for this session. Contact the administrator."
],
- "Search account": [
- "Buscar cuenta"
+ "The account or session was not found.": [
+ "The account or session was not found."
],
- "Failed to load account decisions.": [
- ""
+ "The session is disabled. Contact the administrator.": [
+ "The session is disabled. Contact the administrator."
],
- "Check account details": [
- "Verificar detalles de la cuenta"
+ "The exchange does not support PDF reports.": [
+ "The exchange does not support PDF reports."
],
- "Account most recent decisions": [
- "Decisiones más recientes de la cuenta"
+ "Read-only officers cannot create AML decisions.": [
+ "Read-only officers cannot create AML decisions."
],
- "When": [
- "Cuándo"
+ "A payto URI is required to create a new decision.": [
+ "A payto URI is required to create a new decision."
],
- "LATEST": [
- "MÁS RECIENTE"
+ "Back to accounts": [
+ "Back to accounts"
],
- "ACTIVE": [
- "ACTIVA"
+ "File no. %1$s": [
+ "File no. %1$s"
],
- "Account not found": [
- "Cuenta no encontrada"
+ "New decision": [
+ "New decision"
],
- "There is no history known for this account yet.": [
- "Aún no hay historial conocido para esta cuenta."
+ "Download AML file (PDF)": [
+ "Download AML file (PDF)"
],
- "You can make a decision for this account anyway.": [
- "Aun así, puedes tomar una decisión para esta cuenta."
+ "AML file download started.": [
+ "AML file download started."
],
- "Search": [
- "Buscar"
+ "Try again": [
+ ""
],
- "IBAN": [
- "IBAN"
+ "Account identifiers": [
+ "Account identifiers"
],
- "Taler Bank": [
- "Taler Bank"
+ "Technical identifiers": [
+ "Technical identifiers"
],
- "Wallet": [
- "Cartera"
+ "Full payto URI": [
+ "Full payto URI"
],
- "Generic Payto:// URI": [
- "URI genérica Payto://"
+ "Unavailable": [
+ "Unavailable"
],
- "Account type": [
- "Tipo de cuenta"
+ "Copy payto URI": [
+ "Copy payto URI"
],
- "Should be 52 characters.": [
- "Debe tener 52 caracteres."
+ "Normalized payto hash": [
+ "Normalized payto hash"
],
- "Failed to parse: %1$s": [
- "No se pudo interpretar: %1$s"
+ "Copy normalized payto hash": [
+ "Copy normalized payto hash"
],
- "Address contains invalid characters.": [
- "La dirección contiene caracteres inválidos."
+ "Account case views": [
+ "Account case views"
],
- "Can't mix uppercased and lowercased characters.": [
- "No se pueden mezclar mayúsculas y minúsculas."
+ "Overview": [
+ "Overview"
],
- "The addr checksum doesn't match.": [
- "La suma de verificación de la dirección no coincide."
+ "Transfers": [
+ "Transfers"
],
- "Missing separator or address type.": [
- "Falta el separador o el tipo de dirección."
+ "Decision history": [
+ "Decision history"
],
- "Address should have less than 90 characters.": [
- "La dirección debe tener menos de 90 caracteres."
+ "Close": [
+ "Close"
],
- "Address should have more than 6 characters.": [
- "La dirección debe tener más de 6 caracteres."
+ "Cancel": [
+ "Cancel"
],
- "Decoding issue.": [
- ""
+ "AML officer enrollment request": [
+ "AML officer enrollment request"
],
- "Unsupported country.": [
- "País no compatible."
+ "Please enroll this AML officer public key:\n\n%1$s": [
+ "Please enroll this AML officer public key:\n\n%1$s"
],
- "IBANs have fewer than 34 characters.": [
- "Los IBAN tienen menos de 34 caracteres."
+ "Officer key awaiting enrollment": [
+ "Officer key awaiting enrollment"
],
- "IBANs have more than 4 characters.": [
- "Los IBAN tienen más de 4 caracteres."
+ "This browser has created an AML officer key, but the exchange has not granted it access. Ask the exchange operator or administrator to enroll the public key below.": [
+ "This browser has created an AML officer key, but the exchange has not granted it access. Ask the exchange operator or administrator to enroll the public key below."
],
- "IBAN length is invalid for this country.": [
- "La longitud del IBAN no es válida para este país."
+ "AML officer public key": [
+ "AML officer public key"
],
- "It should only contain numbers and letters.": [
- "Solo debe contener números y letras."
+ "Copy AML officer public key": [
+ "Copy AML officer public key"
],
- "The checksum is wrong.": [
- "La suma de verificación es incorrecta."
+ "After the operator confirms enrollment, retry the access check.": [
+ "After the operator confirms enrollment, retry the access check."
],
- "The string should start with payto://": [
- "La cadena debe comenzar con payto://"
+ "Retry access check": [
+ "Retry access check"
],
- "After the target type it should follow a '/' with more information.": [
- "Después del tipo de destino debe seguir un '/' con más información."
+ "Checking officer access": [
+ "Checking officer access"
],
- "The target type is not supported, only x-taler-bank, taler-reserve or iban": [
- "El tipo de destino no es compatible, solo x-taler-bank, taler-reserve o iban"
+ "Last checked at %1$s": [
+ "Last checked at %1$s"
],
- "IBAN is missing": [
- "Falta el IBAN"
+ "Request enrollment": [
+ "Request enrollment"
],
- "Bitcoin address is missing": [
- "Falta la dirección de Bitcoin"
+ "Discard this key": [
+ "Discard this key"
],
- "Bank host and account is missing": [
- "Falta el host y la cuenta del banco"
+ "Confirmation required": [
+ "Confirmation required"
],
- "Exchange host and account is missing": [
- "Falta el host y la cuenta del exchange"
+ "Discarding this key removes the officer session from this browser. You will need to create a new key to use the AML WebUI again.": [
+ "Discarding this key removes the officer session from this browser. You will need to create a new key to use the AML WebUI again."
],
- "Ethereum address is missing": [
- "Falta la dirección de Ethereum"
+ "Failed to check AML officer access.": [
+ "Failed to check AML officer access."
],
- "Cyclos address is missing": [
- "Falta la dirección de Cyclos"
+ "This officer key cannot authenticate with the exchange. Retry the check or discard the key and create a new session.": [
+ "This officer key cannot authenticate with the exchange. Retry the check or discard the key and create a new session."
],
- "Invalid IBAN: %1$s": [
- "IBAN inválido: %1$s"
+ "The exchange rejected the officer access check.": [
+ "The exchange rejected the officer access check."
],
- "Invalid BTC: %1$s": [
- "BTC inválido: %1$s"
+ "Technical details": [
+ "Technical details"
],
- "Invalid reserve: %1$s": [
- "Reserva inválida: %1$s"
+ "Failed to unlock the session.": [
+ "Failed to unlock the session."
],
- "Invalid host": [
- "Host inválido"
+ "Session locked": [
+ "Session locked"
],
- "Invalid address": [
- "Dirección inválida"
+ "Your session is normally locked anytime you reload. To unlock type your password again.": [
+ "Your session is normally locked anytime you reload. To unlock type your password again."
],
- "Payto URI": [
- "URI Payto"
+ "Unlock": [
+ "Unlock"
],
- "As defined by RFC 8905": [
- "Según se define en el RFC 8905"
+ "Forget session": [
+ "Forget session"
],
- "payto://": [
- "payto://"
+ "There are no rules for operations": [
+ ""
],
- "International Bank Account Number": [
- "Número de cuenta bancaria internacional"
+ "This means that no operation has any limit.": [
+ ""
],
- "DE1231231231": [
- "DE1231231231"
+ "Operation": [
+ "Operation"
],
- "Host": [
- "Host"
+ "Threshold": [
+ "Threshold"
],
- "Exchange hostname": [
- "Nombre de host del exchange"
+ "Escalation": [
+ "Escalation"
],
- "exchange.taler.net": [
- "exchange.taler.net"
+ "Visibility": [
+ ""
],
- "Remove last '/'": [
- "Quitar el último '/'"
+ "Priority": [
+ ""
],
- "Invalid value": [
- "Valor inválido"
+ "Actions": [
+ ""
],
- "ID": [
- "ID"
+ "Block operation": [
+ ""
],
- "Wallet reserve public key": [
- "Clave pública de reserva de la cartera"
+ "All required:": [
+ ""
],
- "abcdef1235": [
- "abcdef1235"
+ "Any one:": [
+ ""
],
- "Should be 52 characters": [
- "Debe tener 52 caracteres"
+ "Customer-visible": [
+ ""
],
- "Account": [
- "Cuenta"
+ "Internal": [
+ ""
],
- "Bank account identification": [
- "Identificación de la cuenta bancaria"
+ "Move %1$s rule up": [
+ ""
],
- "DE123123123": [
- "DE123123123"
+ "Move %1$s rule down": [
+ ""
],
- "Hostname": [
- "Nombre de host"
+ "Edit %1$s rule": [
+ ""
],
- "Without the scheme, may include subpath: bank.com, bank.com/path/": [
- "Sin el esquema, puede incluir subruta: bank.com, bank.com/path/"
+ "Remove %1$s rule": [
+ ""
],
- "bank.demo.taler.net": [
- "bank.demo.taler.net"
+ "AML officer justification": [
+ "AML officer justification"
],
- "Invalid hostname": [
- "Nombre de host inválido"
+ "No justification was recorded.": [
+ "No justification was recorded."
],
- "Failed to load the account information.": [
- ""
+ "Operation rules": [
+ "Operation rules"
],
- "Different form version": [
- "Versión de formulario diferente"
+ "Decision date": [
+ "Decision date"
],
- "The collected information don't have the form version used.": [
- "La información recopilada no tiene la versión de formulario utilizada."
+ "Expired": [
+ "Expired"
],
- "The collected information used the form version \"%1$s \" but is not available.": [
- "La información recopilada usó la versión de formulario \"%1$s \", pero no está disponible."
+ "Expires": [
+ "Expires"
],
- "Case details": [
- "Detalles del caso"
+ "Successor measure": [
+ "Successor measure"
],
- "Next event": [
- "Próximo evento"
+ "Exchange defaults": [
+ "Exchange defaults"
],
- "Previous event": [
- "Evento anterior"
+ "Forms": [
+ "Forms"
],
- "Direction": [
- "Dirección"
+ "Measures used to gather information about the customer.": [
+ "Measures used to gather information about the customer."
],
- "Credit": [
- "Crédito"
+ "Select": [
+ "Select"
],
- "Debit": [
- "Débito"
+ "Name": [
+ "Name"
],
- "KYC Auth": [
- "Autenticación KYC"
+ "Check": [
+ "Check"
],
- "Minimum amount": [
- "Monto mínimo"
+ "Program": [
+ "Program"
],
- "All amounts below the given threshold will be filtered.": [
- "Se filtrarán todos los montos por debajo del umbral indicado."
+ "Context": [
+ "Context"
],
- "Failed to load the transfer list.": [
- ""
+ "Modify": [
+ "Modify"
],
- "Select transaction type": [
- "Selecciona el tipo de transacción"
+ "Instant measures": [
+ "Instant measures"
],
- "Please select a transaction type to show transactions.": [
- "Selecciona un tipo de transacción para mostrar las transacciones."
+ "Triggered immediately without customer interaction.": [
+ "Triggered immediately without customer interaction."
],
- "Transfers history for account": [
- "Historial de transferencias de la cuenta"
+ "Input requirement": [
+ "Input requirement"
],
- "Transfers history": [
- "Historial de transferencias"
+ "Started": [
+ "Started"
],
- "No transfers yet.": [
- "Aún no hay transferencias."
+ "Status": [
+ "Status"
],
- "There are no transfers for this account.": [
- "No hay transferencias para esta cuenta."
+ "Forbidden": [
+ "Forbidden"
],
- "There are no transfers reported to the exchange with the current threshold.": [
- "No hay transferencias informadas al exchange con el umbral actual."
+ "Completed": [
+ "Completed"
],
- "Date": [
- "Fecha"
+ "Waiting for customer": [
+ "Waiting for customer"
],
- "Amount": [
- "Monto"
+ "The operation is categorically forbidden by this requirement.": [
+ "The operation is categorically forbidden by this requirement."
],
- "sent": [
- "enviado"
+ "All listed measures must be completed.": [
+ "All listed measures must be completed."
],
- "received": [
- "recibido"
+ "Any one listed measure may be completed.": [
+ "Any one listed measure may be completed."
],
- "to": [
- "a"
+ "Values may be derived from the selected AML/KYC form. Confirm them against the case record and change only values that require an officer override.": [
+ ""
],
- "from": [
- "de"
+ "Invalid custom properties": [
+ "Invalid custom properties"
],
- "Welcome to the exchange configuration": [
- "Bienvenido a la configuración del exchange"
+ "Custom property names and values must be non-empty and names must be unique and different from built-in properties.": [
+ "Custom property names and values must be non-empty and names must be unique and different from built-in properties."
],
- "Transfers": [
- "Transferencias"
+ "Properties": [
+ "Properties"
],
- "Profile": [
- "Perfil"
+ "Built-in property names are preserved when the decision is submitted.": [
+ ""
],
- "Failed to load available measures.": [
- "No se pudieron cargar las medidas disponibles."
+ "Custom properties": [
+ "Custom properties"
],
- "The officer session is invalid.": [
- "La sesión del responsable de AML no es válida."
+ "Add more properties that are not listed above.": [
+ "Add more properties that are not listed above."
],
- "The measures endpoint was not found.": [
- "No se encontró el punto de acceso de las medidas."
+ "New properties": [
+ "New properties"
],
- "The officer session is disabled.": [
- "La sesión del responsable de AML está deshabilitada."
+ "Value": [
+ "Value"
],
- "Failed to load the active AML decision.": [
- "No se pudo cargar la decisión AML activa."
+ "Current note on the GwG file": [
+ "Current note on the GwG file"
],
- "The officer session signature is invalid.": [
- "La firma de la sesión del responsable de AML no es válida."
+ "Customer name or internal alias.": [
+ "Customer name or internal alias."
],
- "The requested AML account or session was not found.": [
- "No se encontró la cuenta AML o la sesión solicitada."
+ "Is the account active for deposit and payments?": [
+ "Is the account active for deposit and payments?"
],
- "The officer session is disabled or the account state changed.": [
- "La sesión del responsable de AML está deshabilitada o cambió el estado de la cuenta."
+ "Is the account idle?": [
+ "Is the account idle?"
],
- "Invalid expiration": [
- "Caducidad no válida"
+ "No operation for a period of time": [
+ "No operation for a period of time"
],
- "Attributes require an expiration date in the future.": [
- "Los atributos requieren una fecha de caducidad futura."
+ "Does account belong to a domestic PEP?": [
+ "Does account belong to a domestic PEP?"
],
- "Too many SKIP measures": [
- "Demasiadas medidas SKIP"
+ "Does account belong to a foreign PEP?": [
+ "Does account belong to a foreign PEP?"
],
- "At most one immediate measure may use the SKIP check.": [
- "Como máximo una medida inmediata puede usar la comprobación SKIP."
+ "Does account belong to an international-organization PEP?": [
+ "Does account belong to an international-organization PEP?"
],
- "Require all measures": [
- "Exigir todas las medidas"
+ "Does account belong to a high risk customer?": [
+ "Does account belong to a high risk customer?"
],
- "Run all selected measures together instead of accepting any one of them.": [
- "Ejecutar juntas todas las medidas seleccionadas en lugar de aceptar cualquiera de ellas."
+ "Does account belong to a person from a high risk country?": [
+ "Does account belong to a person from a high risk country?"
],
- "Invalid custom properties": [
- "Propiedades personalizadas no válidas"
+ "The MROS reporting state for the account.": [
+ "The MROS reporting state for the account."
],
- "Custom property names and values must be non-empty and names must be unique and different from built-in properties.": [
- "Los nombres y valores de las propiedades personalizadas no pueden estar vacíos; los nombres deben ser únicos y diferentes de las propiedades integradas."
+ "None": [
+ "None"
],
- "Unknown measure": [
- "Medida desconocida"
+ "Pending investigation": [
+ "Pending investigation"
],
- "A rule or immediate action references a measure that is not available. Review the rules and measures before submitting.": [
- "Una regla o acción inmediata hace referencia a una medida que no está disponible. Revise las reglas y las medidas antes de enviar."
+ "Investigated without suspicion": [
+ "Investigated without suspicion"
],
- "Requires investigation": [
- "Requiere investigación"
+ "Reported simple suspicion": [
+ "Reported simple suspicion"
],
- "Collection event not found": [
- "No se encontró el evento de recopilación"
+ "Reported substantiated suspicion": [
+ "Reported substantiated suspicion"
],
- "There is no collection event with ID %1$s for this account.": [
- "No hay ningún evento de recopilación con el ID %1$s para esta cuenta."
+ "Informal reason why the AML investigation was triggered": [
+ "Informal reason why the AML investigation was triggered"
],
- "Attributes unavailable": [
- "Atributos no disponibles"
+ "Identifies the sanction list entry that the account matched against": [
+ "Identifies the sanction list entry that the account matched against"
],
- "The collection event does not contain readable attributes.": [
- "El evento de recopilación no contiene atributos legibles."
+ "Best match, does not mean it was a good match.": [
+ "Best match, does not mean it was a good match."
],
- "Form identifier missing": [
- "Falta el identificador del formulario"
+ "Score for how good the sanction list match was": [
+ "Score for how good the sanction list match was"
],
- "The collected information does not identify the form used to create it.": [
- "La información recopilada no identifica el formulario utilizado para crearla."
+ "Integer score from 0 (no match) to 1,000,000,000 (best match).": [
+ ""
],
- "Form not available": [
- "Formulario no disponible"
+ "Score for how much supporting data we had for the sanction list match": [
+ "Score for how much supporting data we had for the sanction list match"
],
- "Form %1$s is not configured in this AML Web UI.": [
- "El formulario %1$s no está configurado en esta interfaz web de AML."
+ "Integer score from 0 (no supporting data) to 1,000,000,000 (highest confidence).": [
+ ""
],
- "The account was not found.": [
- "No se encontró la cuenta."
+ "Suppress flagging this account when it creates a hit on a sanctions list, this is a false-positive": [
+ "Suppress flagging this account when it creates a hit on a sanctions list, this is a false-positive"
],
- "The account state changed. Reload it and try again.": [
- "El estado de la cuenta ha cambiado. Vuelva a cargarla e inténtelo de nuevo."
+ "Expiration shortcuts": [
+ ""
],
- "The payto URI does not belong to this account. Return to the account search and start the decision again.": [
- "El URI payto no pertenece a esta cuenta. Vuelva a la búsqueda de cuentas e inicie de nuevo la decisión."
+ "In a week": [
+ "In a week"
],
- "This account has no active decision and its payto URI is unknown. Start the decision from the account search so the account type can be determined safely.": [
- "Esta cuenta no tiene una decisión activa y se desconoce su URI payto. Inicie la decisión desde la búsqueda de cuentas para poder determinar de forma segura el tipo de cuenta."
+ "In a month": [
+ "In a month"
],
- "Return to account": [
- "Volver a la cuenta"
+ "In a year": [
+ "In a year"
],
- "threshold\u0004%1$s every %2$s": [
- "%1$s cada %2$s"
+ "Never": [
+ "Never"
],
- "operation type\u0004Withdraw": [
- "Retirada"
+ "Failed to load available measures.": [
+ "Failed to load available measures."
],
- "operation type\u0004Deposit": [
- "Depósito"
+ "The officer session is invalid.": [
+ "The officer session is invalid."
],
- "operation type\u0004Merge": [
- "Fusión"
+ "The measures endpoint was not found.": [
+ "The measures endpoint was not found."
],
- "operation type\u0004Aggregate": [
- "Agregación"
+ "The officer session is disabled.": [
+ "The officer session is disabled."
],
- "operation type\u0004Balance": [
- "Saldo"
+ "Edit proposed rule": [
+ ""
],
- "operation type\u0004Refund": [
- "Reembolso"
+ "Add proposed rule": [
+ ""
],
- "operation type\u0004Close": [
- "Cerrar"
+ "Save rule": [
+ ""
],
- "operation type\u0004Transaction": [
- "Transacción"
- ]
- }
- },
- "domain": "messages",
- "plural_forms": "",
- "lang": "es",
- "completeness": 89
-};
-
-strings['en'] = {
- "locale_data": {
- "messages": {
- "": {
- "domain": "messages",
- "lang": "en",
- "plural_forms": "nplurals=2; plural=(n != 1);"
- },
- "Use testing dialect": [
+ "Add rule": [
""
],
- "Allow Insecure password": [
+ "This complete rule set replaces the currently applied rules and exchange defaults until it expires. Higher rows take precedence.": [
""
],
- "Keep session after reload": [
+ "Rules for another account type": [
""
],
- "Don't compress request": [
+ "These operations do not apply to this account type: %1$s.": [
""
],
- "Preferences": [
+ "Operations without limits": [
""
],
- "Show debug information": [
+ "No proposed rule limits these operations: %1$s.": [
""
],
- "Password": [
+ "Invalid proposed rules": [
""
],
- "Required": [
+ "Edit the highlighted rule set before continuing. Hard blocks cannot be combined with measures, and Balance and Refund rules must use an instant timeframe.": [
""
],
- "should have at least 12 characters": [
+ "Remove proposed rule?": [
""
],
- "should have lowercase and uppercase characters": [
+ "This is the final rule. Removing it leaves every applicable operation unlimited.": [
""
],
- "should have numbers": [
+ "The rule will be removed from the proposed set.": [
""
],
- "should have at least one character which is not a number or letter": [
+ "Keep rule": [
""
],
- "Repeat password": [
+ "Remove rule": [
""
],
- "doesn't match": [
+ "Replace proposed rules": [
""
],
- "Create session": [
+ "Preview a complete replacement before applying it.": [
""
],
- "Create": [
+ "Currently applied": [
""
],
- "Failed to unlock the session.": [
+ "E-commerce": [
+ "E-commerce"
+ ],
+ "Point of Sale": [
+ "Point of Sale"
+ ],
+ "Basic plan": [
+ "Basic plan"
+ ],
+ "Premium": [
+ "Premium"
+ ],
+ "Freeze account": [
""
],
- "Authorization denied for this session. Contact the administrator.": [
+ "Replacement preview": [
""
],
- "Session locked": [
+ "Confirm account freeze": [
""
],
- "Your session is normally locked anytime you reload. To unlock type your password again.": [
+ "Every applicable operation will receive a zero hard limit.": [
""
],
- "Unlock": [
+ "Apply replacement": [
""
],
- "Forget session": [
+ "Choose how long the proposed rules apply and what happens afterwards.": [
""
],
- "There are no rules for operations": [
+ "The proposed rules never expire, so no successor action will run.": [
""
],
- "This means that no operation has any limit.": [
+ "Restore currently applied expiration": [
""
],
- "Add custom rule": [
+ "Operation type": [
+ "Operation type"
+ ],
+ "Timeframe": [
+ "Timeframe"
+ ],
+ "Use Y, M, D, h, m or s after each number. Forever accumulates over the account's full history.": [
""
],
- "Operation": [
+ "Instant timeframe": [
""
],
- "Threshold": [
+ "Balance and Refund limits apply to one balance or transaction, so their timeframe is fixed to zero.": [
""
],
- "Escalation": [
+ "Exposed": [
+ "Exposed"
+ ],
+ "Is this limit communicated to the customer?": [
+ "Is this limit communicated to the customer?"
+ ],
+ "When the threshold is crossed": [
""
],
- "%1$s": [
+ "Require measures": [
""
],
- "(all)": [
+ "Required measures": [
""
],
- "Since": [
+ "Measures that the customer will need to satisfy to apply for a new threshold.": [
+ "Measures that the customer will need to satisfy to apply for a new threshold."
+ ],
+ "All measures": [
+ "All measures"
+ ],
+ "Hint the customer that all measures should be completed": [
+ "Hint the customer that all measures should be completed"
+ ],
+ "Expiration date": [
+ "Expiration date"
+ ],
+ "Until when are the new rules active.": [
+ "Until when are the new rules active."
+ ],
+ "Choose a future expiration date or Never.": [
""
],
- "Expired": [
+ "After expiration": [
""
],
- "Expires": [
+ "Return to exchange defaults": [
""
],
- "Successor measure": [
+ "Trigger a successor measure": [
""
],
- "AML officer justification": [
+ "Measure taken automatically upon expiration of the current decision.": [
+ "Measure taken automatically upon expiration of the current decision."
+ ],
+ "This successor measure is no longer available.": [
""
],
+ "Case summary": [
+ "Case summary"
+ ],
+ "Current review state and the latest account activity.": [
+ "Current review state and the latest account activity."
+ ],
+ "Review status": [
+ "Review status"
+ ],
+ "Loading…": [
+ "Loading…"
+ ],
+ "Manual review required — waiting for an AML decision.": [
+ "Manual review required — waiting for an AML decision."
+ ],
+ "No manual review": [
+ "No manual review"
+ ],
+ "Effective decision": [
+ "Effective decision"
+ ],
+ "Requirements": [
+ "Requirements"
+ ],
+ "Latest collected information": [
+ "Latest collected information"
+ ],
+ "Effective policy": [
+ "Effective policy"
+ ],
+ "The AML decision and operation rules currently applied to this account.": [
+ "The AML decision and operation rules currently applied to this account."
+ ],
+ "Effective policy could not be loaded": [
+ "Effective policy could not be loaded"
+ ],
+ "Exchange defaults apply": [
+ "Exchange defaults apply"
+ ],
+ "No AML officer decision is active for this account.": [
+ "No AML officer decision is active for this account."
+ ],
+ "Account type unavailable": [
+ "Account type unavailable"
+ ],
+ "Open this case from the account directory or payto search to see the applicable default rules.": [
+ "Open this case from the account directory or payto search to see the applicable default rules."
+ ],
+ "Default rules could not be loaded": [
+ "Default rules could not be loaded"
+ ],
"Default rules": [
- ""
+ "Default rules"
+ ],
+ "Account assessment": [
+ "Account assessment"
+ ],
+ "Properties recorded by AML officers for this account.": [
+ "Properties recorded by AML officers for this account."
+ ],
+ "Account assessment could not be loaded": [
+ "Account assessment could not be loaded"
+ ],
+ "Collected information": [
+ "Collected information"
+ ],
+ "KYC information filed by the customer or an AML officer.": [
+ "KYC information filed by the customer or an AML officer."
+ ],
+ "Collected information could not be loaded": [
+ "Collected information could not be loaded"
+ ],
+ "No collected information": [
+ "No collected information"
+ ],
+ "No KYC information has been collected for this account.": [
+ "No KYC information has been collected for this account."
+ ],
+ "Active requirements": [
+ "Active requirements"
+ ],
+ "Measures the customer must complete under the current policy.": [
+ "Measures the customer must complete under the current policy."
+ ],
+ "Active requirements could not be loaded": [
+ "Active requirements could not be loaded"
+ ],
+ "No active requirements": [
+ "No active requirements"
+ ],
+ "The customer has no active legitimization measures to complete.": [
+ "The customer has no active legitimization measures to complete."
+ ],
+ "Officer decision": [
+ "Officer decision"
+ ],
+ "Does not expire": [
+ "Does not expire"
+ ],
+ "Waiting": [
+ "Waiting"
+ ],
+ "More on later pages": [
+ "More on later pages"
+ ],
+ "Try loading this section again.": [
+ "Try loading this section again."
+ ],
+ "Retry": [
+ "Retry"
+ ],
+ "No account properties": [
+ "No account properties"
+ ],
+ "No assessment properties have been recorded for this account.": [
+ "No assessment properties have been recorded for this account."
+ ],
+ "Yes": [
+ "Yes"
+ ],
+ "No": [
+ "No"
+ ],
+ "Unconfigured form": [
+ "Unconfigured form"
+ ],
+ "Form not identified": [
+ "Form not identified"
+ ],
+ "Filed by an AML officer": [
+ "Filed by an AML officer"
+ ],
+ "Provided by the customer": [
+ "Provided by the customer"
],
- "Forms": [
- ""
+ "Attribute data is unavailable.": [
+ "Attribute data is unavailable."
],
- "Measures used to gather information about the customer.": [
- ""
+ "View details": [
+ "View details"
],
- "Name": [
- ""
+ "Review superseded AML decisions for this account, from newest to oldest.": [
+ "Review superseded AML decisions for this account, from newest to oldest."
],
- "Check": [
- ""
+ "Loading decision history…": [
+ "Loading decision history…"
],
- "Program": [
- ""
+ "Decision history could not be loaded": [
+ "Decision history could not be loaded"
],
- "Context": [
- ""
+ "Try loading the decision history again.": [
+ "Try loading the decision history again."
],
- "Modify": [
- ""
+ "No previous decisions": [
+ "No previous decisions"
],
- "Info": [
- ""
+ "No superseded AML decisions have been recorded for this account.": [
+ "No superseded AML decisions have been recorded for this account."
],
- "Will show information to the user.": [
- ""
+ "Previous decisions": [
+ "Previous decisions"
],
- "Instant measures": [
- ""
+ "The export could not be prepared. Try again.": [
+ "The export could not be prepared. Try again."
],
- "Triggered immediately without customer interaction.": [
- ""
+ "Failed to load accounts": [
+ "Failed to load accounts"
],
- "Input requirement": [
- ""
+ "Accounts": [
+ "Accounts"
],
- "Already completed.": [
- ""
+ "Review accounts known to the exchange for AML and KYC handling.": [
+ "Review accounts known to the exchange for AML and KYC handling."
],
- "Waiting to be completed.": [
- ""
+ "Export filtered accounts": [
+ "Export filtered accounts"
],
- "Current active rules": [
- ""
+ "Download CSV": [
+ "Download CSV"
],
- "There are no rules for this account yet.": [
- ""
+ "Download Excel": [
+ "Download Excel"
],
- "New rule form": [
- ""
+ "Preparing export…": [
+ "Preparing export…"
],
- "Add": [
- ""
+ "Export failed": [
+ "Export failed"
],
- "Cancel": [
- ""
+ "Account filters": [
+ "Account filters"
],
- "Basic plan": [
- ""
+ "Investigation": [
+ "Investigation"
],
- "Premium": [
- ""
+ "All accounts": [
+ "All accounts"
],
- "E-commerce": [
- ""
+ "Not under investigation": [
+ "Not under investigation"
],
- "Point of Sale": [
- ""
+ "Risk": [
+ "Risk"
],
- "Check rules": [
- ""
+ "All risk levels": [
+ "All risk levels"
],
- "The account is a wallet and there are bank account operation's limits which may trigger actions that are not required: %1$s": [
- ""
+ "Not high risk": [
+ "Not high risk"
],
- "The account isn't a wallet and there are wallet operation's limits which may trigger actions that are not required: %1$s": [
- ""
+ "File status": [
+ "File status"
],
- "The account is a wallet and there are wallet operation's limits which are not limited: %1$s": [
- ""
+ "All file statuses": [
+ "All file statuses"
],
- "The AML account is a bank account, but not all account-related operations are limited ( %1$s).": [
- ""
+ "Not open": [
+ "Not open"
],
- "New rules": [
- ""
+ "Clear filters": [
+ "Clear filters"
],
- "Reset rules to current state": [
- ""
+ "Showing %1$s accounts · newest first": [
+ "Showing %1$s accounts · newest first"
],
- "Set rules to default": [
- ""
+ "AML and KYC accounts": [
+ "AML and KYC accounts"
],
- "Freeze account": [
- ""
+ "Account lifecycle": [
+ "Account lifecycle"
],
- "Behavior on rule expiration": [
- ""
+ "Latest note": [
+ "Latest note"
],
- "Reset measure": [
- ""
+ "Copied": [
+ "Copied"
],
- "Reset expiration": [
- ""
+ "Copy": [
+ "Copy"
],
- "Operation type": [
- ""
+ "No matching accounts": [
+ "No matching accounts"
],
- "Timeframe": [
- ""
+ "No accounts yet": [
+ "No accounts yet"
],
- "Exposed": [
- ""
+ "No accounts match the selected filters.": [
+ "No accounts match the selected filters."
],
- "Is this limit communicated to the customer?": [
- ""
+ "The exchange has not recorded any AML or KYC accounts yet.": [
+ "The exchange has not recorded any AML or KYC accounts yet."
],
- "Escalation measure": [
- ""
+ "This officer session is not authorized to list accounts.": [
+ "This officer session is not authorized to list accounts."
],
- "Measures that the customer will need to satisfy to apply for a new threshold.": [
- ""
+ "The exchange does not recognize this officer session.": [
+ "The exchange does not recognize this officer session."
],
- "All measures": [
- ""
+ "This officer session is currently disabled.": [
+ "This officer session is currently disabled."
],
- "Hint the customer that all measures should be completed": [
- ""
+ "There are no matching accounts to export.": [
+ "There are no matching accounts to export."
],
- "Expiration": [
- ""
+ "The exchange does not support the selected export format.": [
+ "The exchange does not support the selected export format."
],
- "Predefined shortcuts": [
- ""
+ "This officer session is not authorized to export accounts.": [
+ "This officer session is not authorized to export accounts."
],
- "In a week": [
- ""
+ "Dashboard": [
+ "Dashboard"
],
- "In a month": [
- ""
+ "Review cases requiring attention, investigate accounts, and monitor AML reporting indicators.": [
+ "Review cases requiring attention, investigate accounts, and monitor AML reporting indicators."
],
- "In a year": [
- ""
+ "Review case queue": [
+ "Review case queue"
],
- "Never": [
- ""
+ "Find credit, debit, and KYC authorization activity.": [
+ "Find credit, debit, and KYC authorization activity."
],
- "Expiration date": [
- ""
+ "Statistics": [
+ "Statistics"
],
- "Until when are the new rules active.": [
+ "No reporting profile for this dialect": [
""
],
- "Measure taken automatically upon expiration of the current decision.": [
+ "The testing dialect does not define dashboard statistics. Select TOPS in development settings to inspect the TOPS reporting profile.": [
""
],
- "Failed to load account information.": [
- ""
+ "Failed to load TOPS statistics.": [
+ "Failed to load TOPS statistics."
],
- "Failed to load decision history.": [
- ""
+ "Some statistics are unavailable.": [
+ "Some statistics are unavailable."
],
- "Failed to load current legitimizations.": [
- ""
+ "The available values are shown below. Missing values are not zero.": [
+ "The available values are shown below. Missing values are not zero."
],
- "New decision": [
- ""
+ "Accounts open": [
+ "Accounts open"
],
- "Show transfers": [
- ""
+ "New files last year": [
+ "New files last year"
],
- "Failed to download report.": [
- ""
+ "Closed files last year": [
+ "Closed files last year"
],
- "The account has no KYC info.": [
- ""
+ "MROS substantiated": [
+ "MROS substantiated"
],
- "Session not found. Contact the administrator.": [
- ""
+ "MROS simple": [
+ "MROS simple"
],
- "The session is disabled. Contact the administrator.": [
- ""
+ "High risk files": [
+ "High risk files"
],
- "The server doesn't support PDF download. Contact the administrator.": [
- ""
+ "PEP files": [
+ "PEP files"
],
- "Case history for selected account": [
- ""
+ "Number of accounts that are opened": [
+ "Number of accounts that are opened"
],
- "ID:": [
- ""
+ "Number of new GwG files in the last year": [
+ "Number of new GwG files in the last year"
],
- "Payto:": [
- ""
+ "Number of GwG files closed in the last year": [
+ "Number of GwG files closed in the last year"
],
- "Export as PDF": [
- ""
+ "Number of MROS reports based on Art 9 Abs. 1 GwG (per year)": [
+ "Number of MROS reports based on Art 9 Abs. 1 GwG (per year)"
],
- "Export completed": [
- ""
+ "Number of MROS reports based on Art 305ter Abs. 2 StGB (per year)": [
+ "Number of MROS reports based on Art 305ter Abs. 2 StGB (per year)"
],
- "Click here to save the file in your computer.": [
- ""
+ "Number of GwG files of high-risk customers": [
+ "Number of GwG files of high-risk customers"
],
- "Under investigation": [
- ""
+ "Number of GwG files managed with “increased risk” due to PEP status": [
+ "Number of GwG files managed with “increased risk” due to PEP status"
],
- "This account requires a manual review and is waiting for a decision to be made.": [
- ""
+ "Number of customers with open proceeding.": [
+ "Number of customers with open proceeding."
],
- "Collected information": [
- ""
+ "previous": [
+ "previous"
],
- "Every attribute collection event (via form upload or KYC provider).": [
- ""
+ "Decreased by": [
+ "Decreased by"
],
- "No collected attributes for this account.": [
- ""
+ "Increased by": [
+ "Increased by"
],
- "Current account properties": [
+ "Built-in events are derived from changes to the proposed account properties. They are stored for reporting and statistics; they do not notify the customer.": [
""
],
- "No active decision found": [
- ""
+ "Calculated": [
+ "Calculated"
],
- "There is no decision for this account yet. The account is limited by the default rules.": [
+ "Other built-in events": [
""
],
- "Previous AML decisions": [
+ "Operator-defined event names that are not part of the selected dialect.": [
""
],
- "No AML history found": [
+ "The completed form is attached to this AML decision as reviewed account information. It does not create a customer-facing measure.": [
""
],
- "Current active measures": [
- ""
+ "Expiration": [
+ "Expiration"
],
- "Now": [
- ""
+ "Expiration date of the information filled in this form.": [
+ "Expiration date of the information filled in this form."
],
- "Session public key": [
- ""
+ "Form context": [
+ "Form context"
],
- "Request session activation": [
+ "Only change this operator-defined JSON when the form documentation requires additional context.": [
""
],
- "Lock session": [
- ""
+ "Context as JSON": [
+ "Context as JSON"
],
- "Failed to load accounts": [
- ""
+ "Invalid JSON": [
+ "Invalid JSON"
],
- "Failed to load the accounts": [
- ""
+ "Invalid expiration": [
+ "Invalid expiration"
],
- "This session signature is invalid, contact administrator or create a new one.": [
- ""
+ "Attributes require an expiration date in the future or set to Never.": [
+ "Attributes require an expiration date in the future or set to Never."
],
- "The designated AML session is not known, contact administrator or create a new one.": [
- ""
+ "Include new information": [
+ "Include new information"
],
- "The designated AML session is not enabled, contact administrator or create a new one.": [
+ "This step is optional. Select a form to attach newly reviewed AML/KYC information, or continue without one.": [
""
],
- "High risk accounts. Only with custom rules.": [
+ "AML/KYC form": [
""
],
- "Account with custom rules.": [
- ""
+ "Search AML/KYC forms": [
+ "Search AML/KYC forms"
],
- "High risk accounts": [
+ "Full name used in the payto URI when creating this previously unknown account.": [
""
],
- "All known accounts.": [
+ "Record the facts and reasoning needed to understand this decision in a later audit or review.": [
""
],
- "High risk accounts under investigation. Only with custom rules.": [
+ "Combine a customer check with an AML program, or use SKIP to run a program immediately. Context values must satisfy the selected check and program requirements.": [
""
],
- "Accounts under investigation. Only with custom rules.": [
- ""
+ "Add custom measure": [
+ "Add custom measure"
],
- "High risk accounts under investigation.": [
+ "Save changes": [
""
],
- "Accounts under investigation.": [
+ "Use advanced measure editor": [
""
],
- "High risk accounts without investigation. Only with custom rules.": [
- ""
+ "There is already a measure with that name": [
+ "There is already a measure with that name"
],
- "Accounts without investigation. Only with custom rules.": [
+ "Runs immediately for SKIP measures, or after a successful check. It may be omitted for a check that only presents or collects information.": [
""
],
- "High risk accounts without investigation.": [
- ""
+ "Missing check or program": [
+ "Missing check or program"
],
- "Accounts without investigation.": [
+ "The customer-facing check to perform before the program. Leave empty to use SKIP and run the program immediately.": [
""
],
- "Failed to download": [
+ "Configuration values required by the selected check or program. Property names and value types must match the exchange configuration.": [
""
],
- "There are no accounts in the resultset.": [
- ""
+ "Field name": [
+ "Field name"
],
- "The format requested is not acceptable from the service provider.": [
- ""
+ "Type": [
+ "Type"
],
- "Authorization denied for this session.": [
- ""
+ "string": [
+ "string"
],
- "The session is disabled. Contact the administrator": [
- ""
+ "number": [
+ "number"
],
- "Accounts": [
- ""
+ "boolean": [
+ "boolean"
],
- "Export as file": [
- ""
+ "json": [
+ "json"
],
- "No results": [
- ""
+ "There are unsatisfied inputs: %1$s": [
+ "There are unsatisfied inputs: %1$s"
],
- "#": [
+ "Check \"%1$s\" is not available": [
""
],
- "Account Identification": [
- ""
+ "There are missing inputs: %1$s": [
+ "There are missing inputs: %1$s"
],
- "Open time": [
- ""
+ "There are missing requirements: %1$s": [
+ "There are missing requirements: %1$s"
],
- "Status": [
- ""
+ "Can't be empty": [
+ "Can't be empty"
],
- "From %1$s %2$s To %3$s": [
- ""
+ "Not a number": [
+ "Not a number"
],
- "Since %1$s": [
- ""
+ "It should be finite": [
+ "It should be finite"
],
- "Not opened": [
- ""
+ "It should be either \"true\" or \"false\"": [
+ "It should be either \"true\" or \"false\""
],
- "High risk": [
- ""
+ "Couldn't parse as json string: %1$s": [
+ "Couldn't parse as json string: %1$s"
],
- "With custom rules": [
- ""
+ "Description": [
+ "Description"
],
- "Invalid account": [
- ""
+ "Inputs": [
+ "Inputs"
],
- "Search by ID": [
- ""
+ "Fallback": [
+ "Fallback"
],
- "Under investigation: ": [
+ "Selected pipeline": [
""
],
- "High risk:": [
+ "Review how the exchange will execute this measure.": [
""
],
- "Custom rules:": [
- ""
+ "Name of the verification measure": [
+ "Name of the verification measure"
],
- "Dashboard": [
- ""
+ "Read only": [
+ "Read only"
],
- "Failed to load TOPS statistics.": [
- ""
+ "Prevent the customer from changing the address": [
+ "Prevent the customer from changing the address"
],
- "Statistics": [
+ "Customer actions after submission": [
""
],
- "Accounts open": [
+ "Immediate measures start as soon as this decision is accepted. A measure may show information, collect customer data, or run an AML program. Leave the selection empty when no immediate customer action is required.": [
""
],
- "New files last year": [
- ""
+ "Too many SKIP measures": [
+ "Too many SKIP measures"
],
- "Closed files last year": [
- ""
+ "At most one immediate measure may use the SKIP check.": [
+ "At most one immediate measure may use the SKIP check."
],
- "MROS substantiated": [
- ""
+ "Custom measures": [
+ "Custom measures"
],
- "MROS simple": [
+ "Edit": [
""
],
- "High risk files": [
+ "Reusable templates configured by the exchange operator": [
""
],
- "PEP files": [
+ "Use as template": [
""
],
- "Number of accounts that are opened": [
+ "Selected measures begin immediately after the decision is accepted by the exchange.": [
""
],
- "Number of new GwG files in the last year": [
- ""
+ "Failed to make the decision.": [
+ "Failed to make the decision."
],
- "Number of GwG files closed in the last year": [
- ""
+ "Invalid credentials.": [
+ "Invalid credentials."
],
- "Number of MROS reports based on Art 9 Abs. 1 GwG (per year)": [
- ""
+ "Session not found. Contact the administrator.": [
+ "Session not found. Contact the administrator."
],
- "Number of MROS reports based on Art 305ter Abs. 2 StGB (per year)": [
+ "The exchange rejected the decision because the officer session is disabled or the account has a newer decision. Reload the account before trying again.": [
""
],
- "Number of GwG files of high-risk customers": [
+ "This decision records that an MROS report was filed. Confirm that the report has actually been submitted before continuing.": [
""
],
- "Number of GwG files managed with “increased risk” due to PEP status": [
- ""
+ "Confirm decision": [
+ "Confirm decision"
],
- "Number of customers with open proceeding.": [
- ""
+ "Unknown measure": [
+ "Unknown measure"
],
- "previous": [
- ""
+ "A rule or immediate action references a measure that is not available. Review the rules and measures before submitting.": [
+ "A rule or immediate action references a measure that is not available. Review the rules and measures before submitting."
],
- "Decreased by": [
+ "A custom measure references an unavailable check or program, lacks required context, or cannot provide the selected program inputs. Review the immediate measures before submitting.": [
""
],
- "Increased by": [
- ""
+ "Missing deadline": [
+ "Missing deadline"
],
- "Events": [
+ "Set when the proposed rules expire and what should happen afterward.": [
""
],
- "The events will be triggered only after the decision has been confirmed.": [
+ "Invalid rule expiration": [
""
],
- "Calculated": [
+ "Rule expiration must be in the future or set to Never.": [
""
],
- "Events based on properties and new attributes that should be triggered": [
+ "Missing rules": [
+ "Missing rules"
+ ],
+ "A decision must contain the complete rule set that will apply to the account.": [
""
],
- "Others": [
+ "Review the proposed rules. Hard blocks must be explicit, and Balance and Refund rules must use an instant timeframe.": [
""
],
- "Events that can be triggered manually": [
+ "Immediate measures not reviewed": [
""
],
- "Custom list": [
+ "No measure will start when this decision is submitted.": [
""
],
- "Events without built-in support.": [
+ "Review the account properties before submitting the decision.": [
""
],
- "Complete the form": [
+ "Reporting events not reviewed": [
""
],
- "These measures will ask the customer for information.": [
+ "Review which statistical events will be recorded with the decision.": [
""
],
- "change form": [
+ "Case disposition incomplete": [
""
],
- "Expiration date of the information filled in this form.": [
- ""
+ "You must complete the justification section.": [
+ "You must complete the justification section."
],
- "Include new information": [
- ""
+ "Invalid attributes": [
+ "Invalid attributes"
],
- "Select a form to submit new information about the customer or continue to the next step": [
+ "Correct the selected form or continue without attaching new customer information.": [
""
],
- "Form:": [
- ""
+ "Decision details": [
+ "Decision details"
],
"Justification": [
- ""
+ "Justification"
],
- "Keep investigation?": [
- ""
+ "Not provided": [
+ "Not provided"
],
- "Account holder": [
- ""
+ "The account will not remain under investigation.": [
+ "The account will not remain under investigation."
],
- "Full name of the account holder": [
- ""
+ "Events": [
+ "Events"
],
- "loading...": [
- ""
+ "No events": [
+ "No events"
],
- "Update": [
- ""
+ "Submitted attributes": [
+ "Submitted attributes"
],
- "Remove": [
- ""
+ "expiration set": [
+ "expiration set"
],
- "Configure verification type: %1$s": [
- ""
+ "No new attributes": [
+ "No new attributes"
],
- "Show complete form": [
+ "All entries made in this decision wizard will be lost. No change will be submitted to the exchange.": [
""
],
- "Configure measure": [
- ""
+ "Payto URI": [
+ "Payto URI"
],
- "Show as verification": [
- ""
+ "Decision steps": [
+ "Decision steps"
],
- "There is already a measure with that name": [
- ""
+ "Previous step": [
+ "Previous step"
],
- "Only required when no check is specified": [
- ""
+ "Next step": [
+ "Next step"
],
- "Missing check or program": [
- ""
+ "Account properties": [
+ "Account properties"
],
- "Without a check the program will run automatically": [
+ "Review the account state derived from the available information.": [
""
],
- "Field name": [
+ "Review the statistical events recorded with this decision.": [
""
],
- "Type": [
+ "Set operation thresholds, escalation measures, and expiration behavior.": [
""
],
- "string": [
+ "Case disposition": [
""
],
- "number": [
+ "Check the complete decision before signing and submitting it.": [
""
],
- "boolean": [
- ""
+ "Enter a valid HTTP or HTTPS URL.": [
+ "Enter a valid HTTP or HTTPS URL."
],
- "json": [
- ""
+ "Development settings": [
+ "Development settings"
],
- "Value": [
- ""
+ "These browser-local settings are intended for development and troubleshooting.": [
+ "These browser-local settings are intended for development and troubleshooting."
],
- "There are unsatisfied inputs: %1$s": [
- ""
+ "Exchange connection": [
+ "Exchange connection"
],
- "There are missing inputs: %1$s": [
- ""
+ "Changing the exchange reloads the application. The override is stored only in this browser.": [
+ "Changing the exchange reloads the application. The override is stored only in this browser."
],
- "There are missing requirements: %1$s": [
- ""
+ "Exchange base URL": [
+ "Exchange base URL"
],
- "Can't be empty": [
- ""
+ "Leave empty to use the configured URL: %1$s": [
+ "Leave empty to use the configured URL: %1$s"
],
- "It should be a number": [
- ""
+ "Leave empty to derive the exchange URL from this page.": [
+ "Leave empty to derive the exchange URL from this page."
],
- "Not a number": [
- ""
+ "Currently connected to": [
+ "Currently connected to"
],
- "It should be finite": [
- ""
+ "Apply and reload": [
+ "Apply and reload"
],
- "It should be a safe integer": [
- ""
+ "Use configured URL": [
+ "Use configured URL"
],
- "It should be either \"true\" or \"false\"": [
- ""
+ "Preferences": [
+ "Preferences"
],
- "Couldn't parse as json string: %1$s": [
+ "AML SPA dialect": [
""
],
- "Description": [
+ "Testing": [
""
],
- "Inputs": [
- ""
+ "Show debug information": [
+ "Show debug information"
],
- "Output": [
+ "Fallback dialect for development and testing.": [
""
],
- "Requires": [
+ "TOPS": [
""
],
- "Fallback": [
+ "Taler Operations deployment for Swiss AML processes.": [
""
],
- "Name of the verification measure": [
- ""
+ "File note": [
+ "File note"
],
- "Read only": [
+ "Text": [
""
],
- "Prevent the customer from changing the address": [
- ""
+ "Customer label": [
+ "Customer label"
],
- "Configure verification measure: \"%1$s\"": [
- ""
+ "Account open": [
+ "Account open"
],
- "Add custom measure": [
- ""
+ "Domestic PEP": [
+ "Domestic PEP"
],
- "Custom measures": [
+ "Whether the customer is a domestic politically exposed person.": [
""
],
- "Server measures": [
- ""
+ "Foreign PEP": [
+ "Foreign PEP"
],
- "New measures": [
+ "Whether the customer is a foreign politically exposed person.": [
""
],
- "Measures that are available/executed directly after the decision is confirmed.": [
- ""
+ "International-organization PEP": [
+ "International-organization PEP"
],
- "Reset to default": [
+ "Whether the customer is a politically exposed person associated with an international organization.": [
""
],
- "Properties": [
- ""
+ "High-risk customer": [
+ "High-risk customer"
],
- "Custom properties": [
- ""
+ "High-risk country": [
+ "High-risk country"
],
- "Add more properties that are not listed above.": [
+ "Whether the customer is associated with a high-risk country.": [
""
],
- "New properties": [
- ""
+ "Account idle": [
+ "Account idle"
],
- "Current note on the GwG file": [
+ "Whether the account has been marked as idle.": [
""
],
- "Customer name or internal alias.": [
+ "Score from 0 (no match) to 1,000,000,000 (best match).": [
""
],
- "Is the account active for deposit and payments?": [
+ "Integer": [
""
],
- "Is the account idle?": [
+ "Score from 0 (no supporting data) to 1,000,000,000 (highest confidence).": [
""
],
- "No operation for a period of time": [
+ "Whether this account's sanction-list hit is treated as a false positive.": [
""
],
- "Does account belong to a domestic PEP?": [
+ "Recorded when an account changes to open.": [
""
],
- "Does account belong to a foreign PEP?": [
+ "Recorded when an account changes from open to closed.": [
""
],
- "Does account belong to an international-organization PEP?": [
+ "Recorded when an open account becomes classified as a high-risk customer.": [
""
],
- "Does account belong to a high risk customer?": [
+ "Recorded when the high-risk customer classification is removed.": [
""
],
- "Does account belong to a person from a high risk country?": [
+ "Recorded when an open account becomes associated with a high-risk country.": [
""
],
- "The MROS reporting state for the account.": [
+ "High-risk country classification removed": [
""
],
- "None": [
+ "Recorded when the high-risk country classification is removed.": [
""
],
- "Pending investigation": [
+ "PEP classification added": [
""
],
- "Investigated without suspicion": [
+ "Recorded when an open account becomes associated with any PEP category.": [
""
],
- "Reported simple suspicion": [
+ "Recorded when the account is no longer associated with any PEP category.": [
""
],
- "Reported substantiated suspicion": [
+ "Foreign PEP classification added": [
""
],
- "Informal reason why the AML investigation was triggered": [
+ "Recorded when an open account becomes associated with a foreign PEP.": [
""
],
- "Identifies the sanction list entry that the account matched against": [
+ "Foreign PEP classification removed": [
""
],
- "Best match, does not mean it was a good match.": [
+ "Recorded when the foreign PEP classification is removed.": [
""
],
- "Score for how good the sanction list match was": [
+ "Domestic PEP classification added": [
""
],
- "Score for how much supporting data we had for the sanction list match": [
+ "Recorded when an open account becomes associated with a domestic PEP.": [
""
],
- "Suppress flagging this account when it creates a hit on a sanctions list, this is a false-positive": [
+ "Domestic PEP classification removed": [
""
],
- "Failed to make the decision.": [
+ "Recorded when the domestic PEP classification is removed.": [
""
],
- "Invalid credentials.": [
+ "Recorded when the international-organization PEP classification is removed.": [
""
],
- "The session is disabled or a more recent decision was already submitted.": [
+ "Simple suspicion reported to MROS": [
""
],
- "Confirmation required": [
+ "Recorded when a report is filed under Article 305ter paragraph 2 StGB.": [
""
],
- "This decision declares that the MROS report has concluded. Please make sure that this is the case": [
+ "Recorded when a report is filed under Article 9 GwG.": [
""
],
- "I want to check first!": [
+ "Recorded when a pending special clarification is concluded.": [
""
],
- "Confirm decision": [
+ "Recorded when a previously concluded investigation returns to a non-concluded state.": [
""
],
- "Missing deadline": [
+ "Browser override": [
""
],
- "Deadline should specify when this rules ends and what is the next measures to apply after expiration.": [
+ "Exchange identity, the active AML dialect, and the checks and programs available to AML decisions.": [
""
],
- "Missing rules": [
+ "Public information reported by this exchange.": [
""
],
- "Can't make a decision without rules.": [
+ "Base URL": [
""
],
- "Missing active measure": [
+ "Protocol": [
""
],
- "You should specify in the measure section.": [
+ "Protocol version": [
""
],
- "No customer action required.": [
+ "Currency": [
""
],
- "No active measure has been selected.": [
+ "AML dialect": [
""
],
- "Missing properties": [
+ "Canonical properties defined by the effective dialect.": [
""
],
- "You should specify in the properties section.": [
+ "This dialect does not define derived events.": [
""
],
- "Missing events": [
+ "Checks, programs, root measures, and default rules reported by the exchange.": [
""
],
- "You should specify in the events section.": [
+ "%1$s entry": [
""
],
- "Missing justification": [
+ "%1$s entries": [
""
],
- "You must complete the justification section.": [
+ "No root measures are configured.": [
""
],
- "Invalid attributes": [
+ "No KYC checks are configured.": [
""
],
- "You should check form errors or submit a decision without attributes.": [
+ "No AML programs are configured.": [
""
],
- "Clear": [
+ "No default AML rules are configured.": [
""
],
- "Send decision": [
+ "Built-in check that proceeds without collecting customer data.": [
""
],
- "Prev": [
+ "Voluntary": [
""
],
- "Next": [
- ""
+ "Session and access": [
+ "Session and access"
],
- "Attributes": [
- ""
+ "Review this officer's exchange access and manage the unlocked key in this browser.": [
+ "Review this officer's exchange access and manage the unlocked key in this browser."
],
- "Add more information about the customer": [
- ""
+ "Officer access": [
+ "Officer access"
],
- "Rules": [
- ""
+ "Officer name": [
+ "Officer name"
],
- "Set the limit of the operations": [
- ""
+ "Permissions": [
+ "Permissions"
],
- "Trigger notifications.": [
- ""
+ "Read-only": [
+ "Read-only"
],
- "Measures": [
- ""
+ "Read and write": [
+ "Read and write"
],
- "Ask the customer to take action.": [
- ""
+ "Session security": [
+ "Session security"
],
- "Describe the decision.": [
- ""
+ "Lock the session when you leave this device unattended.": [
+ "Lock the session when you leave this device unattended."
],
- "Flag the current account state.": [
- ""
+ "Lock now": [
+ "Lock now"
],
- "Summary": [
- ""
+ "Unlocked": [
+ "Unlocked"
],
- "Review and submit.": [
- ""
+ "Locks automatically": [
+ "Locks automatically"
],
- "Decision for account:": [
- ""
+ "Exact time": [
+ "Exact time"
],
- "Decision for wallet:": [
- ""
+ "Officer public key": [
+ "Officer public key"
],
- "Decision for bank account:": [
- ""
+ "Copy public key": [
+ "Copy public key"
],
- "Search account": [
- ""
+ "Remove key from this browser": [
+ "Remove key from this browser"
+ ],
+ "Removing this key deletes the officer key from this browser. It does not revoke or change the officer's access at the exchange. Ask the exchange operator to revoke access if needed.": [
+ "Removing this key deletes the officer key from this browser. It does not revoke or change the officer's access at the exchange. Ask the exchange operator to revoke access if needed."
+ ],
+ "Remove key": [
+ "Remove key"
+ ],
+ "Remove officer key?": [
+ "Remove officer key?"
+ ],
+ "This deletes the officer key from this browser. You will need to create and enroll a new key to use the AML WebUI here again.": [
+ "This deletes the officer key from this browser. You will need to create and enroll a new key to use the AML WebUI here again."
+ ],
+ "This does not revoke the officer at the exchange. Ask the exchange operator to revoke its access if the key may be compromised.": [
+ "This does not revoke the officer at the exchange. Ask the exchange operator to revoke its access if the key may be compromised."
+ ],
+ "Find account": [
+ "Find account"
+ ],
+ "Look up an account by its payto information or normalized payto hash.": [
+ "Look up an account by its payto information or normalized payto hash."
+ ],
+ "Find by payto": [
+ "Find by payto"
+ ],
+ "Find by normalized payto hash": [
+ "Find by normalized payto hash"
+ ],
+ "Enter a valid 52-character normalized payto hash.": [
+ "Enter a valid 52-character normalized payto hash."
+ ],
+ "Open account": [
+ "Open account"
],
"Failed to load account decisions.": [
- ""
+ "Failed to load account decisions."
],
"Failed to load the account history.": [
- ""
+ "Failed to load the account history."
],
- "Check account details": [
- ""
+ "This session signature is invalid, contact administrator or create a new one.": [
+ "This session signature is invalid, contact administrator or create a new one."
],
- "Account most recent decisions": [
- ""
+ "The designated AML session is not known, contact administrator or create a new one.": [
+ "The designated AML session is not known, contact administrator or create a new one."
],
- "When": [
- ""
+ "The designated AML session is not enabled, contact administrator or create a new one.": [
+ "The designated AML session is not enabled, contact administrator or create a new one."
],
- "LATEST": [
+ "This account has an AML decision history. Open its case to review current rules, measures, attributes, and past decisions.": [
""
],
- "ACTIVE": [
+ "Active": [
""
],
"Account not found": [
- ""
+ "Account not found"
],
"There is no history known for this account yet.": [
- ""
- ],
- "You can make a decision for this account anyway.": [
- ""
+ "There is no history known for this account yet."
],
"Search": [
- ""
- ],
- "IBAN": [
- ""
+ "Search"
],
"Taler Bank": [
- ""
+ "Taler Bank"
],
"Wallet": [
- ""
+ "Wallet"
],
"Generic Payto:// URI": [
- ""
+ "Generic Payto:// URI"
],
"Account type": [
- ""
+ "Account type"
],
"Should be 52 characters.": [
- ""
+ "Should be 52 characters."
],
"Failed to parse: %1$s": [
- ""
+ "Failed to parse: %1$s"
],
"Address contains invalid characters.": [
- ""
+ "Address contains invalid characters."
],
"Can't mix uppercased and lowercased characters.": [
- ""
+ "Can't mix uppercased and lowercased characters."
],
"The addr checksum doesn't match.": [
- ""
+ "The addr checksum doesn't match."
],
"Missing separator or address type.": [
- ""
+ "Missing separator or address type."
],
"Address should have less than 90 characters.": [
- ""
+ "Address should have less than 90 characters."
],
"Address should have more than 6 characters.": [
- ""
+ "Address should have more than 6 characters."
],
"Decoding issue.": [
- ""
+ "Decoding issue."
],
"Invalid data": [
- ""
+ "Invalid data"
],
"Unsupported country.": [
- ""
+ "Unsupported country."
],
"IBANs have fewer than 34 characters.": [
- ""
+ "IBANs have fewer than 34 characters."
],
"IBANs have more than 4 characters.": [
- ""
+ "IBANs have more than 4 characters."
],
"IBAN length is invalid for this country.": [
"IBAN length is invalid for this country."
],
"It should only contain numbers and letters.": [
- ""
+ "It should only contain numbers and letters."
],
"The checksum is wrong.": [
- ""
+ "The checksum is wrong."
],
"The string should start with payto://": [
- ""
+ "The string should start with payto://"
],
"After the target type it should follow a '/' with more information.": [
- ""
+ "After the target type it should follow a '/' with more information."
],
"The target type is not supported, only x-taler-bank, taler-reserve or iban": [
- ""
+ "The target type is not supported, only x-taler-bank, taler-reserve or iban"
],
"IBAN is missing": [
- ""
+ "IBAN is missing"
],
"Bitcoin address is missing": [
- ""
+ "Bitcoin address is missing"
],
"Bank host and account is missing": [
- ""
+ "Bank host and account is missing"
],
"Exchange host and account is missing": [
- ""
+ "Exchange host and account is missing"
],
"Ethereum address is missing": [
- ""
+ "Ethereum address is missing"
],
"Cyclos address is missing": [
- ""
+ "Cyclos address is missing"
],
"Void address is missing": [
- ""
+ "Void address is missing"
],
"Invalid IBAN: %1$s": [
- ""
+ "Invalid IBAN: %1$s"
],
"Invalid BTC: %1$s": [
- ""
+ "Invalid BTC: %1$s"
],
"Invalid reserve: %1$s": [
- ""
+ "Invalid reserve: %1$s"
],
"Invalid host": [
- ""
+ "Invalid host"
],
- "Invalid address": [
- ""
+ "Invalid account": [
+ "Invalid account"
],
- "Payto URI": [
- ""
+ "Invalid address": [
+ "Invalid address"
],
"As defined by RFC 8905": [
- ""
+ "As defined by RFC 8905"
],
"payto://": [
- ""
+ "payto://"
],
"International Bank Account Number": [
- ""
+ "International Bank Account Number"
],
"DE1231231231": [
- ""
+ "DE1231231231"
],
"Host": [
- ""
+ "Host"
],
"Exchange hostname": [
- ""
+ "Exchange hostname"
],
"exchange.taler.net": [
- ""
+ "exchange.taler.net"
],
"Remove last '/'": [
- ""
+ "Remove last '/'"
],
"Invalid value": [
- ""
+ "Invalid value"
],
"ID": [
- ""
+ "ID"
],
"Wallet reserve public key": [
- ""
+ "Wallet reserve public key"
],
"abcdef1235": [
- ""
+ "abcdef1235"
],
"Should be 52 characters": [
- ""
- ],
- "Account": [
- ""
+ "Should be 52 characters"
],
"Bank account identification": [
- ""
+ "Bank account identification"
],
"DE123123123": [
- ""
+ "DE123123123"
],
"Hostname": [
- ""
+ "Hostname"
],
"Without the scheme, may include subpath: bank.com, bank.com/path/": [
- ""
- ],
- "bank.demo.taler.net": [
- ""
- ],
- "Invalid hostname": [
- ""
- ],
- "Failed to load the account information.": [
- ""
- ],
- "Different form version": [
- ""
- ],
- "The collected information don't have the form version used.": [
- ""
- ],
- "The collected information used the form version \"%1$s \" but is not available.": [
- ""
- ],
- "Case details": [
- ""
- ],
- "Next event": [
- ""
- ],
- "Previous event": [
- ""
- ],
- "Direction": [
- ""
- ],
- "Credit": [
- ""
- ],
- "Debit": [
- ""
- ],
- "KYC Auth": [
- ""
- ],
- "Minimum amount": [
- ""
- ],
- "All amounts below the given threshold will be filtered.": [
- ""
+ "Without the scheme, may include subpath: bank.com, bank.com/path/"
],
- "Failed to load transfer list.": [
- ""
+ "bank.demo.taler.net": [
+ "bank.demo.taler.net"
],
- "Failed to load the transfer list.": [
- ""
+ "Invalid hostname": [
+ "Invalid hostname"
],
- "Select transaction type": [
- ""
+ "Failed to load account information.": [
+ "Failed to load account information."
],
- "Please select a transaction type to show transactions.": [
- ""
+ "Failed to load the account information.": [
+ "Failed to load the account information."
],
- "Transfers history for account": [
- ""
+ "Collection event not found": [
+ "Collection event not found"
],
- "Transfers history": [
- ""
+ "There is no collection event with ID %1$s for this account.": [
+ "There is no collection event with ID %1$s for this account."
],
- "No transfers yet.": [
- ""
+ "Attributes unavailable": [
+ "Attributes unavailable"
],
- "There are no transfers for this account.": [
- ""
+ "The collection event does not contain readable attributes.": [
+ "The collection event does not contain readable attributes."
],
- "There are no transfers reported to the exchange with the current threshold.": [
- ""
+ "Form identifier missing": [
+ "Form identifier missing"
],
- "Date": [
- ""
+ "The collected information does not identify the form used to create it.": [
+ "The collected information does not identify the form used to create it."
],
- "Amount": [
- ""
+ "Form not available": [
+ "Form not available"
],
- "sent": [
- ""
+ "Form %1$s is not configured in this AML Web UI.": [
+ "Form %1$s is not configured in this AML Web UI."
],
- "received": [
+ "Source": [
""
],
- "to": [
- ""
+ "Different form version": [
+ "Different form version"
],
- "from": [
+ "The collected information does not identify the form version used. The latest configured version is shown and field labels may differ from those used at collection time.": [
""
],
- "Welcome to the exchange configuration": [
+ "JSON view": [
""
],
- "Transfers": [
+ "Incoming": [
""
],
- "Profile": [
+ "Outgoing": [
""
],
- "Failed to load server measures.": [
+ "KYC authorization": [
""
],
- "Failed to load the measures": [
+ "Wallet credits (P2P)": [
""
],
- "A list of all the predefined measures you can use.": [
- ""
+ "Minimum amount": [
+ "Minimum amount"
],
- "Failed to load available measures.": [
- ""
+ "All amounts below the given threshold will be filtered.": [
+ "All amounts below the given threshold will be filtered."
],
- "The officer session is invalid.": [
+ "Inspect successful P2P credits received by this wallet. Requests that were not paid are not shown.": [
""
],
- "The measures endpoint was not found.": [
+ "Inspect effective bank transfers observed by the exchange. Credit transfers are incoming, debit transfers are outgoing, and bounced or drain transfers are not included.": [
""
],
- "The officer session is disabled.": [
+ "Inspect effective transfers observed by the exchange. Incoming, outgoing, and KYC authorization entries are bank transfers. Wallet credits are successful P2P transfers into wallets.": [
""
],
- "Failed to load the active AML decision.": [
- ""
+ "Failed to load transfer list.": [
+ "Failed to load transfer list."
],
- "The officer session signature is invalid.": [
- ""
+ "Failed to load the transfer list.": [
+ "Failed to load the transfer list."
],
- "The requested AML account or session was not found.": [
- ""
+ "Select transaction type": [
+ "Select transaction type"
],
- "The officer session is disabled or the account state changed.": [
- ""
+ "Please select a transaction type to show transactions.": [
+ "Please select a transaction type to show transactions."
],
- "Invalid expiration": [
- ""
+ "No transfers yet.": [
+ "No transfers yet."
],
- "Attributes require an expiration date in the future.": [
- ""
+ "There are no transfers for this account.": [
+ "There are no transfers for this account."
],
- "Too many SKIP measures": [
- ""
+ "There are no transfers reported to the exchange with the current threshold.": [
+ "There are no transfers reported to the exchange with the current threshold."
],
- "At most one immediate measure may use the SKIP check.": [
- ""
+ "Unknown date": [
+ "Unknown date"
],
- "Require all measures": [
- ""
+ "Time": [
+ "Time"
],
- "Run all selected measures together instead of accepting any one of them.": [
- ""
+ "Amount": [
+ "Amount"
],
- "Invalid custom properties": [
- ""
+ "Unknown time": [
+ "Unknown time"
],
- "Custom property names and values must be non-empty and names must be unique and different from built-in properties.": [
- ""
+ "sent": [
+ "sent"
],
- "Unknown measure": [
- ""
+ "received": [
+ "received"
],
- "A rule or immediate action references a measure that is not available. Review the rules and measures before submitting.": [
- ""
+ "to": [
+ "to"
],
- "Requires investigation": [
- ""
+ "from": [
+ "from"
],
- "Collection event not found": [
- ""
+ "This exchange is not compatible with the AML WebUI.": [
+ "This exchange is not compatible with the AML WebUI."
],
- "There is no collection event with ID %1$s for this account.": [
- ""
+ "Officer identity and permissions require exchange protocol v40 or newer.": [
+ "Officer identity and permissions require exchange protocol v40 or newer."
],
- "Attributes unavailable": [
- ""
+ "Verifying that this public key is enrolled by the exchange.": [
+ "Verifying that this public key is enrolled by the exchange."
],
- "The collection event does not contain readable attributes.": [
- ""
+ "Read-only officer access": [
+ "Read-only officer access"
],
- "Form identifier missing": [
- ""
+ "You can review AML information, but this officer key cannot submit decisions.": [
+ "You can review AML information, but this officer key cannot submit decisions."
],
- "The collected information does not identify the form used to create it.": [
- ""
+ "This officer key cannot create or submit AML decisions.": [
+ "This officer key cannot create or submit AML decisions."
],
- "Form not available": [
- ""
+ "Return to account": [
+ "Return to account"
],
- "Form %1$s is not configured in this AML Web UI.": [
- ""
+ "Failed to load the active AML decision.": [
+ "Failed to load the active AML decision."
],
"The account was not found.": [
- ""
+ "The account was not found."
],
"The account state changed. Reload it and try again.": [
- ""
+ "The account state changed. Reload it and try again."
],
"The payto URI does not belong to this account. Return to the account search and start the decision again.": [
- ""
+ "The payto URI does not belong to this account. Return to the account search and start the decision again."
],
- "This account has no active decision and its payto URI is unknown. Start the decision from the account search so the account type can be determined safely.": [
- ""
+ "Session": [
+ "Session"
],
- "Return to account": [
- ""
+ "AML navigation": [
+ "AML navigation"
+ ],
+ "Failed to load server measures.": [
+ "Failed to load server measures."
+ ],
+ "Failed to load the measures": [
+ "Failed to load the measures"
+ ],
+ "Measures": [
+ "Measures"
+ ],
+ "A list of all the predefined measures you can use.": [
+ "A list of all the predefined measures you can use."
],
"threshold\u0004%1$s every %2$s": [
""
],
"operation type\u0004Withdraw": [
- ""
+ "Withdraw"
],
"operation type\u0004Deposit": [
- ""
+ "Deposit"
],
"operation type\u0004Merge": [
- ""
+ "Merge"
],
"operation type\u0004Aggregate": [
- ""
+ "Aggregate"
],
"operation type\u0004Balance": [
- ""
+ "Balance"
],
"operation type\u0004Refund": [
- ""
+ "Refund"
],
"operation type\u0004Close": [
- ""
+ "Close"
],
"operation type\u0004Transaction": [
- ""
+ "Transaction"
]
}
},
@@ -5261,9 +8210,6 @@ strings['de'] = {
"lang": "de",
"plural_forms": ""
},
- "Use testing dialect": [
- "Test-Dialekt verwenden"
- ],
"Allow Insecure password": [
"Unsichere Passwörter erlauben"
],
@@ -5273,8 +8219,11 @@ strings['de'] = {
"Don't compress request": [
"Anfragen nicht komprimieren"
],
- "Preferences": [
- "Einstellungen"
+ "Lock session": [
+ "Sitzung sperren"
+ ],
+ "Lock": [
+ "Sperren"
],
"Password": [
"Passwort"
@@ -5288,35 +8237,266 @@ strings['de'] = {
"should have lowercase and uppercase characters": [
"sollte Klein- und Großbuchstaben enthalten"
],
- "should have numbers": [
- "sollte Zahlen enthalten"
+ "should have numbers": [
+ "sollte Zahlen enthalten"
+ ],
+ "should have at least one character which is not a number or letter": [
+ "sollte mindestens ein Zeichen enthalten, das keine Zahl oder kein Buchstabe ist"
+ ],
+ "Repeat password": [
+ "Passwort wiederholen"
+ ],
+ "doesn't match": [
+ "stimmt nicht überein"
+ ],
+ "Create": [
+ "Erstellen"
+ ],
+ "Wallet account": [
+ "Wallet-Konto"
+ ],
+ "Bank account": [
+ "Bankkonto"
+ ],
+ "Under investigation": [
+ "In Untersuchung"
+ ],
+ "High risk": [
+ "Hohes Risiko"
+ ],
+ "Payment target type": [
+ ""
+ ],
+ "Account holder": [
+ "Kontoinhaber"
+ ],
+ "IBAN": [
+ "IBAN"
+ ],
+ "BIC": [
+ ""
+ ],
+ "Bank": [
+ ""
+ ],
+ "Account": [
+ "Konto"
+ ],
+ "Taler bank": [
+ "Taler-Bank"
+ ],
+ "Cyclos": [
+ ""
+ ],
+ "Bitcoin address": [
+ ""
+ ],
+ "Reserve public key": [
+ ""
+ ],
+ "Bitcoin": [
+ ""
+ ],
+ "Ethereum address": [
+ ""
+ ],
+ "Ethereum": [
+ ""
+ ],
+ "Exchange": [
+ ""
+ ],
+ "Taler reserve": [
+ "Taler-Reserve"
+ ],
+ "Taler reserve (HTTP)": [
+ ""
+ ],
+ "Test account": [
+ "Testkonto"
+ ],
+ "Account details unavailable": [
+ ""
+ ],
+ "Not opened": [
+ "Nicht eröffnet"
+ ],
+ "Opened:": [
+ "Eröffnet:"
+ ],
+ "Closed:": [
+ "Geschlossen:"
+ ],
+ "Closed": [
+ "Geschlossen"
+ ],
+ "Open": [
+ "Offen"
+ ],
+ "No note": [
+ "Keine Notiz"
+ ],
+ "Show full note": [
+ "Vollständige Notiz anzeigen"
+ ],
+ "System information": [
+ "Systeminformation"
+ ],
+ "Transactions remain below the threshold that opens an AML file.": [
+ "Die Transaktionen liegen weiterhin unter dem Schwellenwert, ab dem eine AML-Akte eröffnet wird."
+ ],
+ "Account case": [
+ "Kontofall"
+ ],
+ "Failed to download AML file.": [
+ "Die AML-Akte konnte nicht heruntergeladen werden."
+ ],
+ "No AML file is available for this account.": [
+ "Für dieses Konto ist keine AML-Akte verfügbar."
+ ],
+ "Authorization denied for this session. Contact the administrator.": [
+ "Autorisierung für diese Sitzung verweigert. Wenden Sie sich an den Administrator."
+ ],
+ "The account or session was not found.": [
+ "Das Konto oder die Sitzung wurde nicht gefunden."
+ ],
+ "The session is disabled. Contact the administrator.": [
+ "Die Sitzung ist deaktiviert. Wenden Sie sich an den Administrator."
+ ],
+ "The exchange does not support PDF reports.": [
+ "Der Exchange unterstützt keine PDF-Berichte."
+ ],
+ "Read-only officers cannot create AML decisions.": [
+ "Sachbearbeiter mit Lesezugriff können keine AML-Entscheidungen erstellen."
+ ],
+ "A payto URI is required to create a new decision.": [
+ "Zum Erstellen einer neuen Entscheidung ist eine Payto-URI erforderlich."
+ ],
+ "Back to accounts": [
+ "Zurück zu den Konten"
+ ],
+ "File no. %1$s": [
+ "Aktennr. %1$s"
+ ],
+ "New decision": [
+ "Neue Entscheidung"
+ ],
+ "Download AML file (PDF)": [
+ "AML-Akte herunterladen (PDF)"
+ ],
+ "AML file download started.": [
+ "Der Download der AML-Akte wurde gestartet."
+ ],
+ "Try again": [
+ ""
+ ],
+ "Account identifiers": [
+ "Kontokennungen"
+ ],
+ "Technical identifiers": [
+ "Technische Kennungen"
+ ],
+ "Full payto URI": [
+ "Vollständige Payto-URI"
+ ],
+ "Unavailable": [
+ "Nicht verfügbar"
+ ],
+ "Copy payto URI": [
+ "Payto-URI kopieren"
+ ],
+ "Normalized payto hash": [
+ "Normalisierter Payto-Hash"
+ ],
+ "Copy normalized payto hash": [
+ "Normalisierten Payto-Hash kopieren"
+ ],
+ "Account case views": [
+ "Ansichten des Kontofalls"
+ ],
+ "Overview": [
+ "Übersicht"
+ ],
+ "Transfers": [
+ "Überweisungen"
+ ],
+ "Decision history": [
+ "Entscheidungsverlauf"
+ ],
+ "Close": [
+ "Schließen"
+ ],
+ "Cancel": [
+ "Abbrechen"
+ ],
+ "AML officer enrollment request": [
+ "Antrag auf Registrierung eines AML-Sachbearbeiters"
+ ],
+ "Please enroll this AML officer public key:\n\n%1$s": [
+ "Bitte registrieren Sie diesen öffentlichen Schlüssel des AML-Sachbearbeiters:\n\n%1$s"
+ ],
+ "Officer key awaiting enrollment": [
+ "Schlüssel des AML-Sachbearbeiters wartet auf Registrierung"
+ ],
+ "This browser has created an AML officer key, but the exchange has not granted it access. Ask the exchange operator or administrator to enroll the public key below.": [
+ "Dieser Browser hat einen Schlüssel für einen AML-Sachbearbeiter erstellt, aber der Exchange hat ihm noch keinen Zugriff gewährt. Bitten Sie den Betreiber oder Administrator des Exchange, den unten angegebenen öffentlichen Schlüssel zu registrieren."
+ ],
+ "AML officer public key": [
+ "Öffentlicher Schlüssel des AML-Sachbearbeiters"
+ ],
+ "Copy AML officer public key": [
+ "Öffentlichen Schlüssel des AML-Sachbearbeiters kopieren"
+ ],
+ "After the operator confirms enrollment, retry the access check.": [
+ "Nachdem der Betreiber die Registrierung bestätigt hat, prüfen Sie den Zugriff erneut."
+ ],
+ "Retry access check": [
+ "Zugriff erneut prüfen"
+ ],
+ "Checking officer access": [
+ "Zugriff des AML-Sachbearbeiters wird geprüft"
+ ],
+ "Last checked at %1$s": [
+ "Zuletzt geprüft um %1$s"
+ ],
+ "Request enrollment": [
+ "Registrierung anfordern"
+ ],
+ "Discard this key": [
+ "Diesen Schlüssel verwerfen"
+ ],
+ "Confirmation required": [
+ "Bestätigung erforderlich"
+ ],
+ "Discarding this key removes the officer session from this browser. You will need to create a new key to use the AML WebUI again.": [
+ "Wenn Sie diesen Schlüssel verwerfen, wird die Sitzung des AML-Sachbearbeiters aus diesem Browser entfernt. Sie müssen einen neuen Schlüssel erstellen, um die AML-Weboberfläche erneut zu verwenden."
],
- "should have at least one character which is not a number or letter": [
- "sollte mindestens ein Zeichen enthalten, das keine Zahl oder kein Buchstabe ist"
+ "Failed to check AML officer access.": [
+ "Der Zugriff des AML-Sachbearbeiters konnte nicht geprüft werden."
],
- "Repeat password": [
- "Passwort wiederholen"
+ "This officer key cannot authenticate with the exchange. Retry the check or discard the key and create a new session.": [
+ "Dieser Sachbearbeiterschlüssel kann sich nicht beim Exchange authentifizieren. Wiederholen Sie die Prüfung oder verwerfen Sie den Schlüssel und erstellen Sie eine neue Sitzung."
],
- "doesn't match": [
- "stimmt nicht überein"
+ "The exchange rejected the officer access check.": [
+ "Der Exchange hat die Zugriffsprüfung des Sachbearbeiters abgelehnt."
],
- "Create": [
- "Erstellen"
+ "Technical details": [
+ "Technische Details"
],
"Failed to unlock the session.": [
""
],
- "Authorization denied for this session. Contact the administrator.": [
- ""
- ],
"Unlock": [
"Entsperren"
],
+ "Forget session": [
+ "Sitzung vergessen"
+ ],
"There are no rules for operations": [
"Es gibt keine Regeln für Vorgänge"
],
- "Add custom rule": [
- "Benutzerdefinierte Regel hinzufügen"
+ "This means that no operation has any limit.": [
+ "Das bedeutet, dass kein Vorgang begrenzt ist."
],
"Operation": [
"Vorgang"
@@ -5327,14 +8507,53 @@ strings['de'] = {
"Escalation": [
"Eskalation"
],
- "%1$s": [
- "%1$s"
+ "Visibility": [
+ "Sichtbarkeit"
],
- "(all)": [
- "(alle)"
+ "Priority": [
+ "Priorität"
],
- "Since": [
- "Seit"
+ "Actions": [
+ "Aktionen"
+ ],
+ "Block operation": [
+ "Vorgang sperren"
+ ],
+ "All required:": [
+ "Alle erforderlich:"
+ ],
+ "Any one:": [
+ "Eine beliebige:"
+ ],
+ "Customer-visible": [
+ "Für Kunden sichtbar"
+ ],
+ "Internal": [
+ "Intern"
+ ],
+ "Move %1$s rule up": [
+ "%1$s-Regel nach oben verschieben"
+ ],
+ "Move %1$s rule down": [
+ "%1$s-Regel nach unten verschieben"
+ ],
+ "Edit %1$s rule": [
+ "%1$s-Regel bearbeiten"
+ ],
+ "Remove %1$s rule": [
+ "%1$s-Regel entfernen"
+ ],
+ "AML officer justification": [
+ "Begründung des AML-Sachbearbeiters"
+ ],
+ "No justification was recorded.": [
+ "Es wurde keine Begründung erfasst."
+ ],
+ "Operation rules": [
+ "Vorgangsregeln"
+ ],
+ "Decision date": [
+ "Entscheidungsdatum"
],
"Expired": [
"Abgelaufen"
@@ -5345,15 +8564,18 @@ strings['de'] = {
"Successor measure": [
"Nachfolgemaßnahme"
],
- "AML officer justification": [
- "Begründung des AML-Sachbearbeiters"
- ],
- "Default rules": [
- "Standardregeln"
+ "Exchange defaults": [
+ "Exchange-Standardregeln"
],
"Forms": [
"Formulare"
],
+ "Measures used to gather information about the customer.": [
+ "Maßnahmen zur Erfassung von Informationen über den Kunden."
+ ],
+ "Select": [
+ "Auswählen"
+ ],
"Name": [
"Name"
],
@@ -5369,12 +8591,6 @@ strings['de'] = {
"Modify": [
"Ändern"
],
- "Info": [
- "Info"
- ],
- "Will show information to the user.": [
- "Zeigt dem Benutzer Informationen an."
- ],
"Instant measures": [
"Sofortmaßnahmen"
],
@@ -5384,32 +8600,212 @@ strings['de'] = {
"Input requirement": [
"Eingabeanforderung"
],
- "Already completed.": [
- "Bereits abgeschlossen."
+ "Started": [
+ "Begonnen"
],
- "Waiting to be completed.": [
- "Wartet auf Abschluss."
+ "Status": [
+ "Status"
],
- "Current active rules": [
- "Aktuell aktive Regeln"
+ "Forbidden": [
+ "Verboten"
],
- "There are no rules for this account yet.": [
- "Für dieses Konto gibt es noch keine Regeln."
+ "Completed": [
+ "Abgeschlossen"
],
- "New rule form": [
- "Formular für neue Regel"
+ "Waiting for customer": [
+ "Wartet auf den Kunden"
],
- "Add": [
- "Hinzufügen"
+ "The operation is categorically forbidden by this requirement.": [
+ "Der Vorgang ist aufgrund dieser Anforderung grundsätzlich verboten."
],
- "Cancel": [
- "Abbrechen"
+ "All listed measures must be completed.": [
+ "Alle aufgeführten Maßnahmen müssen abgeschlossen werden."
],
- "Basic plan": [
- "Basisplan"
+ "Any one listed measure may be completed.": [
+ "Eine beliebige der aufgeführten Maßnahmen kann abgeschlossen werden."
],
- "Premium": [
- "Premium"
+ "Values may be derived from the selected AML/KYC form. Confirm them against the case record and change only values that require an officer override.": [
+ ""
+ ],
+ "Invalid custom properties": [
+ "Ungültige benutzerdefinierte Eigenschaften"
+ ],
+ "Custom property names and values must be non-empty and names must be unique and different from built-in properties.": [
+ "Namen und Werte benutzerdefinierter Eigenschaften dürfen nicht leer sein; die Namen müssen eindeutig sein und sich von integrierten Eigenschaften unterscheiden."
+ ],
+ "Properties": [
+ "Eigenschaften"
+ ],
+ "Built-in property names are preserved when the decision is submitted.": [
+ ""
+ ],
+ "Custom properties": [
+ "Benutzerdefinierte Eigenschaften"
+ ],
+ "Add more properties that are not listed above.": [
+ "Weitere Eigenschaften hinzufügen, die oben nicht aufgeführt sind."
+ ],
+ "New properties": [
+ "Neue Eigenschaften"
+ ],
+ "Value": [
+ "Wert"
+ ],
+ "Current note on the GwG file": [
+ "Aktuelle Notiz zur GwG-Akte"
+ ],
+ "Customer name or internal alias.": [
+ "Kundenname oder interner Alias."
+ ],
+ "Is the account active for deposit and payments?": [
+ "Ist das Konto für Einzahlungen und Zahlungen aktiv?"
+ ],
+ "Is the account idle?": [
+ "Ist das Konto inaktiv?"
+ ],
+ "No operation for a period of time": [
+ "Keine Vorgänge über einen bestimmten Zeitraum"
+ ],
+ "Does account belong to a domestic PEP?": [
+ "Gehört das Konto zu einer inländischen PEP?"
+ ],
+ "Does account belong to a foreign PEP?": [
+ "Gehört das Konto zu einer ausländischen PEP?"
+ ],
+ "Does account belong to an international-organization PEP?": [
+ "Gehört das Konto zu einer PEP einer internationalen Organisation?"
+ ],
+ "Does account belong to a high risk customer?": [
+ "Gehört das Konto zu einem Hochrisikokunden?"
+ ],
+ "Does account belong to a person from a high risk country?": [
+ "Gehört das Konto zu einer Person aus einem Hochrisikoland?"
+ ],
+ "The MROS reporting state for the account.": [
+ "Der MROS-Meldestatus für das Konto."
+ ],
+ "None": [
+ "Keine"
+ ],
+ "Pending investigation": [
+ "Untersuchung ausstehend"
+ ],
+ "Investigated without suspicion": [
+ "Untersucht, kein Verdacht"
+ ],
+ "Reported simple suspicion": [
+ "Einfacher Verdacht gemeldet"
+ ],
+ "Reported substantiated suspicion": [
+ "Begründeter Verdacht gemeldet"
+ ],
+ "Informal reason why the AML investigation was triggered": [
+ "Informeller Grund für die Auslösung der AML-Untersuchung"
+ ],
+ "Identifies the sanction list entry that the account matched against": [
+ "Identifiziert den Sanktionslisteneintrag, mit dem das Konto übereinstimmte"
+ ],
+ "Best match, does not mean it was a good match.": [
+ "Beste Übereinstimmung, bedeutet nicht, dass es eine gute Übereinstimmung war."
+ ],
+ "Score for how good the sanction list match was": [
+ "Bewertung, wie gut die Übereinstimmung mit der Sanktionsliste war"
+ ],
+ "Integer score from 0 (no match) to 1,000,000,000 (best match).": [
+ ""
+ ],
+ "Score for how much supporting data we had for the sanction list match": [
+ "Bewertung, wie viele Belegdaten für die Übereinstimmung mit der Sanktionsliste vorlagen"
+ ],
+ "Integer score from 0 (no supporting data) to 1,000,000,000 (highest confidence).": [
+ ""
+ ],
+ "Suppress flagging this account when it creates a hit on a sanctions list, this is a false-positive": [
+ "Markierung dieses Kontos unterdrücken, wenn es einen Treffer auf einer Sanktionsliste erzeugt; dies ist ein Fehlalarm"
+ ],
+ "Expiration shortcuts": [
+ "Schnellauswahl für den Ablauf"
+ ],
+ "In a week": [
+ "In einer Woche"
+ ],
+ "In a month": [
+ "In einem Monat"
+ ],
+ "In a year": [
+ "In einem Jahr"
+ ],
+ "Never": [
+ "Nie"
+ ],
+ "Failed to load available measures.": [
+ "Die verfügbaren Maßnahmen konnten nicht geladen werden."
+ ],
+ "The officer session is invalid.": [
+ "Die Sitzung des AML-Sachbearbeiters ist ungültig."
+ ],
+ "The measures endpoint was not found.": [
+ "Der Endpunkt für Maßnahmen wurde nicht gefunden."
+ ],
+ "The officer session is disabled.": [
+ "Die Sitzung des AML-Sachbearbeiters ist deaktiviert."
+ ],
+ "Edit proposed rule": [
+ "Vorgeschlagene Regel bearbeiten"
+ ],
+ "Add proposed rule": [
+ "Vorgeschlagene Regel hinzufügen"
+ ],
+ "Save rule": [
+ "Regel speichern"
+ ],
+ "Add rule": [
+ "Regel hinzufügen"
+ ],
+ "This complete rule set replaces the currently applied rules and exchange defaults until it expires. Higher rows take precedence.": [
+ "Dieser vollständige Regelsatz ersetzt bis zu seinem Ablauf die derzeit angewendeten Regeln und die Standardregeln der Börse. Weiter oben stehende Regeln haben Vorrang."
+ ],
+ "Rules for another account type": [
+ "Regeln für einen anderen Kontotyp"
+ ],
+ "These operations do not apply to this account type: %1$s.": [
+ "Diese Vorgänge gelten nicht für diesen Kontotyp: %1$s."
+ ],
+ "Operations without limits": [
+ "Vorgänge ohne Limits"
+ ],
+ "No proposed rule limits these operations: %1$s.": [
+ "Keine vorgeschlagene Regel begrenzt diese Vorgänge: %1$s."
+ ],
+ "Invalid proposed rules": [
+ "Ungültige vorgeschlagene Regeln"
+ ],
+ "Edit the highlighted rule set before continuing. Hard blocks cannot be combined with measures, and Balance and Refund rules must use an instant timeframe.": [
+ "Bearbeiten Sie den hervorgehobenen Regelsatz, bevor Sie fortfahren. Harte Sperren können nicht mit Maßnahmen kombiniert werden, und Regeln für Saldo und Rückerstattung müssen einen sofortigen Zeitraum verwenden."
+ ],
+ "Remove proposed rule?": [
+ "Vorgeschlagene Regel entfernen?"
+ ],
+ "This is the final rule. Removing it leaves every applicable operation unlimited.": [
+ "Dies ist die letzte Regel. Wenn Sie sie entfernen, bleiben alle zutreffenden Vorgänge unbegrenzt."
+ ],
+ "The rule will be removed from the proposed set.": [
+ "Die Regel wird aus dem vorgeschlagenen Satz entfernt."
+ ],
+ "Keep rule": [
+ "Regel behalten"
+ ],
+ "Remove rule": [
+ "Regel entfernen"
+ ],
+ "Replace proposed rules": [
+ "Vorgeschlagene Regeln ersetzen"
+ ],
+ "Preview a complete replacement before applying it.": [
+ "Zeigen Sie vor der Anwendung eine Vorschau des vollständigen Ersatzes an."
+ ],
+ "Currently applied": [
+ "Derzeit angewendet"
],
"E-commerce": [
"E-Commerce"
@@ -5417,38 +8813,35 @@ strings['de'] = {
"Point of Sale": [
"Point-of-Sale"
],
- "Check rules": [
- "Regeln überprüfen"
- ],
- "The account is a wallet and there are bank account operation's limits which may trigger actions that are not required: %1$s": [
- "Das Konto ist eine Wallet, und es bestehen Limits für Bankkonto-Vorgänge, die möglicherweise nicht erforderliche Aktionen auslösen: %1$s"
+ "Basic plan": [
+ "Basisplan"
],
- "The account isn't a wallet and there are wallet operation's limits which may trigger actions that are not required: %1$s": [
- "Das Konto ist keine Wallet, und es bestehen Limits für Wallet-Vorgänge, die möglicherweise nicht erforderliche Aktionen auslösen: %1$s"
+ "Premium": [
+ "Premium"
],
- "The account is a wallet and there are wallet operation's limits which are not limited: %1$s": [
- "Das Konto ist eine Wallet, und es bestehen Limits für Wallet-Vorgänge, die nicht begrenzt sind: %1$s"
+ "Freeze account": [
+ "Konto einfrieren"
],
- "New rules": [
- "Neue Regeln"
+ "Replacement preview": [
+ "Vorschau des Ersatzes"
],
- "Reset rules to current state": [
- "Regeln auf aktuellen Stand zurücksetzen"
+ "Confirm account freeze": [
+ "Kontosperrung bestätigen"
],
- "Set rules to default": [
- "Regeln auf Standard setzen"
+ "Every applicable operation will receive a zero hard limit.": [
+ "Jeder zutreffende Vorgang erhält ein hartes Limit von null."
],
- "Freeze account": [
- "Konto einfrieren"
+ "Apply replacement": [
+ "Ersatz anwenden"
],
- "Behavior on rule expiration": [
- "Verhalten bei Ablauf der Regel"
+ "Choose how long the proposed rules apply and what happens afterwards.": [
+ "Legen Sie fest, wie lange die vorgeschlagenen Regeln gelten und was danach geschieht."
],
- "Reset measure": [
- "Maßnahme zurücksetzen"
+ "The proposed rules never expire, so no successor action will run.": [
+ "Die vorgeschlagenen Regeln laufen nie ab, daher wird keine Nachfolgeaktion ausgeführt."
],
- "Reset expiration": [
- "Ablauf zurücksetzen"
+ "Restore currently applied expiration": [
+ "Derzeit angewendeten Ablauf wiederherstellen"
],
"Operation type": [
"Vorgangstyp"
@@ -5456,14 +8849,29 @@ strings['de'] = {
"Timeframe": [
"Zeitraum"
],
+ "Use Y, M, D, h, m or s after each number. Forever accumulates over the account's full history.": [
+ "Verwenden Sie Y, M, D, h, m oder s nach jeder Zahl. „Für immer“ summiert über den gesamten Verlauf des Kontos."
+ ],
+ "Instant timeframe": [
+ "Sofortiger Zeitraum"
+ ],
+ "Balance and Refund limits apply to one balance or transaction, so their timeframe is fixed to zero.": [
+ "Limits für Saldo und Rückerstattung gelten für einen einzelnen Saldo beziehungsweise eine einzelne Transaktion; ihr Zeitraum ist daher fest auf null gesetzt."
+ ],
"Exposed": [
"Sichtbar"
],
"Is this limit communicated to the customer?": [
"Wird dieses Limit dem Kunden mitgeteilt?"
],
- "Escalation measure": [
- "Eskalationsmaßnahme"
+ "When the threshold is crossed": [
+ "Wenn der Schwellenwert überschritten wird"
+ ],
+ "Require measures": [
+ "Maßnahmen verlangen"
+ ],
+ "Required measures": [
+ "Erforderliche Maßnahmen"
],
"Measures that the customer will need to satisfy to apply for a new threshold.": [
"Maßnahmen, die der Kunde erfüllen muss, um einen neuen Schwellenwert zu beantragen."
@@ -5474,228 +8882,327 @@ strings['de'] = {
"Hint the customer that all measures should be completed": [
"Den Kunden darauf hinweisen, dass alle Maßnahmen abgeschlossen werden sollten"
],
- "Expiration": [
- "Ablauf"
- ],
- "Predefined shortcuts": [
- "Vordefinierte Schnellauswahl"
- ],
- "In a week": [
- "In einer Woche"
- ],
- "In a month": [
- "In einem Monat"
- ],
- "In a year": [
- "In einem Jahr"
- ],
- "Never": [
- "Nie"
- ],
"Expiration date": [
"Ablaufdatum"
],
"Until when are the new rules active.": [
"Bis wann die neuen Regeln aktiv sind."
],
+ "Choose a future expiration date or Never.": [
+ "Wählen Sie ein zukünftiges Ablaufdatum oder „Nie“."
+ ],
+ "After expiration": [
+ "Nach dem Ablauf"
+ ],
+ "Return to exchange defaults": [
+ "Zu den Börsenstandards zurückkehren"
+ ],
+ "Trigger a successor measure": [
+ "Eine Nachfolgemaßnahme auslösen"
+ ],
"Measure taken automatically upon expiration of the current decision.": [
"Maßnahme, die automatisch bei Ablauf der aktuellen Entscheidung ergriffen wird."
],
- "Failed to load account information.": [
- ""
+ "This successor measure is no longer available.": [
+ "Diese Nachfolgemaßnahme ist nicht mehr verfügbar."
],
- "Failed to load decision history.": [
- ""
+ "Case summary": [
+ "Fallübersicht"
+ ],
+ "Current review state and the latest account activity.": [
+ "Aktueller Prüfstatus und letzte Kontoaktivität."
+ ],
+ "Review status": [
+ "Prüfstatus"
+ ],
+ "Loading…": [
+ "Wird geladen…"
+ ],
+ "Manual review required — waiting for an AML decision.": [
+ "Manuelle Prüfung erforderlich — wartet auf eine AML-Entscheidung."
+ ],
+ "No manual review": [
+ "Keine manuelle Prüfung"
+ ],
+ "Effective decision": [
+ "Wirksame Entscheidung"
+ ],
+ "Requirements": [
+ "Anforderungen"
+ ],
+ "Latest collected information": [
+ "Neueste erfasste Informationen"
+ ],
+ "Effective policy": [
+ "Wirksame Richtlinie"
+ ],
+ "The AML decision and operation rules currently applied to this account.": [
+ "Die derzeit für dieses Konto geltende AML-Entscheidung und die Vorgangsregeln."
+ ],
+ "Effective policy could not be loaded": [
+ "Die geltende Richtlinie konnte nicht geladen werden"
+ ],
+ "Exchange defaults apply": [
+ "Exchange-Standardregeln gelten"
+ ],
+ "No AML officer decision is active for this account.": [
+ "Für dieses Konto ist keine Entscheidung eines AML-Sachbearbeiters aktiv."
+ ],
+ "Account type unavailable": [
+ "Kontotyp nicht verfügbar"
+ ],
+ "Open this case from the account directory or payto search to see the applicable default rules.": [
+ "Öffnen Sie diesen Fall über das Kontoverzeichnis oder die Payto-Suche, um die geltenden Standardregeln anzuzeigen."
+ ],
+ "Default rules could not be loaded": [
+ "Standardregeln konnten nicht geladen werden"
+ ],
+ "Default rules": [
+ "Standardregeln"
+ ],
+ "Account assessment": [
+ "Kontobewertung"
+ ],
+ "Properties recorded by AML officers for this account.": [
+ "Von AML-Sachbearbeitern für dieses Konto erfasste Eigenschaften."
+ ],
+ "Account assessment could not be loaded": [
+ "Die Kontobewertung konnte nicht geladen werden"
+ ],
+ "Collected information": [
+ "Erfasste Informationen"
+ ],
+ "KYC information filed by the customer or an AML officer.": [
+ "Vom Kunden oder einem AML-Sachbearbeiter eingereichte KYC-Informationen."
+ ],
+ "Collected information could not be loaded": [
+ "Erfasste Informationen konnten nicht geladen werden"
+ ],
+ "No collected information": [
+ "Keine erfassten Informationen"
+ ],
+ "No KYC information has been collected for this account.": [
+ "Für dieses Konto wurden keine KYC-Informationen erfasst."
+ ],
+ "Active requirements": [
+ "Aktive Anforderungen"
+ ],
+ "Measures the customer must complete under the current policy.": [
+ "Maßnahmen, die der Kunde gemäß der aktuellen Richtlinie abschließen muss."
+ ],
+ "Active requirements could not be loaded": [
+ "Aktive Anforderungen konnten nicht geladen werden"
],
- "Failed to load current legitimizations.": [
- ""
+ "No active requirements": [
+ "Keine aktiven Anforderungen"
],
- "New decision": [
- "Neue Entscheidung"
+ "The customer has no active legitimization measures to complete.": [
+ "Der Kunde muss keine aktiven Legitimierungsmaßnahmen abschließen."
],
- "Show transfers": [
- "Überweisungen anzeigen"
+ "Officer decision": [
+ "Entscheidung des Sachbearbeiters"
],
- "Failed to download report.": [
- ""
+ "Does not expire": [
+ "Läuft nicht ab"
],
- "Session not found. Contact the administrator.": [
- ""
+ "Waiting": [
+ "Ausstehend"
],
- "The session is disabled. Contact the administrator.": [
- ""
+ "More on later pages": [
+ "Weitere auf nachfolgenden Seiten"
],
- "The server doesn't support PDF download. Contact the administrator.": [
- ""
+ "Try loading this section again.": [
+ "Versuchen Sie, diesen Abschnitt erneut zu laden."
],
- "Case history for selected account": [
- "Fallverlauf für ausgewähltes Konto"
+ "Retry": [
+ "Erneut versuchen"
],
- "ID:": [
- "ID:"
+ "No account properties": [
+ "Keine Kontoeigenschaften"
],
- "Payto:": [
- "Payto:"
+ "No assessment properties have been recorded for this account.": [
+ "Für dieses Konto wurden keine Bewertungseigenschaften erfasst."
],
- "Export as PDF": [
- "Als PDF exportieren"
+ "Yes": [
+ "Ja"
],
- "Export completed": [
- "Export abgeschlossen"
+ "No": [
+ "Nein"
],
- "Click here to save the file in your computer.": [
- "Klicken Sie hier, um die Datei auf Ihrem Computer zu speichern."
+ "Unconfigured form": [
+ "Nicht konfiguriertes Formular"
],
- "Under investigation": [
- "In Untersuchung"
+ "Form not identified": [
+ "Formular nicht identifiziert"
],
- "This account requires a manual review and is waiting for a decision to be made.": [
- "Dieses Konto erfordert eine manuelle Überprüfung und wartet auf eine Entscheidung."
+ "Filed by an AML officer": [
+ "Von einem AML-Sachbearbeiter eingereicht"
],
- "Collected information": [
- "Erfasste Informationen"
+ "Provided by the customer": [
+ "Vom Kunden bereitgestellt"
],
- "Every attribute collection event (via form upload or KYC provider).": [
- "Jedes Ereignis der Attributerfassung (über Formular-Upload oder KYC-Anbieter)."
+ "Attribute data is unavailable.": [
+ "Attributdaten sind nicht verfügbar."
],
- "No collected attributes for this account.": [
- "Keine erfassten Attribute für dieses Konto."
+ "View details": [
+ "Details anzeigen"
],
- "Current account properties": [
- "Aktuelle Kontoeigenschaften"
+ "Review superseded AML decisions for this account, from newest to oldest.": [
+ "Abgelöste AML-Entscheidungen für dieses Konto von der neuesten bis zur ältesten prüfen."
],
- "No active decision found": [
- "Keine aktive Entscheidung gefunden"
+ "Loading decision history…": [
+ "Entscheidungsverlauf wird geladen…"
],
- "There is no decision for this account yet. The account is limited by the default rules.": [
- "Für dieses Konto liegt noch keine Entscheidung vor. Das Konto unterliegt den Standardregeln."
+ "Decision history could not be loaded": [
+ "Entscheidungsverlauf konnte nicht geladen werden"
],
- "Previous AML decisions": [
- "Frühere AML-Entscheidungen"
+ "Try loading the decision history again.": [
+ "Versuchen Sie erneut, den Entscheidungsverlauf zu laden."
],
- "No AML history found": [
- "Kein AML-Verlauf gefunden"
+ "No previous decisions": [
+ "Keine früheren Entscheidungen"
],
- "Current active measures": [
- "Aktuell aktive Maßnahmen"
+ "No superseded AML decisions have been recorded for this account.": [
+ "Für dieses Konto wurden keine abgelösten AML-Entscheidungen erfasst."
],
- "Now": [
- "Jetzt"
+ "Previous decisions": [
+ "Frühere Entscheidungen"
],
- "Lock session": [
- ""
+ "The export could not be prepared. Try again.": [
+ "Der Export konnte nicht erstellt werden. Versuchen Sie es erneut."
],
"Failed to load accounts": [
- ""
+ "Konten konnten nicht geladen werden"
],
- "High risk accounts. Only with custom rules.": [
- "Hochrisikokonten. Nur mit benutzerdefinierten Regeln."
+ "Accounts": [
+ "Konten"
],
- "Account with custom rules.": [
- "Konto mit benutzerdefinierten Regeln."
+ "Review accounts known to the exchange for AML and KYC handling.": [
+ "Prüfen Sie die dem Exchange bekannten Konten zur AML- und KYC-Bearbeitung."
],
- "High risk accounts": [
- "Hochrisikokonten"
+ "Export filtered accounts": [
+ "Gefilterte Konten exportieren"
],
- "All known accounts.": [
- "Alle bekannten Konten."
+ "Download CSV": [
+ "CSV herunterladen"
],
- "High risk accounts under investigation. Only with custom rules.": [
- "Hochrisikokonten in Untersuchung. Nur mit benutzerdefinierten Regeln."
+ "Download Excel": [
+ "Excel-Datei herunterladen"
],
- "Accounts under investigation. Only with custom rules.": [
- "Konten in Untersuchung. Nur mit benutzerdefinierten Regeln."
+ "Preparing export…": [
+ "Export wird vorbereitet…"
],
- "High risk accounts under investigation.": [
- "Hochrisikokonten in Untersuchung."
+ "Export failed": [
+ "Export fehlgeschlagen"
],
- "Accounts under investigation.": [
- "Konten in Untersuchung."
+ "Account filters": [
+ "Kontofilter"
],
- "High risk accounts without investigation. Only with custom rules.": [
- "Hochrisikokonten ohne Untersuchung. Nur mit benutzerdefinierten Regeln."
+ "Investigation": [
+ "Untersuchung"
],
- "Accounts without investigation. Only with custom rules.": [
- "Konten ohne Untersuchung. Nur mit benutzerdefinierten Regeln."
+ "All accounts": [
+ "Alle Konten"
],
- "High risk accounts without investigation.": [
- "Hochrisikokonten ohne Untersuchung."
+ "Not under investigation": [
+ "Nicht in Untersuchung"
],
- "Accounts without investigation.": [
- "Konten ohne Untersuchung."
+ "Risk": [
+ "Risiko"
],
- "Failed to download": [
- ""
+ "All risk levels": [
+ "Alle Risikostufen"
],
- "The format requested is not acceptable from the service provider.": [
- ""
+ "Not high risk": [
+ "Kein hohes Risiko"
],
- "Authorization denied for this session.": [
- ""
+ "File status": [
+ "Aktenstatus"
],
- "The session is disabled. Contact the administrator": [
- ""
+ "All file statuses": [
+ "Alle Aktenstatus"
],
- "Accounts": [
- "Konten"
+ "Not open": [
+ "Nicht offen"
],
- "Export as file": [
- "Als Datei exportieren"
+ "Clear filters": [
+ "Filter zurücksetzen"
],
- "No results": [
- "Keine Ergebnisse"
+ "Showing %1$s accounts · newest first": [
+ "%1$s Konten · neueste zuerst"
],
- "#": [
- "#"
+ "AML and KYC accounts": [
+ "AML- und KYC-Konten"
],
- "Account Identification": [
- "Kontokennung"
+ "Account lifecycle": [
+ "Lebenszyklus der Akte"
],
- "Open time": [
- "Eröffnungszeit"
+ "Latest note": [
+ "Neueste Notiz"
],
- "Status": [
- "Status"
+ "Copied": [
+ "Kopiert"
],
- "From %1$s %2$s To %3$s": [
- "Von %1$s %2$s Bis %3$s"
+ "Copy": [
+ "Kopieren"
],
- "Since %1$s": [
- "Seit %1$s"
+ "No matching accounts": [
+ "Keine passenden Konten"
],
- "Not opened": [
- "Nicht eröffnet"
+ "No accounts yet": [
+ "Noch keine Konten"
],
- "High risk": [
- "Hohes Risiko"
+ "No accounts match the selected filters.": [
+ "Keine Konten entsprechen den ausgewählten Filtern."
],
- "With custom rules": [
- "Mit benutzerdefinierten Regeln"
+ "The exchange has not recorded any AML or KYC accounts yet.": [
+ "Der Exchange hat noch keine AML- oder KYC-Konten erfasst."
],
- "Invalid account": [
- "Ungültiges Konto"
+ "This officer session is not authorized to list accounts.": [
+ "Diese Sachbearbeitersitzung ist nicht berechtigt, Konten aufzulisten."
],
- "Search by ID": [
- "Nach ID suchen"
+ "The exchange does not recognize this officer session.": [
+ "Der Exchange erkennt diese Sachbearbeitersitzung nicht."
],
- "Under investigation: ": [
- "In Untersuchung: "
+ "This officer session is currently disabled.": [
+ "Diese Sachbearbeitersitzung ist derzeit deaktiviert."
],
- "High risk:": [
- "Hochrisiko:"
+ "There are no matching accounts to export.": [
+ "Es gibt keine passenden Konten für den Export."
],
- "Custom rules:": [
- "Benutzerdefinierte Regeln:"
+ "The exchange does not support the selected export format.": [
+ "Der Exchange unterstützt das ausgewählte Exportformat nicht."
+ ],
+ "This officer session is not authorized to export accounts.": [
+ "Diese Sachbearbeitersitzung ist nicht berechtigt, Konten zu exportieren."
],
"Dashboard": [
"Dashboard"
],
- "Failed to load TOPS statistics.": [
+ "Review cases requiring attention, investigate accounts, and monitor AML reporting indicators.": [
+ ""
+ ],
+ "Review case queue": [
+ ""
+ ],
+ "Find credit, debit, and KYC authorization activity.": [
""
],
"Statistics": [
"Statistiken"
],
+ "No reporting profile for this dialect": [
+ ""
+ ],
+ "The testing dialect does not define dashboard statistics. Select TOPS in development settings to inspect the TOPS reporting profile.": [
+ ""
+ ],
+ "Failed to load TOPS statistics.": [
+ ""
+ ],
+ "The available values are shown below. Missing values are not zero.": [
+ ""
+ ],
"Accounts open": [
"Eröffnete Konten"
],
@@ -5747,95 +9254,86 @@ strings['de'] = {
"Increased by": [
"Erhöht um"
],
- "Events": [
- "Ereignisse"
+ "The built-in event selection differs from the events derived from the proposed account state.": [
+ ""
],
- "The events will be triggered only after the decision has been confirmed.": [
- "Die Ereignisse werden erst ausgelöst, nachdem die Entscheidung bestätigt wurde."
+ "Built-in events are derived from changes to the proposed account properties. They are stored for reporting and statistics; they do not notify the customer.": [
+ ""
],
"Calculated": [
"Berechnet"
],
- "Events based on properties and new attributes that should be triggered": [
- "Ereignisse, die auf Grundlage von Eigenschaften und neuen Attributen ausgelöst werden sollen"
- ],
- "Others": [
- "Sonstige"
- ],
- "Events that can be triggered manually": [
- "Ereignisse, die manuell ausgelöst werden können"
- ],
- "Custom list": [
- "Benutzerdefinierte Liste"
+ "Events derived from proposed property changes and submitted information.": [
+ ""
],
- "Events without built-in support.": [
- "Ereignisse ohne integrierte Unterstützung."
+ "Other built-in events": [
+ ""
],
- "Complete the form": [
- "Formular ausfüllen"
+ "Operator-defined event names that are not part of the selected dialect.": [
+ ""
],
- "These measures will ask the customer for information.": [
- "Diese Maßnahmen fordern den Kunden zur Angabe von Informationen auf."
+ "The completed form is attached to this AML decision as reviewed account information. It does not create a customer-facing measure.": [
+ ""
],
- "change form": [
- "Formular ändern"
+ "Expiration": [
+ "Ablauf"
],
"Expiration date of the information filled in this form.": [
"Ablaufdatum der in diesem Formular eingegebenen Informationen."
],
- "Include new information": [
- "Neue Informationen einbeziehen"
- ],
- "Select a form to submit new information about the customer or continue to the next step": [
- "Wählen Sie ein Formular aus, um neue Informationen über den Kunden zu übermitteln, oder fahren Sie mit dem nächsten Schritt fort"
+ "Only change this operator-defined JSON when the form documentation requires additional context.": [
+ ""
],
- "Form:": [
- "Formular:"
+ "Invalid expiration": [
+ "Ungültiges Ablaufdatum"
],
- "Justification": [
- "Begründung"
+ "Attributes require an expiration date in the future or set to Never.": [
+ "Attribute benötigen ein in der Zukunft liegendes Ablaufdatum oder müssen auf „Nie“ gesetzt werden."
],
- "Keep investigation?": [
- "Untersuchung beibehalten?"
+ "Include new information": [
+ "Neue Informationen einbeziehen"
],
- "Account holder": [
- "Kontoinhaber"
+ "This step is optional. Select a form to attach newly reviewed AML/KYC information, or continue without one.": [
+ ""
],
- "Full name of the account holder": [
- "Vollständiger Name des Kontoinhabers"
+ "AML/KYC form": [
+ ""
],
- "loading...": [
- "wird geladen..."
+ "Search AML/KYC forms": [
+ "AML/KYC-Formulare durchsuchen"
],
- "Update": [
- "Aktualisieren"
+ "Full name used in the payto URI when creating this previously unknown account.": [
+ ""
],
- "Remove": [
- "Entfernen"
+ "Record the facts and reasoning needed to understand this decision in a later audit or review.": [
+ ""
],
- "Configure verification type: %1$s": [
- "Verifizierungstyp konfigurieren: %1$s"
+ "Combine a customer check with an AML program, or use SKIP to run a program immediately. Context values must satisfy the selected check and program requirements.": [
+ ""
],
- "Show complete form": [
- "Vollständiges Formular anzeigen"
+ "Add custom measure": [
+ "Benutzerdefinierte Maßnahme hinzufügen"
],
- "Configure measure": [
- "Maßnahme konfigurieren"
+ "Save changes": [
+ ""
],
- "Show as verification": [
- "Als Verifizierung anzeigen"
+ "Use advanced measure editor": [
+ ""
],
"There is already a measure with that name": [
"Es gibt bereits eine Maßnahme mit diesem Namen"
],
- "Only required when no check is specified": [
- "Nur erforderlich, wenn keine Prüfung angegeben ist"
+ "Runs immediately for SKIP measures, or after a successful check. It may be omitted for a check that only presents or collects information.": [
+ ""
],
"Missing check or program": [
"Prüfung oder Programm fehlt"
],
- "Without a check the program will run automatically": [
- "Ohne Prüfung wird das Programm automatisch ausgeführt"
+ "The customer-facing check to perform before the program. Leave empty to use SKIP and run the program immediately.": [
+ ""
+ ],
+ "Configuration values required by the selected check or program. Property names and value types must match the exchange configuration.": [
+ ""
],
"Field name": [
"Feldname"
@@ -5855,12 +9353,12 @@ strings['de'] = {
"json": [
"json"
],
- "Value": [
- "Wert"
- ],
"There are unsatisfied inputs: %1$s": [
"Es gibt nicht erfüllte Eingaben: %1$s"
],
+ "Check \"%1$s\" is not available": [
+ ""
+ ],
"There are missing inputs: %1$s": [
"Es fehlen Eingaben: %1$s"
],
@@ -5870,18 +9368,12 @@ strings['de'] = {
"Can't be empty": [
"Darf nicht leer sein"
],
- "It should be a number": [
- "Es sollte eine Zahl sein"
- ],
"Not a number": [
"Keine Zahl"
],
"It should be finite": [
"Es sollte endlich sein"
],
- "It should be a safe integer": [
- "Es sollte eine sichere Ganzzahl sein"
- ],
"It should be either \"true\" or \"false\"": [
"Es sollte entweder \"true\" oder \"false\" sein"
],
@@ -5894,15 +9386,15 @@ strings['de'] = {
"Inputs": [
"Eingaben"
],
- "Output": [
- "Ausgabe"
- ],
- "Requires": [
- "Erfordert"
- ],
"Fallback": [
"Fallback"
],
+ "Selected pipeline": [
+ ""
+ ],
+ "Review how the exchange will execute this measure.": [
+ ""
+ ],
"Name of the verification measure": [
"Name der Verifizierungsmaßnahme"
],
@@ -5912,236 +9404,470 @@ strings['de'] = {
"Prevent the customer from changing the address": [
"Verhindert, dass der Kunde die Adresse ändert"
],
- "Configure verification measure: \"%1$s\"": [
- "Verifizierungsmaßnahme konfigurieren: \"%1$s\""
+ "Customer actions after submission": [
+ ""
],
- "Add custom measure": [
- "Benutzerdefinierte Maßnahme hinzufügen"
+ "Immediate measures start as soon as this decision is accepted. A measure may show information, collect customer data, or run an AML program. Leave the selection empty when no immediate customer action is required.": [
+ ""
+ ],
+ "Too many SKIP measures": [
+ "Zu viele SKIP-Maßnahmen"
+ ],
+ "At most one immediate measure may use the SKIP check.": [
+ "Höchstens eine sofortige Maßnahme darf die SKIP-Prüfung verwenden."
+ ],
+ "Custom measures": [
+ "Benutzerdefinierte Maßnahmen"
+ ],
+ "Measures defined only for this proposed decision.": [
+ ""
+ ],
+ "Edit": [
+ ""
+ ],
+ "Reusable templates configured by the exchange operator": [
+ ""
+ ],
+ "Use as template": [
+ ""
+ ],
+ "Selected measures begin immediately after the decision is accepted by the exchange.": [
+ ""
+ ],
+ "Session not found. Contact the administrator.": [
+ ""
+ ],
+ "The exchange rejected the decision because the officer session is disabled or the account has a newer decision. Reload the account before trying again.": [
+ ""
+ ],
+ "This decision records that an MROS report was filed. Confirm that the report has actually been submitted before continuing.": [
+ ""
+ ],
+ "Confirm decision": [
+ "Entscheidung bestätigen"
+ ],
+ "Unknown measure": [
+ "Unbekannte Maßnahme"
+ ],
+ "A rule or immediate action references a measure that is not available. Review the rules and measures before submitting.": [
+ "Eine Regel oder sofortige Aktion verweist auf eine nicht verfügbare Maßnahme. Prüfen Sie die Regeln und Maßnahmen vor dem Absenden."
+ ],
+ "A custom measure references an unavailable check or program, lacks required context, or cannot provide the selected program inputs. Review the immediate measures before submitting.": [
+ ""
+ ],
+ "Missing deadline": [
+ "Frist fehlt"
+ ],
+ "Set when the proposed rules expire and what should happen afterward.": [
+ ""
+ ],
+ "Invalid rule expiration": [
+ "Ungültiger Regelablauf"
+ ],
+ "Rule expiration must be in the future or set to Never.": [
+ "Der Regelablauf muss in der Zukunft liegen oder auf „Nie“ gesetzt sein."
+ ],
+ "Missing rules": [
+ "Regeln fehlen"
+ ],
+ "A decision must contain the complete rule set that will apply to the account.": [
+ ""
+ ],
+ "Review the proposed rules. Hard blocks must be explicit, and Balance and Refund rules must use an instant timeframe.": [
+ "Prüfen Sie die vorgeschlagenen Regeln. Harte Sperren müssen ausdrücklich angegeben werden, und Regeln für Saldo und Rückerstattung müssen einen sofortigen Zeitraum verwenden."
+ ],
+ "Immediate measures not reviewed": [
+ ""
+ ],
+ "No measure will start when this decision is submitted.": [
+ ""
+ ],
+ "Review the account properties before submitting the decision.": [
+ ""
+ ],
+ "Reporting events not reviewed": [
+ ""
+ ],
+ "Review which statistical events will be recorded with the decision.": [
+ ""
+ ],
+ "Case disposition incomplete": [
+ ""
+ ],
+ "You must complete the justification section.": [
+ "Sie müssen den Abschnitt Begründung ausfüllen."
+ ],
+ "Invalid attributes": [
+ "Ungültige Attribute"
+ ],
+ "Correct the selected form or continue without attaching new customer information.": [
+ ""
+ ],
+ "Justification": [
+ "Begründung"
+ ],
+ "Events": [
+ "Ereignisse"
+ ],
+ "All entries made in this decision wizard will be lost. No change will be submitted to the exchange.": [
+ ""
+ ],
+ "Payto URI": [
+ "Payto-URI"
+ ],
+ "Decision steps": [
+ ""
+ ],
+ "Account properties": [
+ "Kontoeigenschaften"
+ ],
+ "Review the account state derived from the available information.": [
+ ""
+ ],
+ "Review the statistical events recorded with this decision.": [
+ ""
+ ],
+ "Set operation thresholds, escalation measures, and expiration behavior.": [
+ ""
+ ],
+ "Case disposition": [
+ ""
+ ],
+ "Check the complete decision before signing and submitting it.": [
+ ""
+ ],
+ "Enter a valid HTTP or HTTPS URL.": [
+ ""
+ ],
+ "Development settings": [
+ "Entwicklungseinstellungen"
+ ],
+ "These browser-local settings are intended for development and troubleshooting.": [
+ ""
+ ],
+ "Changing the exchange reloads the application. The override is stored only in this browser.": [
+ ""
+ ],
+ "Exchange base URL": [
+ "Exchange-Basis-URL"
+ ],
+ "Leave empty to use the configured URL: %1$s": [
+ ""
+ ],
+ "Leave empty to derive the exchange URL from this page.": [
+ ""
+ ],
+ "Currently connected to": [
+ ""
+ ],
+ "Apply and reload": [
+ ""
+ ],
+ "Use configured URL": [
+ ""
+ ],
+ "Preferences": [
+ "Einstellungen"
+ ],
+ "AML SPA dialect": [
+ ""
+ ],
+ "Testing": [
+ ""
+ ],
+ "Override how this web interface presents dialect-specific AML rules and properties. The override is stored only in this browser.": [
+ ""
+ ],
+ "Fallback dialect for development and testing.": [
+ ""
+ ],
+ "TOPS": [
+ ""
+ ],
+ "Taler Operations deployment for Swiss AML processes.": [
+ ""
+ ],
+ "File note": [
+ "Aktennotiz"
+ ],
+ "Text": [
+ ""
+ ],
+ "Customer label": [
+ "Kundenbezeichnung"
+ ],
+ "Account open": [
+ "Konto eröffnet"
+ ],
+ "Domestic PEP": [
+ "Inländische PEP"
+ ],
+ "Whether the customer is a domestic politically exposed person.": [
+ ""
+ ],
+ "Foreign PEP": [
+ "Ausländische PEP"
+ ],
+ "Whether the customer is a foreign politically exposed person.": [
+ ""
+ ],
+ "International-organization PEP": [
+ "PEP einer internationalen Organisation"
+ ],
+ "Whether the customer is a politically exposed person associated with an international organization.": [
+ ""
+ ],
+ "High-risk customer": [
+ "Hochrisikokunde"
+ ],
+ "High-risk country": [
+ "Hochrisikoland"
+ ],
+ "Whether the customer is associated with a high-risk country.": [
+ ""
+ ],
+ "Account idle": [
+ "Konto inaktiv"
+ ],
+ "Whether the account has been marked as idle.": [
+ ""
+ ],
+ "Score from 0 (no match) to 1,000,000,000 (best match).": [
+ ""
+ ],
+ "Score from 0 (no supporting data) to 1,000,000,000 (highest confidence).": [
+ ""
+ ],
+ "Whether this account's sanction-list hit is treated as a false positive.": [
+ ""
],
- "Custom measures": [
- "Benutzerdefinierte Maßnahmen"
+ "Recorded when an account changes to open.": [
+ ""
],
- "Server measures": [
- "Server-Maßnahmen"
+ "Recorded when an account changes from open to closed.": [
+ ""
],
- "New measures": [
- "Neue Maßnahmen"
+ "Recorded when an open account becomes classified as a high-risk customer.": [
+ ""
],
- "Measures that are available/executed directly after the decision is confirmed.": [
- "Maßnahmen, die direkt nach Bestätigung der Entscheidung verfügbar sind/ausgeführt werden."
+ "Recorded when the high-risk customer classification is removed.": [
+ ""
],
- "Reset to default": [
- "Auf Standard zurücksetzen"
+ "Recorded when an open account becomes associated with a high-risk country.": [
+ ""
],
- "Properties": [
- "Eigenschaften"
+ "High-risk country classification removed": [
+ ""
],
- "Custom properties": [
- "Benutzerdefinierte Eigenschaften"
+ "Recorded when the high-risk country classification is removed.": [
+ ""
],
- "Add more properties that are not listed above.": [
- "Weitere Eigenschaften hinzufügen, die oben nicht aufgeführt sind."
+ "PEP classification added": [
+ ""
],
- "New properties": [
- "Neue Eigenschaften"
+ "Recorded when an open account becomes associated with any PEP category.": [
+ ""
],
- "Current note on the GwG file": [
- "Aktuelle Notiz zur GwG-Akte"
+ "Recorded when the account is no longer associated with any PEP category.": [
+ ""
],
- "Customer name or internal alias.": [
- "Kundenname oder interner Alias."
+ "Foreign PEP classification added": [
+ ""
],
- "Is the account active for deposit and payments?": [
- "Ist das Konto für Einzahlungen und Zahlungen aktiv?"
+ "Recorded when an open account becomes associated with a foreign PEP.": [
+ ""
],
- "Is the account idle?": [
- "Ist das Konto inaktiv?"
+ "Foreign PEP classification removed": [
+ ""
],
- "No operation for a period of time": [
- "Keine Vorgänge über einen bestimmten Zeitraum"
+ "Recorded when the foreign PEP classification is removed.": [
+ ""
],
- "Does account belong to a domestic PEP?": [
- "Gehört das Konto zu einer inländischen PEP?"
+ "Domestic PEP classification added": [
+ ""
],
- "Does account belong to a foreign PEP?": [
- "Gehört das Konto zu einer ausländischen PEP?"
+ "Recorded when an open account becomes associated with a domestic PEP.": [
+ ""
],
- "Does account belong to an international-organization PEP?": [
- "Gehört das Konto zu einer PEP einer internationalen Organisation?"
+ "Domestic PEP classification removed": [
+ ""
],
- "Does account belong to a high risk customer?": [
- "Gehört das Konto zu einem Hochrisikokunden?"
+ "Recorded when the domestic PEP classification is removed.": [
+ ""
],
- "Does account belong to a person from a high risk country?": [
- "Gehört das Konto zu einer Person aus einem Hochrisikoland?"
+ "Recorded when the international-organization PEP classification is removed.": [
+ ""
],
- "The MROS reporting state for the account.": [
- "Der MROS-Meldestatus für das Konto."
+ "Simple suspicion reported to MROS": [
+ ""
],
- "None": [
- "Keine"
+ "Recorded when a report is filed under Article 305ter paragraph 2 StGB.": [
+ ""
],
- "Pending investigation": [
- "Untersuchung ausstehend"
+ "Recorded when a report is filed under Article 9 GwG.": [
+ ""
],
- "Investigated without suspicion": [
- "Untersucht, kein Verdacht"
+ "Recorded when a pending special clarification is concluded.": [
+ ""
],
- "Reported simple suspicion": [
- "Einfacher Verdacht gemeldet"
+ "Recorded when a previously concluded investigation returns to a non-concluded state.": [
+ ""
],
- "Reported substantiated suspicion": [
- "Begründeter Verdacht gemeldet"
+ "Browser override": [
+ ""
],
- "Informal reason why the AML investigation was triggered": [
- "Informeller Grund für die Auslösung der AML-Untersuchung"
+ "Exchange identity, the active AML dialect, and the checks and programs available to AML decisions.": [
+ ""
],
- "Identifies the sanction list entry that the account matched against": [
- "Identifiziert den Sanktionslisteneintrag, mit dem das Konto übereinstimmte"
+ "Public information reported by this exchange.": [
+ ""
],
- "Best match, does not mean it was a good match.": [
- "Beste Übereinstimmung, bedeutet nicht, dass es eine gute Übereinstimmung war."
+ "Base URL": [
+ ""
],
- "Score for how good the sanction list match was": [
- "Bewertung, wie gut die Übereinstimmung mit der Sanktionsliste war"
+ "Protocol": [
+ ""
],
- "Score for how much supporting data we had for the sanction list match": [
- "Bewertung, wie viele Belegdaten für die Übereinstimmung mit der Sanktionsliste vorlagen"
+ "Protocol version": [
+ ""
],
- "Suppress flagging this account when it creates a hit on a sanctions list, this is a false-positive": [
- "Markierung dieses Kontos unterdrücken, wenn es einen Treffer auf einer Sanktionsliste erzeugt; dies ist ein Fehlalarm"
+ "Currency": [
+ ""
],
- "Confirmation required": [
- "Bestätigung erforderlich"
+ "AML dialect": [
+ ""
],
- "I want to check first!": [
- "Ich möchte zuerst prüfen!"
+ "Canonical properties defined by the effective dialect.": [
+ ""
],
- "Confirm decision": [
- "Entscheidung bestätigen"
+ "This dialect does not define derived events.": [
+ ""
],
- "Missing deadline": [
- "Frist fehlt"
+ "Checks, programs, root measures, and default rules reported by the exchange.": [
+ ""
],
- "Deadline should specify when this rules ends and what is the next measures to apply after expiration.": [
- "Die Frist sollte angeben, wann diese Regel endet und welche Maßnahmen nach Ablauf anzuwenden sind."
+ "%1$s entries": [
+ ""
],
- "Missing rules": [
- "Regeln fehlen"
+ "No root measures are configured.": [
+ ""
],
- "Can't make a decision without rules.": [
- "Ohne Regeln kann keine Entscheidung getroffen werden."
+ "No KYC checks are configured.": [
+ ""
],
- "Missing active measure": [
- "Aktive Maßnahme fehlt"
+ "No AML programs are configured.": [
+ ""
],
- "You should specify in the measure section.": [
- "Sie sollten dies im Abschnitt Maßnahmen angeben."
+ "No default AML rules are configured.": [
+ ""
],
- "No customer action required.": [
- "Keine Kundenaktion erforderlich."
+ "Built-in check that proceeds without collecting customer data.": [
+ ""
],
- "No active measure has been selected.": [
- "Es wurde keine aktive Maßnahme ausgewählt."
+ "Voluntary": [
+ ""
],
- "Missing properties": [
- "Eigenschaften fehlen"
+ "Session and access": [
+ "Sitzung und Zugriff"
],
- "You should specify in the properties section.": [
- "Sie sollten dies im Abschnitt Eigenschaften angeben."
+ "Review this officer's exchange access and manage the unlocked key in this browser.": [
+ "Überprüfen Sie den Exchange-Zugriff dieses Sachbearbeiters und verwalten Sie den entsperrten Schlüssel in diesem Browser."
],
- "Missing events": [
- "Ereignisse fehlen"
+ "Officer access": [
+ "Sachbearbeiterzugriff"
],
- "You should specify in the events section.": [
- "Sie sollten dies im Abschnitt Ereignisse angeben."
+ "Officer name": [
+ "Name des Sachbearbeiters"
],
- "Missing justification": [
- "Begründung fehlt"
+ "Permissions": [
+ "Berechtigungen"
],
- "You must complete the justification section.": [
- "Sie müssen den Abschnitt Begründung ausfüllen."
+ "Read-only": [
+ "Nur lesen"
],
- "Invalid attributes": [
- "Ungültige Attribute"
+ "Read and write": [
+ "Lesen und Schreiben"
],
- "You should check form errors or submit a decision without attributes.": [
- "Sie sollten Formularfehler prüfen oder eine Entscheidung ohne Attribute übermitteln."
+ "Session security": [
+ "Sitzungssicherheit"
],
- "Clear": [
- "Leeren"
+ "Lock the session when you leave this device unattended.": [
+ "Sperren Sie die Sitzung, wenn Sie dieses Gerät unbeaufsichtigt lassen."
],
- "Send decision": [
- "Entscheidung senden"
+ "Lock now": [
+ "Jetzt sperren"
],
- "Prev": [
- "Zurück"
+ "Unlocked": [
+ "Entsperrt"
],
- "Next": [
- "Weiter"
+ "Locks automatically": [
+ "Automatische Sperre"
],
- "Attributes": [
- "Attribute"
+ "Exact time": [
+ "Genauer Zeitpunkt"
],
- "Add more information about the customer": [
- "Weitere Informationen über den Kunden hinzufügen"
+ "Officer public key": [
+ "Öffentlicher Schlüssel des Sachbearbeiters"
],
- "Rules": [
- "Regeln"
+ "Copy public key": [
+ "Öffentlichen Schlüssel kopieren"
],
- "Set the limit of the operations": [
- "Das Limit der Vorgänge festlegen"
+ "Remove key from this browser": [
+ "Schlüssel aus diesem Browser entfernen"
],
- "Trigger notifications.": [
- "Benachrichtigungen auslösen."
+ "Removing this key deletes the officer key from this browser. It does not revoke or change the officer's access at the exchange. Ask the exchange operator to revoke access if needed.": [
+ "Durch das Entfernen dieses Schlüssels wird der Sachbearbeiterschlüssel aus diesem Browser gelöscht. Der Zugriff des Sachbearbeiters beim Exchange wird dadurch weder widerrufen noch geändert. Bitten Sie den Exchange-Betreiber bei Bedarf, den Zugriff zu widerrufen."
],
- "Measures": [
- "Maßnahmen"
+ "Remove key": [
+ "Schlüssel entfernen"
],
- "Ask the customer to take action.": [
- "Den Kunden zum Handeln auffordern."
+ "Remove officer key?": [
+ "Sachbearbeiterschlüssel entfernen?"
],
- "Describe the decision.": [
- "Die Entscheidung beschreiben."
+ "This deletes the officer key from this browser. You will need to create and enroll a new key to use the AML WebUI here again.": [
+ "Hierdurch wird der Sachbearbeiterschlüssel aus diesem Browser gelöscht. Sie müssen einen neuen Schlüssel erstellen und registrieren lassen, um die AML-Weboberfläche hier erneut zu verwenden."
],
- "Flag the current account state.": [
- "Den aktuellen Kontostatus markieren."
+ "This does not revoke the officer at the exchange. Ask the exchange operator to revoke its access if the key may be compromised.": [
+ "Der Sachbearbeiter wird dadurch beim Exchange nicht widerrufen. Bitten Sie den Exchange-Betreiber, seinen Zugriff zu widerrufen, wenn der Schlüssel möglicherweise kompromittiert wurde."
],
- "Summary": [
- "Zusammenfassung"
+ "Find account": [
+ "Konto suchen"
],
- "Review and submit.": [
- "Überprüfen und absenden."
+ "Look up an account by its payto information or normalized payto hash.": [
+ "Suchen Sie ein Konto anhand seiner Payto-Informationen oder seines normalisierten Payto-Hashs."
],
- "Decision for account:": [
- "Entscheidung für Konto:"
+ "Find by payto": [
+ "Nach Payto suchen"
],
- "Decision for wallet:": [
- "Entscheidung für Wallet:"
+ "Find by normalized payto hash": [
+ "Nach normalisiertem Payto-Hash suchen"
],
- "Decision for bank account:": [
- "Entscheidung für Bankkonto:"
+ "Enter a valid 52-character normalized payto hash.": [
+ "Geben Sie einen gültigen normalisierten Payto-Hash mit 52 Zeichen ein."
],
- "Search account": [
- "Konto suchen"
+ "Open account": [
+ "Konto öffnen"
],
"Failed to load account decisions.": [
- ""
+ "Kontoentscheidungen konnten nicht geladen werden."
+ ],
+ "Failed to load the account history.": [
+ "Der Kontoverlauf konnte nicht geladen werden."
],
- "Check account details": [
- "Kontodetails überprüfen"
+ "This session signature is invalid, contact administrator or create a new one.": [
+ "Die Signatur dieser Sitzung ist ungültig. Wenden Sie sich an den Administrator oder erstellen Sie eine neue Sitzung."
],
- "Account most recent decisions": [
- "Jüngste Entscheidungen zum Konto"
+ "The designated AML session is not known, contact administrator or create a new one.": [
+ "Die angegebene AML-Sitzung ist nicht bekannt. Wenden Sie sich an den Administrator oder erstellen Sie eine neue Sitzung."
],
- "When": [
- "Wann"
+ "The designated AML session is not enabled, contact administrator or create a new one.": [
+ "Die angegebene AML-Sitzung ist nicht aktiviert. Wenden Sie sich an den Administrator oder erstellen Sie eine neue Sitzung."
],
- "LATEST": [
- "NEUESTE"
+ "This account has an AML decision history. Open its case to review current rules, measures, attributes, and past decisions.": [
+ ""
],
- "ACTIVE": [
- "AKTIV"
+ "Active": [
+ ""
],
"Account not found": [
"Konto nicht gefunden"
@@ -6149,15 +9875,9 @@ strings['de'] = {
"There is no history known for this account yet.": [
"Für dieses Konto ist noch kein Verlauf bekannt."
],
- "You can make a decision for this account anyway.": [
- "Sie können trotzdem eine Entscheidung für dieses Konto treffen."
- ],
"Search": [
"Suchen"
],
- "IBAN": [
- "IBAN"
- ],
"Taler Bank": [
"Taler-Bank"
],
@@ -6195,7 +9915,10 @@ strings['de'] = {
"Die Adresse sollte mehr als 6 Zeichen haben."
],
"Decoding issue.": [
- ""
+ "Dekodierungsfehler."
+ ],
+ "Invalid data": [
+ "Ungültige Daten"
],
"Unsupported country.": [
"Nicht unterstütztes Land."
@@ -6242,6 +9965,9 @@ strings['de'] = {
"Cyclos address is missing": [
"Cyclos-Adresse fehlt"
],
+ "Void address is missing": [
+ "Die Void-Adresse fehlt"
+ ],
"Invalid IBAN: %1$s": [
"Ungültige IBAN: %1$s"
],
@@ -6254,12 +9980,12 @@ strings['de'] = {
"Invalid host": [
"Ungültiger Host"
],
+ "Invalid account": [
+ "Ungültiges Konto"
+ ],
"Invalid address": [
"Ungültige Adresse"
],
- "Payto URI": [
- "Payto-URI"
- ],
"As defined by RFC 8905": [
"Wie in RFC 8905 definiert"
],
@@ -6299,9 +10025,6 @@ strings['de'] = {
"Should be 52 characters": [
"Sollte 52 Zeichen haben"
],
- "Account": [
- "Konto"
- ],
"Bank account identification": [
"Bankkontokennung"
],
@@ -6320,38 +10043,59 @@ strings['de'] = {
"Invalid hostname": [
"Ungültiger Hostname"
],
+ "Failed to load account information.": [
+ "Kontoinformationen konnten nicht geladen werden."
+ ],
"Failed to load the account information.": [
""
],
- "Different form version": [
- "Andere Formularversion"
+ "Collection event not found": [
+ "Erfassungsereignis nicht gefunden"
+ ],
+ "There is no collection event with ID %1$s for this account.": [
+ "Für dieses Konto gibt es kein Erfassungsereignis mit der ID %1$s."
+ ],
+ "Attributes unavailable": [
+ "Attribute nicht verfügbar"
+ ],
+ "The collection event does not contain readable attributes.": [
+ "Das Erfassungsereignis enthält keine lesbaren Attribute."
+ ],
+ "Form identifier missing": [
+ "Formular-ID fehlt"
+ ],
+ "The collected information does not identify the form used to create it.": [
+ "Die erfassten Informationen geben nicht an, mit welchem Formular sie erstellt wurden."
],
- "The collected information don't have the form version used.": [
- "Die erfassten Informationen enthalten die verwendete Formularversion nicht."
+ "Form not available": [
+ "Formular nicht verfügbar"
+ ],
+ "Form %1$s is not configured in this AML Web UI.": [
+ "Das Formular %1$s ist in dieser AML-Weboberfläche nicht konfiguriert."
],
- "The collected information used the form version \"%1$s \" but is not available.": [
- "Die erfassten Informationen verwendeten die Formularversion \"%1$s \", die jedoch nicht verfügbar ist."
+ "Source": [
+ ""
],
- "Case details": [
- "Falldetails"
+ "Different form version": [
+ "Andere Formularversion"
],
- "Next event": [
- "Nächstes Ereignis"
+ "The collected information does not identify the form version used. The latest configured version is shown and field labels may differ from those used at collection time.": [
+ ""
],
- "Previous event": [
- "Vorheriges Ereignis"
+ "JSON view": [
+ ""
],
- "Direction": [
- "Richtung"
+ "Incoming": [
+ ""
],
- "Credit": [
- "Guthaben"
+ "Outgoing": [
+ ""
],
- "Debit": [
- "Soll"
+ "KYC authorization": [
+ ""
],
- "KYC Auth": [
- "KYC-Authentifizierung"
+ "Wallet credits (P2P)": [
+ ""
],
"Minimum amount": [
"Mindestbetrag"
@@ -6359,6 +10103,15 @@ strings['de'] = {
"All amounts below the given threshold will be filtered.": [
"Alle Beträge unterhalb des angegebenen Schwellenwerts werden ausgefiltert."
],
+ "Inspect successful P2P credits received by this wallet. Requests that were not paid are not shown.": [
+ ""
+ ],
+ "Inspect effective bank transfers observed by the exchange. Credit transfers are incoming, debit transfers are outgoing, and bounced or drain transfers are not included.": [
+ ""
+ ],
+ "Inspect effective transfers observed by the exchange. Incoming, outgoing, and KYC authorization entries are bank transfers. Wallet credits are successful P2P transfers into wallets.": [
+ ""
+ ],
"Failed to load the transfer list.": [
""
],
@@ -6368,12 +10121,6 @@ strings['de'] = {
"Please select a transaction type to show transactions.": [
"Bitte wählen Sie einen Transaktionstyp aus, um Transaktionen anzuzeigen."
],
- "Transfers history for account": [
- "Überweisungsverlauf für Konto"
- ],
- "Transfers history": [
- "Überweisungsverlauf"
- ],
"No transfers yet.": [
"Noch keine Überweisungen."
],
@@ -6383,12 +10130,18 @@ strings['de'] = {
"There are no transfers reported to the exchange with the current threshold.": [
"Es wurden dem Exchange bei dem aktuellen Schwellenwert keine Überweisungen gemeldet."
],
- "Date": [
- "Datum"
+ "Unknown date": [
+ ""
+ ],
+ "Time": [
+ ""
],
"Amount": [
"Betrag"
],
+ "Unknown time": [
+ ""
+ ],
"sent": [
"gesendet"
],
@@ -6401,96 +10154,30 @@ strings['de'] = {
"from": [
"von"
],
- "Welcome to the exchange configuration": [
- "Willkommen bei der Exchange-Konfiguration"
+ "This exchange is not compatible with the AML WebUI.": [
+ "Dieser Exchange ist nicht mit der AML-WebUI kompatibel."
],
- "Transfers": [
- "Überweisungen"
+ "Officer identity and permissions require exchange protocol v40 or newer.": [
+ "Identität und Berechtigungen des Sachbearbeiters erfordern Exchange-Protokoll v40 oder neuer."
],
- "Profile": [
- "Profil"
+ "Verifying that this public key is enrolled by the exchange.": [
+ "Es wird geprüft, ob dieser öffentliche Schlüssel beim Exchange registriert ist."
],
- "Failed to load available measures.": [
- "Die verfügbaren Maßnahmen konnten nicht geladen werden."
+ "Read-only officer access": [
+ "Lesezugriff für Sachbearbeiter"
],
- "The officer session is invalid.": [
- "Die Sitzung des AML-Sachbearbeiters ist ungültig."
+ "You can review AML information, but this officer key cannot submit decisions.": [
+ "Sie können AML-Informationen prüfen, aber dieser Sachbearbeiterschlüssel kann keine Entscheidungen einreichen."
],
- "The measures endpoint was not found.": [
- "Der Endpunkt für Maßnahmen wurde nicht gefunden."
+ "This officer key cannot create or submit AML decisions.": [
+ "Dieser Sachbearbeiterschlüssel kann keine AML-Entscheidungen erstellen oder einreichen."
],
- "The officer session is disabled.": [
- "Die Sitzung des AML-Sachbearbeiters ist deaktiviert."
+ "Return to account": [
+ "Zum Konto zurückkehren"
],
"Failed to load the active AML decision.": [
"Die aktive AML-Entscheidung konnte nicht geladen werden."
],
- "The officer session signature is invalid.": [
- "Die Signatur der Sitzung des AML-Sachbearbeiters ist ungültig."
- ],
- "The requested AML account or session was not found.": [
- "Das angeforderte AML-Konto oder die Sitzung wurde nicht gefunden."
- ],
- "The officer session is disabled or the account state changed.": [
- "Die Sitzung des AML-Sachbearbeiters ist deaktiviert oder der Kontostatus hat sich geändert."
- ],
- "Invalid expiration": [
- "Ungültiges Ablaufdatum"
- ],
- "Attributes require an expiration date in the future.": [
- "Attribute benötigen ein in der Zukunft liegendes Ablaufdatum."
- ],
- "Too many SKIP measures": [
- "Zu viele SKIP-Maßnahmen"
- ],
- "At most one immediate measure may use the SKIP check.": [
- "Höchstens eine sofortige Maßnahme darf die SKIP-Prüfung verwenden."
- ],
- "Require all measures": [
- "Alle Maßnahmen voraussetzen"
- ],
- "Run all selected measures together instead of accepting any one of them.": [
- "Alle ausgewählten Maßnahmen gemeinsam ausführen, anstatt eine beliebige davon zu akzeptieren."
- ],
- "Invalid custom properties": [
- "Ungültige benutzerdefinierte Eigenschaften"
- ],
- "Custom property names and values must be non-empty and names must be unique and different from built-in properties.": [
- "Namen und Werte benutzerdefinierter Eigenschaften dürfen nicht leer sein; die Namen müssen eindeutig sein und sich von integrierten Eigenschaften unterscheiden."
- ],
- "Unknown measure": [
- "Unbekannte Maßnahme"
- ],
- "A rule or immediate action references a measure that is not available. Review the rules and measures before submitting.": [
- "Eine Regel oder sofortige Aktion verweist auf eine nicht verfügbare Maßnahme. Prüfen Sie die Regeln und Maßnahmen vor dem Absenden."
- ],
- "Requires investigation": [
- "Erfordert eine Untersuchung"
- ],
- "Collection event not found": [
- "Erfassungsereignis nicht gefunden"
- ],
- "There is no collection event with ID %1$s for this account.": [
- "Für dieses Konto gibt es kein Erfassungsereignis mit der ID %1$s."
- ],
- "Attributes unavailable": [
- "Attribute nicht verfügbar"
- ],
- "The collection event does not contain readable attributes.": [
- "Das Erfassungsereignis enthält keine lesbaren Attribute."
- ],
- "Form identifier missing": [
- "Formular-ID fehlt"
- ],
- "The collected information does not identify the form used to create it.": [
- "Die erfassten Informationen geben nicht an, mit welchem Formular sie erstellt wurden."
- ],
- "Form not available": [
- "Formular nicht verfügbar"
- ],
- "Form %1$s is not configured in this AML Web UI.": [
- "Das Formular %1$s ist in dieser AML-Weboberfläche nicht konfiguriert."
- ],
"The account was not found.": [
"Das Konto wurde nicht gefunden."
],
@@ -6500,11 +10187,14 @@ strings['de'] = {
"The payto URI does not belong to this account. Return to the account search and start the decision again.": [
"Die Payto-URI gehört nicht zu diesem Konto. Kehren Sie zur Kontosuche zurück und beginnen Sie die Entscheidung erneut."
],
- "This account has no active decision and its payto URI is unknown. Start the decision from the account search so the account type can be determined safely.": [
- "Für dieses Konto gibt es keine aktive Entscheidung und seine Payto-URI ist unbekannt. Starten Sie die Entscheidung über die Kontosuche, damit der Kontotyp sicher bestimmt werden kann."
+ "Session": [
+ "Sitzung"
],
- "Return to account": [
- "Zum Konto zurückkehren"
+ "AML navigation": [
+ "AML-Navigation"
+ ],
+ "Measures": [
+ "Maßnahmen"
],
"threshold\u0004%1$s every %2$s": [
"%1$s alle %2$s"
@@ -6538,6 +10228,6 @@ strings['de'] = {
"domain": "messages",
"plural_forms": "",
"lang": "de",
- "completeness": 89
+ "completeness": 60
};
diff --git a/packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.stories.tsx b/packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.stories.tsx
@@ -0,0 +1,143 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import {
+ AmlDecision,
+ AmountString,
+ AvailableMeasureSummary,
+ HttpStatusCode,
+ LimitOperationType,
+ TalerExchangeHttpClient,
+ opFixedSuccess,
+ opKnownFailure,
+} from "@gnu-taler/taler-util";
+import { dummyHttpResponse } from "@gnu-taler/taler-util/http";
+import * as tests from "@gnu-taler/web-util/testing";
+import { AccountDecisionHistory } from "./AccountDecisionHistory.js";
+
+export default { title: "account decision history page" };
+
+const account = "1111111111111111111111111111111111111111111111111111";
+const now = Math.floor(Date.now() / 1000);
+const timestamp = (seconds: number) => ({ t_s: seconds }) as const;
+
+const previousDecision: AmlDecision = {
+ h_payto: account as never,
+ full_payto:
+ "payto://iban/CH9300762011623852957?receiver-name=Example%20Trading%20AG",
+ is_wallet: false,
+ rowid: 42 as never,
+ justification: "Initial account review completed.",
+ new_measures: "+review-documents current-monitoring",
+ decider_pub: "OFFICERPUB0123456789012345678901234567890123456789012",
+ decider_name: "Alex Compliance",
+ kyc_attributes_rowid: 17 as never,
+ decision_time: timestamp(now - 90 * 24 * 60 * 60),
+ properties: {},
+ limits: {
+ expiration_time: timestamp(now - 60 * 24 * 60 * 60),
+ rules: [
+ {
+ operation_type: LimitOperationType.aggregate,
+ threshold: "CHF:10000" as AmountString,
+ timeframe: { d_us: 30 * 24 * 60 * 60 * 1_000_000 },
+ measures: ["review-documents"],
+ display_priority: 20,
+ exposed: true,
+ is_and_combinator: false,
+ },
+ ],
+ custom_measures: {
+ "review-documents": {
+ check_name: "identity-form",
+ prog_name: "manual-review",
+ context: { document: "ownership" },
+ },
+ },
+ },
+ to_investigate: false,
+ is_active: false,
+};
+
+const props = {
+ account,
+ routeToShowCollectedInfo: ({ cid, rowId }: { cid: string; rowId: string }) =>
+ `/account/${cid}/attributes/${rowId}`,
+};
+
+const serverMeasures: AvailableMeasureSummary = {
+ roots: {
+ "current-monitoring": {
+ check_name: "skip",
+ prog_name: "manual-review",
+ },
+ },
+ checks: {
+ "identity-form": {
+ description: "Collect and review identity documents",
+ requires: [],
+ outputs: ["identity"],
+ fallback: "manual-review",
+ },
+ },
+ programs: {
+ "manual-review": {
+ description: "Perform an AML officer review",
+ context: [],
+ inputs: ["identity"],
+ },
+ },
+ default_rules: [],
+};
+
+function exchangeWithHistory(
+ records: AmlDecision[],
+): Partial<TalerExchangeHttpClient> {
+ return {
+ getAmlDecisions: async () => opFixedSuccess(dummyHttpResponse, { records }),
+ getAmlMeasures: async () =>
+ opFixedSuccess(dummyHttpResponse, serverMeasures),
+ };
+}
+
+export const Populated = tests.createExample(AccountDecisionHistory, props, {
+ exchange: exchangeWithHistory([
+ previousDecision,
+ {
+ ...previousDecision,
+ rowid: 41 as never,
+ new_measures: "removed-measure",
+ decider_pub: undefined,
+ decider_name: undefined,
+ kyc_attributes_rowid: undefined,
+ justification: undefined,
+ },
+ ]),
+});
+
+export const Empty = tests.createExample(AccountDecisionHistory, props, {
+ exchange: exchangeWithHistory([]),
+});
+
+export const Failure = tests.createExample(AccountDecisionHistory, props, {
+ exchange: {
+ getAmlDecisions: async () =>
+ opKnownFailure(dummyHttpResponse, HttpStatusCode.Conflict),
+ getAmlMeasures: async () =>
+ opFixedSuccess(dummyHttpResponse, serverMeasures),
+ },
+});
+
+export const Loading = tests.createExample(AccountDecisionHistory, props, {
+ exchange: {
+ getAmlDecisions: async () => await new Promise<never>(() => undefined),
+ getAmlMeasures: async () =>
+ opFixedSuccess(dummyHttpResponse, serverMeasures),
+ },
+});
diff --git a/packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx b/packages/taler-exchange-aml-webui/src/pages/AccountDecisionHistory.tsx
@@ -0,0 +1,152 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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 { TalerError } from "@gnu-taler/taler-util";
+import {
+ AsyncButton,
+ Attention,
+ Pagination,
+ useExchangeApiContext,
+ useTranslationContext,
+} from "@gnu-taler/web-util/browser";
+import { VNode, h } from "preact";
+import { ShowDecisionLimitInfo } from "../components/ShowDecisionLimitInfo.js";
+import {
+ revalidateAccountDecisions,
+ useAccountDecisions,
+} from "../hooks/decisions.js";
+import { useAmlSpaDialect } from "../hooks/preferences.js";
+import { useServerMeasures } from "../hooks/server-info.js";
+
+export function AccountDecisionHistory({
+ account,
+ routeToShowCollectedInfo,
+}: {
+ account: string;
+ routeToShowCollectedInfo: (params: { cid: string; rowId: string }) => string;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ const { config } = useExchangeApiContext();
+ const dialect = useAmlSpaDialect(config.config.aml_spa_dialect);
+ const history = useAccountDecisions(account, false);
+ const measures = useServerMeasures();
+ const historyOk =
+ history && !(history instanceof TalerError) && history.type === "ok"
+ ? history
+ : undefined;
+ const historyFailed =
+ history instanceof TalerError || history?.type === "fail";
+ const decisions = historyOk?.body ?? [];
+ const measuresOk =
+ measures && !(measures instanceof TalerError) && measures.type === "ok"
+ ? measures.body
+ : undefined;
+ const measuresFailed =
+ measures instanceof TalerError || measures?.type === "fail";
+
+ return (
+ <section aria-labelledby="decision-history-heading" class="space-y-6">
+ <div>
+ <h2
+ id="decision-history-heading"
+ class="text-2xl font-semibold tracking-tight text-gray-950 dark:text-gray-50"
+ >
+ <i18n.Translate>Decision history</i18n.Translate>
+ </h2>
+ <p class="mt-2 text-sm leading-6 text-gray-600 dark:text-gray-300">
+ <i18n.Translate>
+ Review superseded AML decisions for this account, from newest to
+ oldest.
+ </i18n.Translate>
+ </p>
+ </div>
+
+ {!history ? (
+ <p role="status" class="py-6 text-sm text-gray-600 dark:text-gray-300">
+ <i18n.Translate>Loading decision history…</i18n.Translate>
+ </p>
+ ) : historyFailed ? (
+ <Attention
+ type="danger"
+ title={i18n.str`Decision history could not be loaded`}
+ >
+ <p>
+ <i18n.Translate>
+ Try loading the decision history again.
+ </i18n.Translate>
+ </p>
+ <AsyncButton
+ class="mt-3 min-h-11 rounded-md bg-primary px-4 py-2 text-sm font-semibold text-white hover:bg-primary/90 dark:bg-darkPrimary dark:text-gray-950"
+ onClick={async () => {
+ await revalidateAccountDecisions();
+ }}
+ >
+ <i18n.Translate>Retry</i18n.Translate>
+ </AsyncButton>
+ <details class="mt-3">
+ <summary class="min-h-11 cursor-pointer py-2 font-semibold underline">
+ <i18n.Translate>Technical details</i18n.Translate>
+ </summary>
+ <pre class="max-h-72 overflow-auto whitespace-pre-wrap break-words rounded-md bg-white/70 p-3 text-xs text-black">
+ {JSON.stringify(history, null, 2)}
+ </pre>
+ </details>
+ </Attention>
+ ) : !decisions.length ? (
+ <div class="rounded-md border border-dashed border-gray-300 bg-gray-50 px-4 py-6 dark:border-gray-700 dark:bg-gray-900/60">
+ <h2 class="font-semibold text-gray-900 dark:text-gray-100">
+ <i18n.Translate>No previous decisions</i18n.Translate>
+ </h2>
+ <p class="mt-1 text-sm text-gray-600 dark:text-gray-300">
+ <i18n.Translate>
+ No superseded AML decisions have been recorded for this account.
+ </i18n.Translate>
+ </p>
+ </div>
+ ) : (
+ <section aria-labelledby="decision-list-heading" class="space-y-4">
+ <h2
+ id="decision-list-heading"
+ class="text-lg font-semibold text-gray-950 dark:text-gray-50"
+ >
+ <i18n.Translate>Previous decisions</i18n.Translate>
+ </h2>
+ <div class="space-y-3">
+ {decisions.map((decision) => (
+ <ShowDecisionLimitInfo
+ key={decision.rowid}
+ decision={decision}
+ dialect={dialect}
+ serverMeasures={measuresOk}
+ serverMeasuresLoading={!measures}
+ serverMeasuresUnavailable={measuresFailed}
+ account={account}
+ routeToShowCollectedInfo={routeToShowCollectedInfo}
+ presentation="history-disclosure"
+ />
+ ))}
+ </div>
+ <Pagination
+ currentPage={historyOk!.currentPage}
+ onFirstPage={historyOk!.loadFirst}
+ onPrevious={historyOk!.loadPrev}
+ onNext={historyOk!.loadNext}
+ />
+ </section>
+ )}
+ </section>
+ );
+}
diff --git a/packages/taler-exchange-aml-webui/src/pages/AccountDetails.stories.tsx b/packages/taler-exchange-aml-webui/src/pages/AccountDetails.stories.tsx
@@ -0,0 +1,339 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+import {
+ AmlDecision,
+ AmountString,
+ AvailableMeasureSummary,
+ CustomerAccountSummary,
+ HttpStatusCode,
+ KycAttributeCollectionEvent,
+ LegitimizationMeasureDetails,
+ LimitOperationType,
+ TalerAmlProperties,
+ TalerExchangeHttpClient,
+ TalerFormAttributes,
+ opFixedSuccess,
+ opKnownFailure,
+} from "@gnu-taler/taler-util";
+import { dummyHttpResponse } from "@gnu-taler/taler-util/http";
+import * as tests from "@gnu-taler/web-util/testing";
+import { VNode, h } from "preact";
+import { AccountCaseShell } from "../components/AccountCaseShell.js";
+import { AccountDetails } from "./AccountDetails.js";
+
+export default { title: "account case" };
+
+const account = "1111111111111111111111111111111111111111111111111111";
+const fullPayto =
+ "payto://iban/CH9300762011623852957?receiver-name=Example%20Trading%20AG";
+const now = Math.floor(Date.now() / 1000);
+const timestamp = (seconds: number) => ({ t_s: seconds }) as const;
+const rule = {
+ operation_type: LimitOperationType.aggregate,
+ threshold: "ARS:10000" as AmountString,
+ timeframe: { d_us: 30 * 24 * 60 * 60 * 1_000_000 },
+ measures: ["review-documents"],
+ display_priority: 20,
+ exposed: true,
+ is_and_combinator: false,
+};
+
+const currentDecision: AmlDecision = {
+ h_payto: account as never,
+ full_payto: fullPayto,
+ is_wallet: false,
+ rowid: 43 as never,
+ justification:
+ "A change in beneficial ownership requires enhanced monitoring.",
+ new_measures: "+review-documents standard-monitoring",
+ decider_pub: "OFFICERPUB0123456789012345678901234567890123456789012",
+ decider_name: "Alex Compliance",
+ kyc_attributes_rowid: 18 as never,
+ decision_time: timestamp(now - 3_600),
+ properties: {
+ [TalerAmlProperties.CUSTOMER_LABEL]: "Example Trading AG",
+ [TalerAmlProperties.FILE_NOTE]:
+ "Confirm the source of funds before removing the investigation flag.",
+ [TalerAmlProperties.HIGH_RISK_CUSTOMER]: true,
+ business_domain: "Wholesale trade",
+ },
+ limits: {
+ expiration_time: timestamp(now + 30 * 24 * 60 * 60),
+ successor_measure: "standard-monitoring",
+ rules: [rule],
+ custom_measures: {
+ "review-documents": {
+ check_name: "identity-form",
+ prog_name: "review-documents",
+ context: { requested_document: "proof-of-address" },
+ },
+ },
+ },
+ to_investigate: true,
+ is_active: true,
+};
+
+const openSummary: CustomerAccountSummary = {
+ h_payto: account as never,
+ full_payto: fullPayto as never,
+ customer_label: "Example Trading AG",
+ high_risk: true,
+ comments:
+ "Confirm the source of funds before removing the investigation flag.",
+ rowid: 1042 as never,
+ open_time: timestamp(now - 90 * 24 * 60 * 60),
+ close_time: { t_s: "never" },
+ to_investigate: true,
+};
+
+const notOpenedSummary: CustomerAccountSummary = {
+ ...openSummary,
+ customer_label: "New wallet customer",
+ comments: "Contact the customer if the next transfer crosses the limit.",
+ system_note: "BELOW_ACCOUNT_OPENING_THRESHOLD",
+ high_risk: false,
+ rowid: 1043 as never,
+ open_time: { t_s: "never" },
+ to_investigate: false,
+};
+
+const closedSummary: CustomerAccountSummary = {
+ ...openSummary,
+ customer_label: "Former customer",
+ comments: "Relationship closed after the final review.",
+ high_risk: false,
+ rowid: 1041 as never,
+ close_time: timestamp(now - 24 * 60 * 60),
+ to_investigate: false,
+};
+
+const attributes: KycAttributeCollectionEvent[] = [
+ {
+ rowid: 18 as never,
+ by_aml_officer: true,
+ collection_time: timestamp(now - 1_800),
+ attributes: {
+ [TalerFormAttributes.FORM_ID]: "generic_note",
+ [TalerFormAttributes.FORM_VERSION]: 1,
+ note: "Ownership documentation reviewed by AML staff.",
+ },
+ },
+ {
+ rowid: 17 as never,
+ by_aml_officer: false,
+ collection_time: timestamp(now - 24 * 60 * 60),
+ },
+];
+
+const requirements: LegitimizationMeasureDetails[] = [
+ {
+ h_payto: account as never,
+ rowid: 9 as never,
+ start_time: timestamp(now - 7_200),
+ is_finished: false,
+ measures: {
+ measures: [
+ {
+ check_name: "identity-form",
+ prog_name: "review-documents",
+ context: { requested_document: "proof-of-address" },
+ },
+ ],
+ is_and_combinator: false,
+ verboten: false,
+ },
+ },
+ {
+ h_payto: account as never,
+ rowid: 8 as never,
+ start_time: timestamp(now - 10_800),
+ is_finished: true,
+ measures: {
+ measures: [],
+ is_and_combinator: false,
+ verboten: true,
+ },
+ },
+];
+
+const serverMeasures: AvailableMeasureSummary = {
+ roots: {
+ "standard-monitoring": {
+ check_name: "skip",
+ prog_name: "review-documents",
+ },
+ },
+ checks: {
+ "identity-form": {
+ description: "Proof of address",
+ requires: ["requested_document"],
+ outputs: ["full_name", "address"],
+ fallback: "manual-review",
+ },
+ },
+ programs: {
+ "review-documents": {
+ description: "Review submitted documents",
+ context: [],
+ inputs: ["full_name", "address"],
+ },
+ },
+ default_rules: [rule],
+};
+
+function exchangeFor({
+ current = currentDecision,
+ events = attributes,
+ activeRequirements = requirements,
+ failCurrent = false,
+ loadEventsForever = false,
+ summary = openSummary,
+ failSummary = false,
+ loadSummaryForever = false,
+}: {
+ current?: AmlDecision | null;
+ events?: KycAttributeCollectionEvent[];
+ activeRequirements?: LegitimizationMeasureDetails[];
+ failCurrent?: boolean;
+ loadEventsForever?: boolean;
+ summary?: CustomerAccountSummary | null;
+ failSummary?: boolean;
+ loadSummaryForever?: boolean;
+} = {}): Partial<TalerExchangeHttpClient> {
+ return {
+ getAmlAccounts: async () => {
+ if (loadSummaryForever) return await new Promise<never>(() => undefined);
+ if (failSummary) {
+ return opKnownFailure(dummyHttpResponse, HttpStatusCode.Conflict);
+ }
+ return opFixedSuccess(dummyHttpResponse, {
+ accounts: summary ? [summary] : [],
+ });
+ },
+ getAmlAttributesForAccount: async () => {
+ if (loadEventsForever) return await new Promise<never>(() => undefined);
+ return opFixedSuccess(dummyHttpResponse, { details: events });
+ },
+ getAmlDecisions: async (_officer, args) => {
+ if (args?.active === true && failCurrent) {
+ return opKnownFailure(dummyHttpResponse, HttpStatusCode.Conflict);
+ }
+ return opFixedSuccess(dummyHttpResponse, {
+ records: current ? [current] : [],
+ });
+ },
+ getAmlLegitimizations: async () =>
+ opFixedSuccess(dummyHttpResponse, { measures: activeRequirements }),
+ getAmlMeasures: async () =>
+ opFixedSuccess(dummyHttpResponse, serverMeasures),
+ getAmlAttributesForAccountAsPdf: async () =>
+ opFixedSuccess(dummyHttpResponse, new Uint8Array()),
+ };
+}
+
+const props = {
+ account,
+ fullPayto,
+ routeToShowCollectedInfo: ({ cid, rowId }: { cid: string; rowId: string }) =>
+ `#/account/${cid}/attributes/${rowId}`,
+};
+
+function AccountCaseStory(): VNode {
+ return (
+ <AccountCaseShell
+ account={account}
+ fullPayto={fullPayto}
+ activeView="overview"
+ routeToAccounts="#/accounts"
+ routeToOverview={`#/account/${account}`}
+ routeToTransfers={`#/account/${account}/transfers`}
+ routeToHistory={`#/account/${account}/history`}
+ onNewDecision={() => undefined}
+ >
+ <AccountDetails {...props} />
+ </AccountCaseShell>
+ );
+}
+
+export const FullyPopulated = tests.createExample(
+ AccountCaseStory,
+ {},
+ {
+ exchange: exchangeFor(),
+ },
+);
+
+export const NotOpenedWithOfficerAndSystemNotes = tests.createExample(
+ AccountCaseStory,
+ {},
+ {
+ exchange: exchangeFor({ summary: notOpenedSummary }),
+ },
+);
+
+export const ClosedAccount = tests.createExample(
+ AccountCaseStory,
+ {},
+ {
+ exchange: exchangeFor({ summary: closedSummary }),
+ },
+);
+
+export const SummaryUnavailable = tests.createExample(
+ AccountCaseStory,
+ {},
+ {
+ exchange: exchangeFor({ failSummary: true }),
+ },
+);
+
+export const SummaryLoading = tests.createExample(
+ AccountCaseStory,
+ {},
+ {
+ exchange: exchangeFor({ loadSummaryForever: true }),
+ },
+);
+
+export const EmptySectionsAndExchangeDefaults = tests.createExample(
+ AccountCaseStory,
+ {},
+ {
+ exchange: exchangeFor({
+ current: null,
+ events: [],
+ activeRequirements: [],
+ }),
+ },
+);
+
+export const ReadOnlyOfficer = tests.createExample(
+ AccountCaseStory,
+ {},
+ {
+ exchange: exchangeFor(),
+ officerInfo: { officer_name: "Read-only reviewer", read_only: true },
+ },
+);
+
+export const SectionFailure = tests.createExample(
+ AccountCaseStory,
+ {},
+ {
+ exchange: exchangeFor({ failCurrent: true }),
+ },
+);
+
+export const EvidenceLoading = tests.createExample(
+ AccountCaseStory,
+ {},
+ {
+ exchange: exchangeFor({ loadEventsForever: true }),
+ },
+);
diff --git a/packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx b/packages/taler-exchange-aml-webui/src/pages/AccountDetails.tsx
@@ -1,619 +1,633 @@
/*
This file is part of GNU Taler
- (C) 2022-2025 Taler Systems S.A.
+ (C) 2022-2026 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 {
AbsoluteTime,
- AccountProperties,
- assertUnreachable,
- HttpStatusCode,
- OfficerSession,
- OperationFail,
+ Paytos,
+ Result,
TalerError,
TalerExchangeApi,
TalerFormAttributes,
TranslatedString,
} from "@gnu-taler/taler-util";
import {
- Attention,
AsyncButton,
- CopyButton,
- ErrorLoading,
- FailLoading,
- Loading,
+ Attention,
+ FormMetadata,
Pagination,
- RouteDefinition,
+ Time,
useExchangeApiContext,
- useNotificationContext,
- useNotifiedOperation,
useTranslationContext,
} from "@gnu-taler/web-util/browser";
-import { format } from "date-fns";
-import { h, VNode } from "preact";
-import { useState } from "preact/hooks";
-import { Fragment } from "preact/jsx-runtime";
-import pdfIcon from "../assets/pdf-icon.png";
+import { ComponentChildren, Fragment, VNode, h } from "preact";
+import { Link } from "wouter-preact";
+import { isWalletPaytoType } from "../components/AccountBadges.js";
+import { useAccountCaseContext } from "../components/AccountCaseShell.js";
+import { AccountSummaryNotes } from "../components/AccountSummary.js";
import { ShowDecisionLimitInfo } from "../components/ShowDecisionLimitInfo.js";
-import { ShowDefaultRules } from "../components/ShowDefaultRules.js";
import { ShowLegistimizationInfo } from "../components/ShowLegitimizationInfo.js";
-import { useAccountInformation } from "../hooks/account.js";
+import { RulesInfo } from "../components/RulesInfo.js";
+import { useUiFormsContext } from "../context/ui-forms.js";
+import {
+ revalidateAccountInformation,
+ useAccountInformation,
+} from "../hooks/account.js";
import {
+ revalidateAccountDecisions,
useAccountActiveDecision,
- useAccountDecisions,
} from "../hooks/decisions.js";
-import { useCurrentLegitimizations } from "../hooks/legitimizations.js";
-import { useOfficer } from "../hooks/officer.js";
-import { useServerMeasures } from "../hooks/server-info.js";
+import {
+ revalidateCurrentLegitimizations,
+ useCurrentLegitimizations,
+} from "../hooks/legitimizations.js";
+import { useAmlSpaDialect } from "../hooks/preferences.js";
+import {
+ revalidateServerMeasures,
+ useServerMeasures,
+} from "../hooks/server-info.js";
import { BANK_RULES, WALLET_RULES } from "./decision/Rules.js";
-export function ShowProperties(props: {
- properties?: AccountProperties;
-}): VNode {
- const { properties } = props;
- const keys = Object.keys(properties ?? {});
- if (!properties || keys.length == 0) {
- return <span>No properties defined for this account.</span>;
- }
- return (
- <>
- {keys.map((x, idx) => {
- if (properties[x] == null) {
- return null;
- }
- return (
- <p key={idx}>
- {x}: {properties[x]}
- </p>
- );
- })}
- </>
- );
-}
+type Retry = () => unknown;
export function AccountDetails({
account,
+ fullPayto,
routeToShowCollectedInfo,
- onNewDecision,
- routeToShowTransfers,
}: {
- onNewDecision: () => void;
- routeToShowCollectedInfo: RouteDefinition<{ cid: string; rowId: string }>;
+ routeToShowCollectedInfo: (params: { cid: string; rowId: string }) => string;
account: string;
- routeToShowTransfers: RouteDefinition<{ cid: string }>;
-}) {
+ fullPayto?: string;
+}): VNode {
const { i18n } = useTranslationContext();
+ const { config } = useExchangeApiContext();
+ const { forms } = useUiFormsContext();
+ const caseContext = useAccountCaseContext();
+ const dialect = useAmlSpaDialect(config.config.aml_spa_dialect);
const details = useAccountInformation(account);
- const history = useAccountDecisions(account);
const active = useAccountActiveDecision(account);
- const legistimizations = useCurrentLegitimizations(account);
- const officer = useOfficer();
- const session = officer.state === "ready" ? officer.session : undefined;
- const { lib } = useExchangeApiContext();
- const [exported, setExported] = useState<{ content: string; file: string }>();
- const { showError } = useNotificationContext();
-
- const downloadPdf = useNotifiedOperation<
- Awaited<ReturnType<typeof lib.exchange.getAmlAttributesForAccountAsPdf>>,
- [OfficerSession, string]
- >(
- (_ct, officerSession: OfficerSession, accountId: string) =>
- lib.exchange.getAmlAttributesForAccountAsPdf(officerSession, accountId),
- {
- onSuccess: (result) => {
- const time = format(new Date(), "yyyyMMdd_HHmmss");
- setExported({
- content: new Uint8Array(result).reduce(
- (data, byte) => data + String.fromCharCode(byte),
- "",
- ),
- file: `account_${time}_${account}.pdf`,
- });
- },
- onFail: showError(i18n.str`Failed to download report.`, (fail) => {
- switch (fail.case) {
- case HttpStatusCode.NoContent:
- return i18n.str`The account has no KYC info.`;
- case HttpStatusCode.Forbidden:
- return i18n.str`Authorization denied for this session. Contact the administrator.`;
- case HttpStatusCode.NotFound:
- return i18n.str`Session not found. Contact the administrator.`;
- case HttpStatusCode.Conflict:
- return i18n.str`The session is disabled. Contact the administrator.`;
- case HttpStatusCode.NotImplemented:
- return i18n.str`The server doesn't support PDF download. Contact the administrator.`;
- default:
- assertUnreachable(fail.case);
- }
- }),
- },
- );
-
+ const legitimizations = useCurrentLegitimizations(account);
const measures = useServerMeasures();
- if (!details || !history || !active || !legistimizations || !measures) {
- return <Loading />;
- }
- if (details instanceof TalerError) {
- return (
- <ErrorLoading
- title={i18n.str`Failed to load account information.`}
- error={details}
- />
- );
- }
- if (details.type === "fail") {
- return (
- <KnownFailure
- title={i18n.str`Failed to load account information.`}
- operation={details}
- />
- );
- }
- if (history instanceof TalerError) {
- return (
- <ErrorLoading
- title={i18n.str`Failed to load decision history.`}
- error={history}
- />
- );
- }
- if (history.type === "fail") {
- return (
- <KnownFailure
- title={i18n.str`Failed to load decision history.`}
- operation={history}
- />
- );
- }
- if (active instanceof TalerError) {
- return (
- <ErrorLoading
- title={i18n.str`Failed to load the active AML decision.`}
- error={active}
- />
- );
- }
- if (active.type === "fail") {
- return (
- <KnownFailure
- title={i18n.str`Failed to load the active AML decision.`}
- operation={active}
- />
- );
- }
- if (legistimizations instanceof TalerError) {
- return (
- <ErrorLoading
- title={i18n.str`Failed to load current legitimizations.`}
- error={legistimizations}
- />
- );
- }
- if (legistimizations.type === "fail") {
- return (
- <KnownFailure
- title={i18n.str`Failed to load current legitimizations.`}
- operation={legistimizations}
- />
- );
- }
- if (measures instanceof TalerError) {
- return (
- <ErrorLoading
- title={i18n.str`Failed to load available measures.`}
- error={measures}
- />
- );
- }
- if (measures.type === "fail") {
- return (
- <KnownFailure
- title={i18n.str`Failed to load available measures.`}
- operation={measures}
- />
- );
- }
+ const detailsOk =
+ details && !(details instanceof TalerError) && details.type === "ok"
+ ? details
+ : undefined;
+ const activeOk =
+ active && !(active instanceof TalerError) && active.type === "ok"
+ ? active
+ : undefined;
+ const legitimizationsOk =
+ legitimizations &&
+ !(legitimizations instanceof TalerError) &&
+ legitimizations.type === "ok"
+ ? legitimizations
+ : undefined;
+ const measuresOk =
+ measures && !(measures instanceof TalerError) && measures.type === "ok"
+ ? measures
+ : undefined;
- const collectionEvents = [...details.body].sort((a, b) =>
- AbsoluteTime.cmp(
- AbsoluteTime.fromProtocolTimestamp(a.collection_time),
- AbsoluteTime.fromProtocolTimestamp(b.collection_time),
- ),
+ const activeDecision = activeOk?.body;
+ const decisionTargetPayto = fullPayto ?? activeDecision?.full_payto;
+ const parsedTarget = decisionTargetPayto
+ ? Result.orUndefined(Paytos.fromString(decisionTargetPayto))
+ : undefined;
+ const targetIsWallet =
+ activeDecision?.is_wallet ??
+ (parsedTarget ? isWalletPaytoType(parsedTarget.targetType) : undefined);
+ const collectionEvents = detailsOk?.body ?? [];
+ const activeRequirements = legitimizationsOk?.body ?? [];
+ const requirementCounts = activeRequirements.reduce(
+ (counts, requirement) => {
+ if (requirement.measures.verboten) counts.forbidden += 1;
+ else if (requirement.is_finished) counts.completed += 1;
+ else counts.waiting += 1;
+ return counts;
+ },
+ { waiting: 0, completed: 0, forbidden: 0 },
);
+ const defaultRules = measuresOk?.body.default_rules ?? [];
+ const filteredRulesByType =
+ targetIsWallet === undefined
+ ? []
+ : defaultRules.filter((rule) =>
+ targetIsWallet
+ ? WALLET_RULES.includes(rule.operation_type)
+ : BANK_RULES.includes(rule.operation_type),
+ );
- const activeDecision = active.body;
- const restDecisions = !activeDecision
- ? history.body
- : history.body.filter((d) => d.rowid !== activeDecision.rowid);
-
- function ShortcutActionButtons(): VNode {
- return (
- <div>
- <button
- onClick={async () => {
- // the wizard should not require checking the account state
- // instead here all the values from the current decision should be
- // loaded into the new decision request, like we are doing with e
- // custom measures
- // FIXME-do-this add properties, limits, investigation state
- onNewDecision();
- }}
- class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
- >
- <i18n.Translate>New decision</i18n.Translate>
- </button>
- <a
- href={routeToShowTransfers.url({
- cid: account,
- })}
- class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
- >
- <i18n.Translate>Show transfers</i18n.Translate>
- </a>
- </div>
- );
- }
-
- const defaultRules = measures.body.default_rules;
- const serverMeasures = measures.body;
-
- const filteredRulesByType = !activeDecision
- ? defaultRules
- : defaultRules.filter((r) => {
- return activeDecision.is_wallet
- ? WALLET_RULES.includes(r.operation_type)
- : BANK_RULES.includes(r.operation_type);
- });
+ const activeFailed = active instanceof TalerError || active?.type === "fail";
+ const detailsFailed =
+ details instanceof TalerError || details?.type === "fail";
+ const legitimizationsFailed =
+ legitimizations instanceof TalerError || legitimizations?.type === "fail";
+ const measuresFailed =
+ measures instanceof TalerError || measures?.type === "fail";
return (
- <div class="min-w-60">
- <header class="flex flex-col justify-between border-b border-white/5 px-4 py-4 sm:px-6 sm:py-6 lg:px-8 gap-2">
- <h1 class="text-base font-semibold leading-7 text-black">
- <i18n.Translate>Case history for selected account</i18n.Translate>
- </h1>
- <div>
- <p>
- <span class="font-bold">
- <i18n.Translate>ID:</i18n.Translate>
- </span>{" "}
- {account} <CopyButton class="" getContent={() => account} />
- </p>
- <p>
- <span class="font-bold">
- <i18n.Translate>Payto:</i18n.Translate>
- </span>{" "}
- {activeDecision?.full_payto ?? "N/A"}{" "}
- <CopyButton
- class=""
- getContent={() => activeDecision?.full_payto ?? "N/A"}
- />
- </p>
- </div>
-
- <div class="flex space-x-2 mb-4">
- <i18n.Translate>Export as PDF</i18n.Translate>
- <AsyncButton
- onClick={
- !session ? undefined : () => downloadPdf.run(session, account)
- }
+ <>
+ <CaseSection
+ id="case-summary"
+ title={i18n.str`Case summary`}
+ description={i18n.str`Current review state and the latest account activity.`}
+ >
+ <div class="grid divide-y divide-gray-200 sm:grid-cols-2 sm:divide-y-0 xl:grid-cols-4 xl:divide-x dark:divide-gray-700">
+ <SummaryItem
+ label={i18n.str`Review status`}
+ targetId="effective-policy"
+ >
+ {!active
+ ? i18n.str`Loading…`
+ : activeFailed
+ ? i18n.str`Unavailable`
+ : activeDecision?.to_investigate
+ ? i18n.str`Manual review required — waiting for an AML decision.`
+ : i18n.str`No manual review`}
+ </SummaryItem>
+ <SummaryItem
+ label={i18n.str`Effective decision`}
+ targetId="effective-policy"
+ >
+ {!active ? (
+ i18n.str`Loading…`
+ ) : activeFailed ? (
+ i18n.str`Unavailable`
+ ) : activeDecision ? (
+ <DecisionSummary
+ until={AbsoluteTime.fromProtocolTimestamp(
+ activeDecision.limits.expiration_time,
+ )}
+ />
+ ) : (
+ i18n.str`Exchange defaults`
+ )}
+ </SummaryItem>
+ <SummaryItem
+ label={i18n.str`Requirements`}
+ targetId="active-requirements"
>
- <img class="size-6 w-6" src={pdfIcon} />
- </AsyncButton>
+ {!legitimizations ? (
+ i18n.str`Loading…`
+ ) : legitimizationsFailed ? (
+ i18n.str`Unavailable`
+ ) : !activeRequirements.length ? (
+ i18n.str`None`
+ ) : (
+ <RequirementSummary
+ counts={requirementCounts}
+ hasMore={Boolean(legitimizationsOk?.loadNext)}
+ />
+ )}
+ </SummaryItem>
+ <SummaryItem
+ label={i18n.str`Latest collected information`}
+ targetId="collected-information"
+ >
+ {!details ? (
+ i18n.str`Loading…`
+ ) : detailsFailed ? (
+ i18n.str`Unavailable`
+ ) : collectionEvents[0] ? (
+ <Time
+ timestamp={AbsoluteTime.fromProtocolTimestamp(
+ collectionEvents[0].collection_time,
+ )}
+ format="PPp"
+ />
+ ) : (
+ i18n.str`None`
+ )}
+ </SummaryItem>
</div>
- {!exported ? (
- <div />
+ </CaseSection>
+
+ <CaseSection
+ id="account-notes"
+ title={i18n.str`Account notes`}
+ description={i18n.str`Officer-authored notes and information recorded by the exchange.`}
+ >
+ {caseContext?.summaryLoading ? (
+ <SectionLoading />
+ ) : caseContext?.summaryFailed ? (
+ <SectionFailure
+ title={i18n.str`Account notes could not be loaded`}
+ technical={{ account, summaryUnavailable: true }}
+ onRetry={caseContext.retrySummary}
+ />
+ ) : caseContext?.summary ? (
+ <div class="max-w-3xl text-sm text-gray-700 dark:text-gray-300">
+ <AccountSummaryNotes record={caseContext.summary} showEmpty />
+ </div>
) : (
- <a
- href={
- "data:application/pdf;base64," + window.btoa(exported.content)
- }
- name="save file"
- download={exported.file}
- >
- <Attention
- title={i18n.str`Export completed`}
- onClose={() => setExported(undefined)}
- >
- <i18n.Translate>
- Click here to save the file in your computer.
- </i18n.Translate>
- </Attention>
- </a>
+ <NeutralState
+ title={i18n.str`No account notes`}
+ description={i18n.str`No officer or system note is available for this account.`}
+ />
)}
- </header>
-
- {!activeDecision || !activeDecision.to_investigate ? undefined : (
- <Attention title={i18n.str`Under investigation`} type="warning">
- <i18n.Translate>
- This account requires a manual review and is waiting for a decision
- to be made.
- </i18n.Translate>
- </Attention>
- )}
-
- <ShortcutActionButtons />
-
- <div class="p-4">
- <h1 class="text-base font-semibold leading-6 text-black">
- <i18n.Translate>Collected information</i18n.Translate>
- </h1>
- <p class="mt-1 text-sm leading-6 text-gray-600">
- <i18n.Translate>
- Every attribute collection event (via form upload or KYC provider).
- </i18n.Translate>
- </p>
- </div>
+ </CaseSection>
- {collectionEvents.length === 0 ? (
- <Attention
- title={i18n.str`No collected attributes for this account.`}
- type="warning"
- />
- ) : (
- <Fragment>
- <ShowTimeline
+ <CaseSection
+ id="effective-policy"
+ title={i18n.str`Current decision`}
+ description={i18n.str`The complete AML decision currently applied to this account.`}
+ featured
+ >
+ {!active ? (
+ <SectionLoading />
+ ) : activeFailed ? (
+ <SectionFailure
+ title={i18n.str`Effective policy could not be loaded`}
+ technical={active}
+ onRetry={revalidateAccountDecisions}
+ />
+ ) : activeDecision ? (
+ <ShowDecisionLimitInfo
+ presentation="static"
+ decision={activeDecision}
+ dialect={dialect}
+ serverMeasures={measuresOk?.body}
+ serverMeasuresLoading={!measures}
+ serverMeasuresUnavailable={measuresFailed}
account={account}
- history={collectionEvents}
routeToShowCollectedInfo={routeToShowCollectedInfo}
/>
- <Pagination
- onFirstPage={details.loadFirst}
- onPrevious={details.loadPrev}
- onNext={details.loadNext}
- />
- </Fragment>
- )}
-
- <h1 class="mb-4 text-base font-semibold leading-6 text-black">
- <i18n.Translate>Current account properties</i18n.Translate>
- </h1>
+ ) : (
+ <div class="space-y-5">
+ <NeutralState
+ title={i18n.str`Exchange defaults apply`}
+ description={i18n.str`No AML officer decision is active for this account.`}
+ />
+ {targetIsWallet === undefined ? (
+ <InlineNotice title={i18n.str`Account type unavailable`}>
+ <i18n.Translate>
+ Open this case from the account directory or payto search to
+ see the applicable default rules.
+ </i18n.Translate>
+ </InlineNotice>
+ ) : !measures ? (
+ <SectionLoading />
+ ) : measuresFailed ? (
+ <SectionFailure
+ title={i18n.str`Default rules could not be loaded`}
+ technical={measures}
+ onRetry={revalidateServerMeasures}
+ />
+ ) : (
+ <div>
+ <h3 class="mb-3 text-base font-semibold text-gray-950 dark:text-gray-50">
+ <i18n.Translate>Default rules</i18n.Translate>
+ </h3>
+ <RulesInfo rules={filteredRulesByType} />
+ </div>
+ )}
+ </div>
+ )}
+ </CaseSection>
- <ShowProperties properties={activeDecision?.properties} />
+ <CaseSection
+ id="collected-information"
+ title={i18n.str`Collected information`}
+ description={i18n.str`KYC information filed by the customer or an AML officer.`}
+ >
+ {!details ? (
+ <SectionLoading />
+ ) : detailsFailed ? (
+ <SectionFailure
+ title={i18n.str`Collected information could not be loaded`}
+ technical={details}
+ onRetry={revalidateAccountInformation}
+ />
+ ) : !collectionEvents.length ? (
+ <NeutralState
+ title={i18n.str`No collected information`}
+ description={i18n.str`No KYC information has been collected for this account.`}
+ />
+ ) : (
+ <div class="space-y-3">
+ <CollectionEventList
+ account={account}
+ events={collectionEvents}
+ forms={forms}
+ routeToShowCollectedInfo={routeToShowCollectedInfo}
+ />
+ <Pagination
+ currentPage={detailsOk!.currentPage}
+ onFirstPage={detailsOk!.loadFirst}
+ onPrevious={detailsOk!.loadPrev}
+ onNext={detailsOk!.loadNext}
+ />
+ </div>
+ )}
+ </CaseSection>
- {!activeDecision ? (
- <Fragment>
- <Attention title={i18n.str`No active decision found`} type="warning">
- <i18n.Translate>
- There is no decision for this account yet. The account is limited
- by the default rules.
- </i18n.Translate>
- </Attention>
- <ShowDefaultRules rules={filteredRulesByType} />
- </Fragment>
- ) : (
- <div class="my-4">
- <h1 class="mb-4 text-base font-semibold leading-6 text-black">
- <i18n.Translate>Current active rules</i18n.Translate>
- </h1>
- <ShowDecisionLimitInfo
- since={AbsoluteTime.fromProtocolTimestamp(
- activeDecision.decision_time,
- )}
- until={AbsoluteTime.fromProtocolTimestamp(
- activeDecision.limits.expiration_time,
- )}
- justification={activeDecision.justification}
- rules={activeDecision.limits.rules}
- startOpen
- measure={activeDecision.limits.successor_measure ?? ""}
+ <CaseSection
+ id="active-requirements"
+ title={i18n.str`Active requirements`}
+ description={i18n.str`Measures the customer must complete under the current policy.`}
+ >
+ {!legitimizations ? (
+ <SectionLoading />
+ ) : legitimizationsFailed ? (
+ <SectionFailure
+ title={i18n.str`Active requirements could not be loaded`}
+ technical={legitimizations}
+ onRetry={revalidateCurrentLegitimizations}
/>
- </div>
- )}
- {restDecisions.length > 0 ? (
- <div class="my-4 grid gap-y-4">
- <h1 class="text-base font-semibold leading-6 text-black">
- <i18n.Translate>Previous AML decisions</i18n.Translate>
- </h1>
- {restDecisions.map((d, k) => {
- return (
- <ShowDecisionLimitInfo
- key={k}
- since={AbsoluteTime.fromProtocolTimestamp(d.decision_time)}
- until={AbsoluteTime.fromProtocolTimestamp(
- d.limits.expiration_time,
- )}
- justification={d.justification}
- rules={d.limits.rules}
- measure={d.limits.successor_measure ?? ""}
- />
- );
- })}
- <Pagination
- onFirstPage={history.loadFirst}
- onPrevious={history.loadPrev}
- onNext={history.loadNext}
+ ) : !activeRequirements.length ? (
+ <NeutralState
+ title={i18n.str`No active requirements`}
+ description={i18n.str`The customer has no active legitimization measures to complete.`}
/>
- </div>
- ) : !activeDecision ? (
- <div class="ty-4">
- <Attention title={i18n.str`No AML history found`} type="warning" />
- </div>
- ) : undefined}
- {legistimizations.body.length > 0 ? (
- <div class="my-4 grid gap-y-4">
- <h1 class="text-base font-semibold leading-6 text-black">
- <i18n.Translate>Current active measures</i18n.Translate>
- </h1>
- {legistimizations.body.map((d, idx) => {
- return (
+ ) : (
+ <div class="space-y-3">
+ {activeRequirements.map((requirement) => (
<ShowLegistimizationInfo
- key={idx}
- since={AbsoluteTime.fromProtocolTimestamp(d.start_time)}
- completed={d.is_finished}
- legitimization={d.measures}
- serverMeasures={serverMeasures}
+ key={requirement.rowid}
+ since={AbsoluteTime.fromProtocolTimestamp(
+ requirement.start_time,
+ )}
+ completed={requirement.is_finished}
+ legitimization={requirement.measures}
+ serverMeasures={measuresOk?.body}
/>
- );
- })}
- <Pagination
- onFirstPage={legistimizations.loadFirst}
- onPrevious={legistimizations.loadPrev}
- onNext={legistimizations.loadNext}
- />
- </div>
- ) : (
- <Fragment />
- )}
- </div>
+ ))}
+ <Pagination
+ currentPage={legitimizationsOk!.currentPage}
+ onFirstPage={legitimizationsOk!.loadFirst}
+ onPrevious={legitimizationsOk!.loadPrev}
+ onNext={legitimizationsOk!.loadNext}
+ />
+ </div>
+ )}
+ </CaseSection>
+ </>
);
}
-function KnownFailure({
+function CaseSection({
+ id,
title,
- operation,
+ description,
+ children,
+ featured = false,
}: {
+ id: string;
title: TranslatedString;
- operation: OperationFail<
- HttpStatusCode.Forbidden | HttpStatusCode.NotFound | HttpStatusCode.Conflict
- >;
+ description: TranslatedString;
+ children: ComponentChildren;
+ featured?: boolean;
+}): VNode {
+ return (
+ <section
+ id={id}
+ aria-labelledby={`${id}-heading`}
+ class="scroll-mt-4 border-t border-gray-300 pt-6 dark:border-gray-700"
+ >
+ <header>
+ <h2
+ id={`${id}-heading`}
+ class={`${featured ? "text-2xl" : "text-xl"} font-bold tracking-tight text-gray-950 dark:text-gray-50`}
+ >
+ {title}
+ </h2>
+ <p class="mt-1 max-w-3xl text-sm leading-6 text-gray-600 dark:text-gray-300">
+ {description}
+ </p>
+ </header>
+ <div class="mt-5 space-y-4">{children}</div>
+ </section>
+ );
+}
+
+function SummaryItem({
+ label,
+ targetId,
+ children,
+}: {
+ label: TranslatedString;
+ targetId: string;
+ children: ComponentChildren;
}): VNode {
return (
- <FailLoading
- title={title}
- operation={operation}
- translate={(failure, i18n) => {
- switch (failure.case) {
- case HttpStatusCode.Forbidden:
- return <p>{i18n.str`The officer session signature is invalid.`}</p>;
- case HttpStatusCode.NotFound:
- return (
- <p>{i18n.str`The requested AML account or session was not found.`}</p>
- );
- case HttpStatusCode.Conflict:
- return (
- <p>{i18n.str`The officer session is disabled or the account state changed.`}</p>
- );
- default:
- return assertUnreachable(failure.case);
- }
+ <button
+ type="button"
+ onClick={() => {
+ document.getElementById(targetId)?.scrollIntoView({
+ behavior: "smooth",
+ block: "start",
+ });
}}
- />
+ class="min-h-24 px-3 py-4 text-left hover:bg-gray-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-inset focus-visible:outline-primary sm:px-4 dark:hover:bg-gray-900/60"
+ >
+ <span class="block text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
+ {label}
+ </span>
+ <span class="mt-2 block text-sm font-semibold leading-5 text-gray-950 dark:text-gray-100">
+ {children}
+ </span>
+ </button>
+ );
+}
+
+function DecisionSummary({ until }: { until: AbsoluteTime }): VNode {
+ const { i18n } = useTranslationContext();
+ return (
+ <span>
+ <i18n.Translate>Officer decision</i18n.Translate>
+ <span class="mt-1 block font-normal text-gray-600 dark:text-gray-300">
+ {AbsoluteTime.isNever(until) ? (
+ <i18n.Translate>Does not expire</i18n.Translate>
+ ) : (
+ <>
+ <i18n.Translate>Expires</i18n.Translate>{" "}
+ <Time timestamp={until} format="PP" />
+ </>
+ )}
+ </span>
+ </span>
);
}
-function ShowTimeline({
- history,
+function RequirementSummary({
+ counts,
+ hasMore,
+}: {
+ counts: { waiting: number; completed: number; forbidden: number };
+ hasMore: boolean;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ return (
+ <span class="flex flex-wrap gap-x-2 gap-y-1">
+ <span>
+ <i18n.Translate>Waiting</i18n.Translate>: {counts.waiting}
+ </span>
+ <span aria-hidden="true">·</span>
+ <span>
+ <i18n.Translate>Completed</i18n.Translate>: {counts.completed}
+ </span>
+ <span aria-hidden="true">·</span>
+ <span>
+ <i18n.Translate>Forbidden</i18n.Translate>: {counts.forbidden}
+ </span>
+ {hasMore ? (
+ <span class="font-normal text-gray-600 dark:text-gray-300">
+ <i18n.Translate>More on later pages</i18n.Translate>
+ </span>
+ ) : undefined}
+ </span>
+ );
+}
+
+function NeutralState({
+ title,
+ description,
+}: {
+ title: TranslatedString;
+ description: TranslatedString;
+}): VNode {
+ return (
+ <div class="rounded-md border border-dashed border-gray-300 bg-gray-50 px-4 py-5 dark:border-gray-700 dark:bg-gray-900/60">
+ <p class="font-semibold text-gray-900 dark:text-gray-100">{title}</p>
+ <p class="mt-1 text-sm text-gray-600 dark:text-gray-300">{description}</p>
+ </div>
+ );
+}
+
+function InlineNotice({
+ title,
+ children,
+}: {
+ title: TranslatedString;
+ children: ComponentChildren;
+}): VNode {
+ return (
+ <div class="rounded-md border border-amber-300 bg-amber-50 p-4 text-amber-950 dark:border-amber-700 dark:bg-amber-950 dark:text-amber-100">
+ <p class="font-semibold">{title}</p>
+ <div class="mt-1 text-sm">{children}</div>
+ </div>
+ );
+}
+
+function SectionLoading(): VNode {
+ const { i18n } = useTranslationContext();
+ return (
+ <p role="status" class="py-4 text-sm text-gray-600 dark:text-gray-300">
+ <i18n.Translate>Loading…</i18n.Translate>
+ </p>
+ );
+}
+
+function SectionFailure({
+ title,
+ technical,
+ onRetry,
+}: {
+ title: TranslatedString;
+ technical: unknown;
+ onRetry: Retry;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ return (
+ <Attention type="danger" title={title}>
+ <p>
+ <i18n.Translate>Try loading this section again.</i18n.Translate>
+ </p>
+ <AsyncButton
+ class="mt-3 min-h-11 rounded-md bg-primary px-4 py-2 text-sm font-semibold text-white hover:bg-primary/90 dark:bg-darkPrimary dark:text-gray-950"
+ onClick={async () => {
+ await onRetry();
+ }}
+ >
+ <i18n.Translate>Retry</i18n.Translate>
+ </AsyncButton>
+ <details class="mt-3">
+ <summary class="min-h-11 cursor-pointer py-2 font-semibold underline">
+ <i18n.Translate>Technical details</i18n.Translate>
+ </summary>
+ <pre class="max-h-72 overflow-auto whitespace-pre-wrap break-words rounded-md bg-white/70 p-3 text-xs text-black">
+ {JSON.stringify(technical, null, 2)}
+ </pre>
+ </details>
+ </Attention>
+ );
+}
+
+function CollectionEventList({
+ events,
account,
+ forms,
routeToShowCollectedInfo,
}: {
+ events: TalerExchangeApi.KycAttributeCollectionEvent[];
account: string;
- routeToShowCollectedInfo: RouteDefinition<{ cid: string; rowId: string }>;
- history: TalerExchangeApi.KycAttributeCollectionEvent[];
+ forms: FormMetadata[];
+ routeToShowCollectedInfo: (params: { cid: string; rowId: string }) => string;
}): VNode {
const { i18n } = useTranslationContext();
return (
- <div class="flow-root">
- <ul role="list">
- {history.map((e, idx) => {
- const values = e.attributes ?? {};
- const formId = values[TalerFormAttributes.FORM_ID] as
- | string
- | undefined;
-
- return (
- <a
- key={idx}
- href={routeToShowCollectedInfo.url({
+ <ul class="divide-y divide-gray-200 overflow-hidden rounded-lg border border-gray-200 dark:divide-gray-700 dark:border-gray-700">
+ {events.map((event) => {
+ const formId = event.attributes?.[TalerFormAttributes.FORM_ID];
+ const form =
+ typeof formId === "string"
+ ? forms.find((candidate) => candidate.id === formId)
+ : undefined;
+ return (
+ <li key={event.rowid}>
+ <Link
+ href={routeToShowCollectedInfo({
cid: account,
- rowId: String(e.rowid),
+ rowId: String(event.rowid),
})}
+ class="block p-4 hover:bg-gray-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-inset focus-visible:outline-primary dark:hover:bg-gray-900"
>
- <li key={idx} class="hover:bg-gray-200 p-2 rounded">
- <div class="relative pb-3">
- <span class="absolute left-3 top-5 -ml-px h-full w-1 bg-gray-200"></span>
- <div class="relative flex space-x-3">
- {/* <ArrowDownCircleIcon class="h-8 w-8 text-green-700" /> */}
- <svg
- xmlns="http://www.w3.org/2000/svg"
- fill="none"
- viewBox="0 0 24 24"
- stroke-width="1.5"
- stroke="currentColor"
- class="w-6 h-6"
- >
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- d="M9 12.75l3 3m0 0l3-3m-3 3v-7.5M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
- />
- </svg>
- {!formId ? undefined : (
- <div>
- <svg
- xmlns="http://www.w3.org/2000/svg"
- fill="none"
- viewBox="0 0 24 24"
- stroke-width="1.5"
- stroke="currentColor"
- class="size-6"
- >
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- d="M12 7.5h1.5m-1.5 3h1.5m-7.5 3h7.5m-7.5 3h7.5m3-9h3.375c.621 0 1.125.504 1.125 1.125V18a2.25 2.25 0 0 1-2.25 2.25M16.5 7.5V18a2.25 2.25 0 0 0 2.25 2.25M16.5 7.5V4.875c0-.621-.504-1.125-1.125-1.125H4.125C3.504 3.75 3 4.254 3 4.875V18a2.25 2.25 0 0 0 2.25 2.25h13.5M6 7.5h3v3H6v-3Z"
- />
- </svg>
- <span>{formId}</span>
- </div>
+ <div class="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
+ <div class="min-w-0">
+ <p class="font-semibold text-gray-950 dark:text-gray-50">
+ {form?.label ??
+ (typeof formId === "string" && formId
+ ? i18n.str`Unconfigured form`
+ : i18n.str`Form not identified`)}
+ </p>
+ {typeof formId === "string" && formId ? (
+ <code class="mt-1 block break-all text-xs text-gray-500 dark:text-gray-400">
+ {formId}
+ </code>
+ ) : undefined}
+ <p class="mt-1 text-sm text-gray-600 dark:text-gray-300">
+ {event.by_aml_officer
+ ? i18n.str`Filed by an AML officer`
+ : i18n.str`Provided by the customer`}
+ </p>
+ {!event.attributes ? (
+ <p class="mt-2 text-sm font-semibold text-amber-800 dark:text-amber-300">
+ <i18n.Translate>
+ Attribute data is unavailable.
+ </i18n.Translate>
+ </p>
+ ) : undefined}
+ </div>
+ <div class="shrink-0 text-sm text-gray-600 dark:text-gray-300 sm:text-right">
+ <Time
+ timestamp={AbsoluteTime.fromProtocolTimestamp(
+ event.collection_time,
)}
- <div class="flex min-w-0 flex-1 justify-between space-x-4 pt-1.5">
- <div class="whitespace-nowrap text-right text-sm text-gray-500">
- {e.collection_time.t_s === "never" ? (
- "never"
- ) : (
- <time
- dateTime={format(
- e.collection_time.t_s * 1000,
- "dd MMM yyyy",
- )}
- >
- {format(
- e.collection_time.t_s * 1000,
- "dd MMM yyyy HH:mm:ss",
- )}
- </time>
- )}
- </div>
- </div>
- </div>
+ format="PPp"
+ />
+ <p class="mt-1 font-semibold text-primary dark:text-darkPrimary">
+ <i18n.Translate>View details</i18n.Translate>
+ </p>
</div>
- </li>
- </a>
- );
- })}
- <li class="hover:bg-gray-200 p-2 rounded">
- <div class="flex min-w-0 flex-1 justify-between space-x-4 pt-1.5">
- <svg
- xmlns="http://www.w3.org/2000/svg"
- fill="none"
- viewBox="0 0 24 24"
- stroke-width="1.5"
- stroke="currentColor"
- class="size-6 w-6 h-6"
- >
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- d="M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"
- />
- </svg>
- <p class="text-sm text-gray-900">
- <i18n.Translate>Now</i18n.Translate>
- </p>
- </div>
- </li>
- </ul>
- </div>
+ </div>
+ </Link>
+ </li>
+ );
+ })}
+ </ul>
);
}
diff --git a/packages/taler-exchange-aml-webui/src/pages/AccountList.stories.tsx b/packages/taler-exchange-aml-webui/src/pages/AccountList.stories.tsx
@@ -0,0 +1,200 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+import {
+ CustomerAccountSummary,
+ HttpStatusCode,
+ opFixedSuccess,
+ opKnownFailure,
+} from "@gnu-taler/taler-util";
+import { dummyHttpResponse } from "@gnu-taler/taler-util/http";
+import * as tests from "@gnu-taler/web-util/testing";
+import { VNode, h } from "preact";
+import { Router } from "wouter-preact";
+import { memoryLocation } from "wouter-preact/memory-location";
+import { ExchangeAmlFrame } from "../ExchangeAmlFrame.js";
+import { Navigation } from "../Routing.js";
+import { AccountList } from "./AccountList.js";
+
+export default { title: "accounts directory" };
+
+const never = { t_s: "never" } as const;
+const opened = { t_s: 1_787_900_000 } as const;
+const closed = { t_s: 1_788_000_000 } as const;
+const reserveKey = "0".repeat(52);
+
+const records: CustomerAccountSummary[] = [
+ {
+ h_payto: "1111111111111111111111111111111111111111111111111111",
+ full_payto:
+ "payto://iban/CH9300762011623852957?receiver-name=Example%20Trading%20AG" as any,
+ customer_label: "Example Trading Group",
+ high_risk: true,
+ comments:
+ "Customer requested an unusually large settlement after a change in beneficial ownership. Confirm the supporting documents and source of funds before changing the current measures.",
+ rowid: 1042 as any,
+ open_time: opened,
+ close_time: never,
+ to_investigate: true,
+ },
+ {
+ h_payto: "2222222222222222222222222222222222222222222222222222",
+ full_payto:
+ "payto://x-taler-bank/bank.example/customers/alice?receiver-name=Alice" as any,
+ high_risk: false,
+ comments: "Relationship closed after twelve months without activity.",
+ rowid: 1041 as any,
+ open_time: opened,
+ close_time: closed,
+ to_investigate: false,
+ },
+ {
+ h_payto: "3333333333333333333333333333333333333333333333333333",
+ full_payto:
+ `payto://taler-reserve/exchange.example/${reserveKey}?receiver-name=Wallet%20customer` as any,
+ high_risk: false,
+ system_note: "BELOW_ACCOUNT_OPENING_THRESHOLD",
+ rowid: 1040 as any,
+ open_time: never,
+ close_time: never,
+ to_investigate: false,
+ },
+ {
+ h_payto: "4444444444444444444444444444444444444444444444444444",
+ full_payto: "payto://iban/DE89370400440532013000" as any,
+ high_risk: false,
+ comments: "transacted amounts below limits that trigger account opening",
+ rowid: 1039 as any,
+ open_time: never,
+ close_time: never,
+ to_investigate: false,
+ },
+];
+
+const routeToAccountById = ({ cid }: { cid: string }) => `#/account/${cid}`;
+
+const successExchange = {
+ getAmlAccounts: async () =>
+ opFixedSuccess(dummyHttpResponse, { accounts: records }),
+};
+
+const { hook: accountsLocationHook } = memoryLocation({
+ path: "/accounts",
+ static: true,
+});
+
+function LoggedInAccounts(): VNode {
+ return (
+ <Router hook={accountsLocationHook}>
+ <ExchangeAmlFrame NavigationBar={Navigation}>
+ <AccountList routeToAccountById={routeToAccountById} />
+ </ExchangeAmlFrame>
+ </Router>
+ );
+}
+
+export const MixedResults = tests.createExample(
+ AccountList,
+ { routeToAccountById },
+ { exchange: successExchange },
+);
+
+export const LoggedInShell = tests.createExample(
+ LoggedInAccounts,
+ {},
+ { exchange: successExchange },
+);
+
+export const EmptyExchange = tests.createExample(
+ AccountList,
+ { routeToAccountById },
+ {
+ exchange: {
+ getAmlAccounts: async () =>
+ opFixedSuccess(dummyHttpResponse, { accounts: [] }),
+ },
+ },
+);
+
+const { hook: filteredLocationHook } = memoryLocation({
+ path: "/accounts?investigation=yes&high_risk=yes&open=yes",
+ static: true,
+});
+
+const { hook: caseQueueLocationHook } = memoryLocation({
+ path: "/accounts?investigation=yes",
+ static: true,
+});
+
+function CaseQueueAccounts(): VNode {
+ return (
+ <Router hook={caseQueueLocationHook}>
+ <AccountList routeToAccountById={routeToAccountById} />
+ </Router>
+ );
+}
+
+export const CaseQueue = tests.createExample(
+ CaseQueueAccounts,
+ {},
+ {
+ exchange: {
+ getAmlAccounts: async (
+ _officer: unknown,
+ params: { investigation?: boolean },
+ ) =>
+ opFixedSuccess(dummyHttpResponse, {
+ accounts: records.filter(
+ (record) =>
+ params.investigation === undefined ||
+ record.to_investigate === params.investigation,
+ ),
+ }),
+ },
+ },
+);
+
+function FilteredEmptyAccounts(): VNode {
+ return (
+ <Router hook={filteredLocationHook}>
+ <AccountList routeToAccountById={routeToAccountById} />
+ </Router>
+ );
+}
+
+export const FilteredEmpty = tests.createExample(
+ FilteredEmptyAccounts,
+ {},
+ {
+ exchange: {
+ getAmlAccounts: async () =>
+ opFixedSuccess(dummyHttpResponse, { accounts: [] }),
+ },
+ },
+);
+
+export const Loading = tests.createExample(
+ AccountList,
+ { routeToAccountById },
+ {
+ exchange: {
+ getAmlAccounts: async () => new Promise<never>(() => undefined),
+ },
+ },
+);
+
+export const AccessDenied = tests.createExample(
+ AccountList,
+ { routeToAccountById },
+ {
+ exchange: {
+ getAmlAccounts: async () =>
+ opKnownFailure(dummyHttpResponse, HttpStatusCode.Forbidden),
+ },
+ },
+);
diff --git a/packages/taler-exchange-aml-webui/src/pages/AccountList.test.tsx b/packages/taler-exchange-aml-webui/src/pages/AccountList.test.tsx
@@ -0,0 +1,178 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import { CustomerAccountSummary, setupI18n } from "@gnu-taler/taler-util";
+import { encodeCrockForURI } from "@gnu-taler/web-util/browser";
+import assert from "node:assert/strict";
+import test from "node:test";
+import { h, render } from "preact";
+import {
+ AccountIdentity,
+ AccountStatuses,
+ filtersFromSearch,
+} from "./AccountList.js";
+
+setupI18n("en", {});
+
+test("the case queue query selects only accounts under investigation", () => {
+ assert.deepEqual(filtersFromSearch("?investigation=yes"), {
+ investigation: true,
+ highRisk: undefined,
+ open: undefined,
+ });
+});
+
+async function installDom() {
+ const happyDomPackage = "happy-dom";
+ const { Window } = await import(happyDomPackage);
+ const window = new Window({
+ url: "https://aml.example/?investigation=yes#/accounts",
+ });
+ for (const [key, value] of Object.entries({
+ window,
+ document: window.document,
+ navigator: window.navigator,
+ Node: window.Node,
+ Element: window.Element,
+ Event: window.Event,
+ HTMLElement: window.HTMLElement,
+ HTMLAnchorElement: window.HTMLAnchorElement,
+ })) {
+ Object.defineProperty(globalThis, key, {
+ configurable: true,
+ writable: true,
+ value,
+ });
+ }
+ return window;
+}
+
+test("one browser Back action returns from an account to the filtered directory", async () => {
+ const window = await installDom();
+ const account = "1111111111111111111111111111111111111111111111111111";
+ const fullPayto =
+ "payto://iban/CH9300762011623852957?receiver-name=Example%20Trading%20AG";
+ const record: CustomerAccountSummary = {
+ h_payto: account as never,
+ full_payto: fullPayto as never,
+ high_risk: false,
+ rowid: 1 as never,
+ open_time: { t_s: "never" },
+ close_time: { t_s: "never" },
+ to_investigate: false,
+ };
+ const container = window.document.createElement("div");
+ window.document.body.append(container);
+ render(
+ <AccountIdentity
+ record={record}
+ routeToAccountById={({ cid }) => `#/account/${cid}`}
+ />,
+ container as unknown as Element,
+ );
+ assert.doesNotMatch(container.textContent, /Bank account/);
+ assert.match(container.textContent, /· IBAN/);
+ const accountLink = container.querySelector("a") as HTMLAnchorElement | null;
+ assert.ok(accountLink);
+ assert.equal(
+ accountLink.getAttribute("href"),
+ `#/account/${account}?payto=${encodeCrockForURI(fullPayto)}`,
+ );
+
+ const initialHistoryLength = window.history.length;
+ accountLink.click();
+ await new Promise((resolve) => setTimeout(resolve, 10));
+ assert.equal(window.history.length, initialHistoryLength + 1);
+ assert.match(window.location.hash, /^#\/account\//);
+
+ window.history.back();
+ await new Promise((resolve) => setTimeout(resolve, 10));
+ assert.equal(window.location.hash, "#/accounts");
+ assert.equal(window.location.search, "?investigation=yes");
+
+ render(null, container as unknown as Element);
+ container.remove();
+ await window.happyDOM.abort();
+});
+
+test("wallet directory entries separate classification from payto type", async () => {
+ const window = await installDom();
+ const reserveKey = "0".repeat(52);
+ const fullPayto = `payto://taler-reserve/exchange.example/${reserveKey}?receiver-name=Wallet%20customer`;
+ const record: CustomerAccountSummary = {
+ h_payto: "2222222222222222222222222222222222222222222222222222" as never,
+ full_payto: fullPayto as never,
+ high_risk: false,
+ rowid: 2 as never,
+ open_time: { t_s: "never" },
+ close_time: { t_s: "never" },
+ to_investigate: true,
+ };
+ const container = window.document.createElement("div");
+ render(
+ <div>
+ <section data-cell="account">
+ <AccountIdentity
+ record={record}
+ routeToAccountById={({ cid }) => `#/account/${cid}`}
+ />
+ </section>
+ <section data-cell="status">
+ <AccountStatuses record={record} />
+ </section>
+ </div>,
+ container as unknown as Element,
+ );
+ const accountCell = container.querySelector('[data-cell="account"]');
+ const statusCell = container.querySelector('[data-cell="status"]');
+ assert.ok(accountCell);
+ assert.ok(statusCell);
+ assert.match(accountCell.textContent ?? "", /· Taler reserve/);
+ assert.doesNotMatch(accountCell.textContent ?? "", /Wallet account/);
+ assert.match(statusCell.textContent ?? "", /Wallet account/);
+ assert.equal(
+ statusCell
+ .querySelector("[data-account-classification]")
+ ?.getAttribute("data-account-classification"),
+ "wallet",
+ );
+ render(null, container as unknown as Element);
+ await window.happyDOM.abort();
+});
+
+test("the customer label is primary and keeps a distinct receiver name", async () => {
+ const window = await installDom();
+ const record: CustomerAccountSummary = {
+ h_payto: "3333333333333333333333333333333333333333333333333333" as never,
+ full_payto:
+ "payto://iban/CH9300762011623852957?receiver-name=Example%20Trading%20AG" as never,
+ customer_label: "Example Trading Group",
+ high_risk: false,
+ rowid: 3 as never,
+ open_time: { t_s: "never" },
+ close_time: { t_s: "never" },
+ to_investigate: false,
+ };
+ const container = window.document.createElement("div");
+ render(
+ <AccountIdentity
+ record={record}
+ routeToAccountById={({ cid }) => `#/account/${cid}`}
+ />,
+ container as unknown as Element,
+ );
+ assert.match(container.textContent, /Example Trading Group/);
+ assert.match(container.textContent, /Example Trading AG/);
+ assert.equal(
+ container.querySelector("a")?.textContent,
+ "Example Trading Group",
+ );
+ render(null, container as unknown as Element);
+ await window.happyDOM.abort();
+});
diff --git a/packages/taler-exchange-aml-webui/src/pages/AccountList.tsx b/packages/taler-exchange-aml-webui/src/pages/AccountList.tsx
@@ -1,452 +1,684 @@
/*
This file is part of GNU Taler
- (C) 2022-2025 Taler Systems S.A.
+ (C) 2022-2026 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 {
- AbsoluteTime,
CustomerAccountSummary,
HttpStatusCode,
- OfficerSession,
- Paytos,
TalerError,
+ TranslatedString,
assertUnreachable,
} from "@gnu-taler/taler-util";
import {
- Attention,
AsyncButton,
+ Attention,
ErrorLoading,
- FailLoading,
- InputToggle,
Loading,
Pagination,
- RouteDefinition,
+ encodeCrockForURI,
useExchangeApiContext,
- useNotificationContext,
- useNotifiedOperation,
useTranslationContext,
} from "@gnu-taler/web-util/browser";
-import { Fragment, VNode, h } from "preact";
-import { useAmlAccounts } from "../hooks/decisions.js";
-
-import { format } from "date-fns";
+import { VNode, h } from "preact";
import { useEffect, useRef, useState } from "preact/hooks";
-import csvIcon from "../assets/csv-icon.png";
-import xlsIcon from "../assets/excel-icon.png";
+import { useLocation, useSearch } from "wouter-preact";
+import { PaytoTargetType } from "../components/PaytoTargetDetails.js";
+import {
+ AccountLifecycleDetails,
+ AccountSummaryBadges,
+ AccountSummaryNotes,
+ accountIdentity,
+} from "../components/AccountSummary.js";
+import { revalidateAmlAccounts, useAmlAccounts } from "../hooks/decisions.js";
import { useOfficer } from "../hooks/officer.js";
-import { Profile } from "./Profile.js";
-const utfDecoder = new TextDecoder("utf-8");
type Mime = "text/csv" | "application/vnd.ms-excel";
+type FilterValue = boolean | undefined;
+type FilterParameter = "investigation" | "high_risk" | "open";
export function AccountList({
- routeToAccountById: caseByIdRoute,
+ routeToAccountById,
}: {
- routeToAccountById: RouteDefinition<{ cid: string }>;
+ routeToAccountById: (params: { cid: string }) => string;
}): VNode {
const { i18n } = useTranslationContext();
- const [investigated, setInvestigated] = useState<boolean>();
- const [opened, setOpened] = useState<boolean>();
- const [highRisk, setHighRisk] = useState<boolean>();
- const list = useAmlAccounts({ investigated, open: opened, highRisk });
- const { showError } = useNotificationContext();
-
+ const [location, navigate] = useLocation();
+ const search = useSearch();
+ const filters = filtersFromSearch(search);
+ const list = useAmlAccounts({
+ investigated: filters.investigation,
+ highRisk: filters.highRisk,
+ open: filters.open,
+ });
const officer = useOfficer();
const session = officer.state === "ready" ? officer.session : undefined;
const { lib } = useExchangeApiContext();
- const [exported, setExported] = useState<{ content: string; file: string }>();
-
- const fileDescription =
- investigated === undefined
- ? opened
- ? highRisk
- ? `risky_opened`
- : `opened`
- : highRisk
- ? `risky`
- : ``
- : investigated
- ? opened
- ? highRisk
- ? `investigated_risky_opened`
- : `investigated_opened`
- : highRisk
- ? `investigated_risky`
- : `investigated`
- : opened
- ? highRisk
- ? `not-investigated_risky_opened`
- : `not-investigated_opened`
- : highRisk
- ? `not-investigated_risky`
- : `not-investigated`;
-
- const download = useNotifiedOperation<
- Awaited<ReturnType<typeof lib.exchange.getAmlAccountsAsOtherFormat>>,
- [
- OfficerSession,
- Mime,
- { investigation?: boolean; open?: boolean; highRisk?: boolean },
- ]
- >(
- (_ct, officerSession: OfficerSession, mime: Mime, filters) =>
- lib.exchange.getAmlAccountsAsOtherFormat(officerSession, mime, filters),
- {
- onFail: showError(i18n.str`Failed to download`, (fail) => {
- switch (fail.case) {
- case HttpStatusCode.NoContent:
- return i18n.str`There are no accounts in the resultset.`;
- case HttpStatusCode.NotAcceptable:
- return i18n.str`The format requested is not acceptable from the service provider.`;
- case HttpStatusCode.Forbidden:
- return i18n.str`Authorization denied for this session.`;
- case HttpStatusCode.NotFound:
- return i18n.str`Session not found. Contact the administrator.`;
- case HttpStatusCode.Conflict:
- return i18n.str`The session is disabled. Contact the administrator`;
- }
- }),
- onSuccess: (result, _officerSession, mime) => {
- const time = format(new Date(), "yyyyMMdd_HHmmss");
- switch (mime) {
- case "text/csv":
- return setExported({
- content: utfDecoder.decode(result),
- file: `accounts_${time}_${fileDescription}.csv`,
- });
- case "application/vnd.ms-excel":
- return setExported({
- content: utfDecoder.decode(result),
- file: `accounts_${time}_${fileDescription}.xls`,
- });
- default:
- assertUnreachable(mime);
- }
- },
- },
- );
+ const [exporting, setExporting] = useState<Mime>();
+ const [exportError, setExportError] = useState<TranslatedString>();
+ const exportMenuRef = useRef<HTMLDetailsElement>(null);
+
+ useEffect(() => {
+ function closeExportMenu(event: PointerEvent): void {
+ const menu = exportMenuRef.current;
+ if (
+ menu?.open &&
+ event.target instanceof Node &&
+ !menu.contains(event.target)
+ ) {
+ menu.open = false;
+ }
+ }
+ function closeExportMenuOnEscape(event: KeyboardEvent): void {
+ const menu = exportMenuRef.current;
+ if (event.key !== "Escape" || !menu?.open) return;
+ menu.open = false;
+ menu.querySelector<HTMLElement>("summary")?.focus();
+ }
+ document.addEventListener("pointerdown", closeExportMenu);
+ document.addEventListener("keydown", closeExportMenuOnEscape);
+ return () => {
+ document.removeEventListener("pointerdown", closeExportMenu);
+ document.removeEventListener("keydown", closeExportMenuOnEscape);
+ };
+ }, []);
+
+ function updateFilter(name: FilterParameter, value: FilterValue): void {
+ const params = new URLSearchParams(search);
+ if (value === undefined) params.delete(name);
+ else params.set(name, value ? "yes" : "no");
+ navigateToFilters(params);
+ }
- if (!list) {
- return <Loading />;
+ function clearFilters(): void {
+ navigateToFilters(new URLSearchParams());
}
+
+ function navigateToFilters(params: URLSearchParams): void {
+ const nextQuery = params.toString();
+ if (nextQuery) {
+ navigate(`${location}?${nextQuery}`);
+ return;
+ }
+ navigate(location);
+ // Wouter's hash-location hook leaves the browser search string unchanged
+ // when navigating without one. Clear it explicitly and notify useSearch().
+ const url = new URL(window.location.href);
+ if (!url.search) return;
+ url.search = "";
+ window.history.replaceState(null, "", url.href);
+ window.dispatchEvent(new PopStateEvent("popstate"));
+ }
+
+ async function exportAccounts(mime: Mime): Promise<void> {
+ if (!session) return;
+ if (exportMenuRef.current) exportMenuRef.current.open = false;
+ setExportError(undefined);
+ setExporting(mime);
+ try {
+ const result = await lib.exchange.getAmlAccountsAsOtherFormat(
+ session,
+ mime,
+ {
+ investigation: filters.investigation,
+ open: filters.open,
+ highRisk: filters.highRisk,
+ },
+ );
+ if (result.type !== "ok") {
+ setExportError(exportFailureMessage(result.case, i18n));
+ return;
+ }
+ const suffix = mime === "text/csv" ? "csv" : "xls";
+ const date = new Date().toISOString().replaceAll(/[:.]/g, "-");
+ const bytes = result.body;
+ const data = bytes.buffer.slice(
+ bytes.byteOffset,
+ bytes.byteOffset + bytes.byteLength,
+ ) as ArrayBuffer;
+ const blob = new Blob([data], { type: mime });
+ const objectUrl = URL.createObjectURL(blob);
+ const link = document.createElement("a");
+ link.href = objectUrl;
+ link.download = `aml-accounts-${date}.${suffix}`;
+ document.body.append(link);
+ link.click();
+ link.remove();
+ URL.revokeObjectURL(objectUrl);
+ } catch (error) {
+ console.error("Failed to export AML accounts", error);
+ setExportError(i18n.str`The export could not be prepared. Try again.`);
+ } finally {
+ setExporting(undefined);
+ }
+ }
+
+ if (!list) return <Loading />;
+
if (list instanceof TalerError) {
return (
- <ErrorLoading title={i18n.str`Failed to load accounts`} error={list} />
+ <div class="space-y-4">
+ <ErrorLoading title={i18n.str`Failed to load accounts`} error={list} />
+ <RetryButton />
+ </div>
);
}
if (list.type === "fail") {
return (
- <Fragment>
- <Profile />
- <FailLoading
- operation={list}
- title={i18n.str`Failed to load the accounts`}
- translate={(d) => {
- switch (d.case) {
- case HttpStatusCode.Forbidden:
- return (
- <i18n.Translate>
- This session signature is invalid, contact administrator or
- create a new one.
- </i18n.Translate>
- );
- case HttpStatusCode.NotFound:
- return (
- <i18n.Translate>
- The designated AML session is not known, contact
- administrator or create a new one.
- </i18n.Translate>
- );
- case HttpStatusCode.Conflict:
- return (
- <i18n.Translate>
- The designated AML session is not enabled, contact
- administrator or create a new one.
- </i18n.Translate>
- );
- default:
- assertUnreachable(d.case);
- }
- }}
- />
- </Fragment>
+ <AccountsFailure
+ title={i18n.str`Failed to load accounts`}
+ message={accountFailureMessage(list.case, i18n)}
+ technical={list}
+ />
);
}
const records = list.body;
-
- const description =
- investigated === undefined
- ? opened
- ? highRisk
- ? i18n.str`High risk accounts. Only with custom rules.`
- : i18n.str`Account with custom rules.`
- : highRisk
- ? i18n.str`High risk accounts`
- : i18n.str`All known accounts.`
- : investigated
- ? opened
- ? highRisk
- ? i18n.str`High risk accounts under investigation. Only with custom rules.`
- : i18n.str`Accounts under investigation. Only with custom rules.`
- : highRisk
- ? i18n.str`High risk accounts under investigation.`
- : i18n.str`Accounts under investigation.`
- : opened
- ? highRisk
- ? i18n.str`High risk accounts without investigation. Only with custom rules.`
- : i18n.str`Accounts without investigation. Only with custom rules.`
- : highRisk
- ? i18n.str`High risk accounts without investigation.`
- : i18n.str`Accounts without investigation.`;
+ const hasFilters = Object.values(filters).some(
+ (value) => value !== undefined,
+ );
return (
- <div>
- <div class="sm:flex sm:items-center">
- <div class="px-2 sm:flex-auto">
- <h1 class="text-base font-semibold leading-6 text-gray-900">
+ <section aria-labelledby="accounts-heading" class="space-y-6">
+ <header class="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
+ <div>
+ <h1
+ id="accounts-heading"
+ class="text-3xl font-bold tracking-tight text-gray-950 dark:text-gray-50"
+ >
<i18n.Translate>Accounts</i18n.Translate>
</h1>
- <p class="mt-2 text-sm text-gray-700 w-80">
- <i18n.Translate>{description}</i18n.Translate>
+ <p class="mt-2 max-w-2xl text-sm text-gray-600 dark:text-gray-300">
+ <i18n.Translate>
+ Review accounts known to the exchange for AML and KYC handling.
+ </i18n.Translate>
</p>
- {!records.length ? undefined : (
- <div class="flex space-x-2 mt-4">
- <i18n.Translate>Export as file</i18n.Translate>
- <AsyncButton
- disabled={download.running}
- onClick={
- !session
- ? undefined
- : () =>
- download.run(session, "text/csv", {
- investigation: investigated,
- open: opened,
- highRisk,
- })
- }
- >
- <img class="size-6 w-6" src={csvIcon} />
- </AsyncButton>
- <AsyncButton
- disabled={download.running}
- onClick={
- !session
- ? undefined
- : () =>
- download.run(session, "application/vnd.ms-excel", {
- investigation: investigated,
- open: opened,
- highRisk,
- })
- }
- >
- <img class="size-6 w-6" src={xlsIcon} />
- </AsyncButton>
- </div>
- )}
-
- {!exported ? (
- <div class="h-5 mb-5" />
- ) : (
- <a
- href={
- "data:text/plain;charset=utf-8," +
- encodeURIComponent(exported.content)
- }
- name="save file"
- download={exported.file}
+ </div>
+ <details ref={exportMenuRef} class="relative lg:text-right">
+ <summary class="inline-flex min-h-11 cursor-pointer list-none items-center justify-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-semibold text-gray-900 shadow-sm hover:bg-gray-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100 dark:hover:bg-gray-800">
+ <i18n.Translate>Export filtered accounts</i18n.Translate>
+ </summary>
+ <div class="z-10 mt-2 flex w-full min-w-52 flex-col gap-1 rounded-md border border-gray-200 bg-white p-2 shadow-lg lg:absolute lg:right-0 dark:border-gray-700 dark:bg-gray-900">
+ <AsyncButton
+ class="min-h-11 rounded-md px-3 py-2 text-left text-sm font-medium text-gray-900 hover:bg-gray-100 disabled:text-gray-500 dark:text-gray-100 dark:hover:bg-gray-800 dark:disabled:text-gray-400"
+ disabled={!!exporting || !session}
+ onClick={() => exportAccounts("text/csv")}
>
- <Attention
- title={i18n.str`Export completed`}
- onClose={() => setExported(undefined)}
- >
- <i18n.Translate>
- Click here to save the file in your computer.
- </i18n.Translate>
- </Attention>
- </a>
- )}
+ <i18n.Translate>Download CSV</i18n.Translate>
+ </AsyncButton>
+ <AsyncButton
+ class="min-h-11 rounded-md px-3 py-2 text-left text-sm font-medium text-gray-900 hover:bg-gray-100 disabled:text-gray-500 dark:text-gray-100 dark:hover:bg-gray-800 dark:disabled:text-gray-400"
+ disabled={!!exporting || !session}
+ onClick={() => exportAccounts("application/vnd.ms-excel")}
+ >
+ <i18n.Translate>Download Excel</i18n.Translate>
+ </AsyncButton>
+ </div>
+ </details>
+ </header>
+
+ {exporting ? (
+ <p role="status" class="text-sm text-gray-600 dark:text-gray-300">
+ <i18n.Translate>Preparing export…</i18n.Translate>
+ </p>
+ ) : undefined}
+ {exportError ? (
+ <Attention type="danger" title={i18n.str`Export failed`}>
+ {exportError}
+ </Attention>
+ ) : undefined}
+
+ <div
+ aria-label={i18n.str`Account filters`}
+ class="rounded-lg border border-gray-200 bg-gray-50 p-4 dark:border-gray-700 dark:bg-gray-900/60"
+ >
+ <div class="flex flex-col gap-4 lg:flex-row lg:items-end">
+ <FilterSelect
+ id="account-filter-investigation"
+ label={i18n.str`Investigation`}
+ value={filters.investigation}
+ allLabel={i18n.str`All accounts`}
+ yesLabel={i18n.str`Under investigation`}
+ noLabel={i18n.str`Not under investigation`}
+ onChange={(value) => updateFilter("investigation", value)}
+ />
+ <FilterSelect
+ id="account-filter-risk"
+ label={i18n.str`Risk`}
+ value={filters.highRisk}
+ allLabel={i18n.str`All risk levels`}
+ yesLabel={i18n.str`High risk`}
+ noLabel={i18n.str`Not high risk`}
+ onChange={(value) => updateFilter("high_risk", value)}
+ />
+ <FilterSelect
+ id="account-filter-file-status"
+ label={i18n.str`File status`}
+ value={filters.open}
+ allLabel={i18n.str`All file statuses`}
+ yesLabel={i18n.str`Open`}
+ noLabel={i18n.str`Not open`}
+ onChange={(value) => updateFilter("open", value)}
+ />
+ <button
+ type="button"
+ disabled={!hasFilters}
+ onClick={clearFilters}
+ class="min-h-11 rounded-md px-3 py-2 text-sm font-semibold text-primary hover:bg-primary/10 disabled:cursor-not-allowed disabled:text-gray-500 dark:text-darkPrimary dark:hover:bg-darkPrimary/10 dark:disabled:text-gray-500"
+ >
+ <i18n.Translate>Clear filters</i18n.Translate>
+ </button>
</div>
+ </div>
- <JumpByIdForm
- caseByIdRoute={caseByIdRoute}
- filters={{ investigated, highRisk, opened }}
- onTog={(f, v) => {
- switch (f) {
- case "investigated": {
- setInvestigated(v);
- break;
- }
- case "highRisk": {
- setHighRisk(v);
- break;
- }
- case "open": {
- setOpened(v);
- break;
- }
- default: {
- assertUnreachable(f);
- }
- }
- }}
+ {!records.length ? (
+ <EmptyAccounts filtered={hasFilters} onClear={clearFilters} />
+ ) : (
+ <div class="space-y-3">
+ <p class="text-sm text-gray-600 dark:text-gray-300">
+ <i18n.Translate>
+ Showing {records.length} accounts · newest first
+ </i18n.Translate>
+ </p>
+ <div class="hidden overflow-hidden rounded-lg border border-gray-200 md:block dark:border-gray-700">
+ <table class="min-w-full table-fixed divide-y divide-gray-200 dark:divide-gray-700">
+ <caption class="sr-only">
+ <i18n.Translate>AML and KYC accounts</i18n.Translate>
+ </caption>
+ <thead class="bg-gray-50 dark:bg-gray-900">
+ <tr>
+ <ColumnHeader class="w-[34%]">
+ <i18n.Translate>Account</i18n.Translate>
+ </ColumnHeader>
+ <ColumnHeader class="w-[22%]">
+ <i18n.Translate>Account lifecycle</i18n.Translate>
+ </ColumnHeader>
+ <ColumnHeader class="w-[20%]">
+ <i18n.Translate>Status</i18n.Translate>
+ </ColumnHeader>
+ <ColumnHeader class="w-[24%]">
+ <i18n.Translate>Latest note</i18n.Translate>
+ </ColumnHeader>
+ </tr>
+ </thead>
+ <tbody class="divide-y divide-gray-200 bg-white dark:divide-gray-700 dark:bg-gray-950">
+ {records.map((record) => (
+ <AccountTableRow
+ key={record.h_payto}
+ record={record}
+ routeToAccountById={routeToAccountById}
+ />
+ ))}
+ </tbody>
+ </table>
+ </div>
+ <div class="space-y-3 md:hidden">
+ {records.map((record) => (
+ <AccountCard
+ key={record.h_payto}
+ record={record}
+ routeToAccountById={routeToAccountById}
+ />
+ ))}
+ </div>
+ <Pagination
+ currentPage={list.currentPage}
+ onFirstPage={list.loadFirst}
+ onPrevious={list.loadPrev}
+ onNext={list.loadNext}
+ />
+ </div>
+ )}
+ </section>
+ );
+}
+
+export function filtersFromSearch(search: string): {
+ investigation?: boolean;
+ highRisk?: boolean;
+ open?: boolean;
+} {
+ const params = new URLSearchParams(search);
+ return {
+ investigation: parseFilter(params.get("investigation")),
+ highRisk: parseFilter(params.get("high_risk")),
+ open: parseFilter(params.get("open")),
+ };
+}
+
+function parseFilter(value: string | null): FilterValue {
+ if (value === "yes") return true;
+ if (value === "no") return false;
+ return undefined;
+}
+
+function FilterSelect({
+ id,
+ label,
+ value,
+ allLabel,
+ yesLabel,
+ noLabel,
+ onChange,
+}: {
+ id: string;
+ label: TranslatedString;
+ value: FilterValue;
+ allLabel: TranslatedString;
+ yesLabel: TranslatedString;
+ noLabel: TranslatedString;
+ onChange: (value: FilterValue) => void;
+}): VNode {
+ return (
+ <label
+ for={id}
+ class="flex min-w-52 flex-1 flex-col gap-1 text-sm font-semibold text-gray-800 dark:text-gray-200"
+ >
+ {label}
+ <select
+ id={id}
+ aria-label={label}
+ value={value === undefined ? "all" : value ? "yes" : "no"}
+ onChange={(event) => onChange(parseFilter(event.currentTarget.value))}
+ class="min-h-11 rounded-md border-gray-300 bg-white text-sm font-normal text-gray-950 shadow-sm focus:border-primary focus:ring-primary dark:border-gray-600 dark:bg-gray-950 dark:text-gray-100"
+ >
+ <option value="all">{allLabel}</option>
+ <option value="yes">{yesLabel}</option>
+ <option value="no">{noLabel}</option>
+ </select>
+ </label>
+ );
+}
+
+function ColumnHeader({
+ children,
+ class: className,
+}: {
+ children: VNode;
+ class?: string;
+}): VNode {
+ return (
+ <th
+ scope="col"
+ class={`px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-gray-700 dark:text-gray-300 ${className ?? ""}`}
+ >
+ {children}
+ </th>
+ );
+}
+
+function AccountTableRow({
+ record,
+ routeToAccountById,
+}: {
+ record: CustomerAccountSummary;
+ routeToAccountById: (params: { cid: string }) => string;
+}): VNode {
+ return (
+ <tr class="align-top hover:bg-gray-50 dark:hover:bg-gray-900/70">
+ <td class="px-4 py-4">
+ <AccountIdentity
+ record={record}
+ routeToAccountById={routeToAccountById}
/>
+ </td>
+ <td class="px-4 py-4 text-sm text-gray-700 dark:text-gray-300">
+ <AccountLifecycleDetails record={record} />
+ </td>
+ <td class="px-4 py-4">
+ <AccountStatuses record={record} />
+ </td>
+ <td class="px-4 py-4 text-sm text-gray-700 dark:text-gray-300">
+ <AccountSummaryNotes record={record} showEmpty />
+ </td>
+ </tr>
+ );
+}
+
+function AccountCard({
+ record,
+ routeToAccountById,
+}: {
+ record: CustomerAccountSummary;
+ routeToAccountById: (params: { cid: string }) => string;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ return (
+ <article class="space-y-4 rounded-lg border border-gray-200 bg-white p-4 shadow-sm dark:border-gray-700 dark:bg-gray-950">
+ <AccountIdentity
+ record={record}
+ routeToAccountById={routeToAccountById}
+ />
+ <div>
+ <h2 class="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
+ <i18n.Translate>Account lifecycle</i18n.Translate>
+ </h2>
+ <div class="mt-1 text-sm text-gray-700 dark:text-gray-300">
+ <AccountLifecycleDetails record={record} />
+ </div>
</div>
- <div class="mt-8 flow-root">
- <div class="overflow-x-auto">
- {!records.length ? (
- <div>
- <i18n.Translate>No results</i18n.Translate>{" "}
- </div>
- ) : (
- <div class="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
- <table class="min-w-full divide-y divide-gray-300">
- <thead>
- <tr>
- <th
- scope="col"
- class="px-3 py-3.5 text-right text-sm font-semibold text-gray-900"
- >
- <i18n.Translate>#</i18n.Translate>
- </th>
- <th
- scope="col"
- class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 w-80"
- >
- <i18n.Translate>Account Identification</i18n.Translate>
- </th>
- <th
- scope="col"
- class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 "
- >
- <i18n.Translate>Open time</i18n.Translate>
- </th>
- <th
- scope="col"
- class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 "
- >
- <i18n.Translate>Status</i18n.Translate>
- </th>
- </tr>
- </thead>
- <tbody class="divide-y divide-gray-200 bg-white">
- {records.map((r, i) => {
- const uri = Paytos.asString(r.full_payto);
- const openTime =
- r.open_time.t_s !== "never"
- ? format(r.open_time.t_s * 1000, "yyyy/MM/dd HH:mm")
- : undefined;
- const closeTime =
- r.close_time.t_s !== "never"
- ? format(r.close_time.t_s * 1000, "yyyy/MM/dd HH:mm")
- : undefined;
- const openDescription = openTime ? (
- closeTime ? (
- <span>
- <i18n.Translate>
- From {openTime}
- <br />
- To {closeTime}
- </i18n.Translate>
- </span>
- ) : (
- i18n.str`Since ${openTime}`
- )
- ) : (
- i18n.str`Not opened`
- );
-
- const paramsDesc = Object.entries(uri.params).map(
- ([name, value]) => {
- return (
- <div key={name}>
- {name}: {value}
- </div>
- );
- },
- );
- return (
- <Fragment key={r.h_payto}>
- <tr class="hover:bg-gray-100 ">
- <td class="whitespace-nowrap px-3 py-5 text-sm text-gray-500 text-right">
- {r.rowid}
- </td>
- <td class="whitespace-nowrap px-3 py-5 text-sm text-gray-500 ">
- <div class="text-gray-900">
- <a
- href={caseByIdRoute.url({
- cid: r.h_payto,
- })}
- class="text-indigo-600 hover:text-indigo-900 font-mono"
- >
- {uri.displayName}
- </a>
- <p class="text-gray-500 text-xs">{paramsDesc}</p>
- </div>
- </td>
- <td class="whitespace-nowrap px-3 text-sm text-gray-900">
- {openDescription}
- </td>
- <td class="whitespace-nowrap px-3 py-5 text-sm text-gray-900 flex">
- {r.to_investigate ? (
- <span title={i18n.str`Under investigation`}>
- <ToInvestigateIcon
- stroke="#be2206ff"
- stroke-width="2"
- />
- </span>
- ) : undefined}
- {r.high_risk ? (
- <span title={i18n.str`High risk`}>
- <HighRiskIcon
- stroke="#b2be06ff"
- stroke-width="2"
- />
- </span>
- ) : undefined}
- {r.open_time.t_s !== "never" ? (
- <span title={i18n.str`With custom rules`}>
- <OpenIcon stroke="#1806beff" stroke-width="2" />
- </span>
- ) : undefined}
- </td>
- </tr>
- {r.comments ? (
- <tr>
- <td
- class="whitespace-nowrap px-3 py-1 text-sm text-gray-500 "
- colSpan={3}
- >
- {r.comments}
- </td>
- </tr>
- ) : undefined}
- </Fragment>
- );
- })}
- </tbody>
- </table>
- <Pagination onFirstPage={list.loadFirst} onNext={list.loadNext} />
- </div>
- )}
+ <AccountStatuses record={record} />
+ <div>
+ <h2 class="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
+ <i18n.Translate>Latest note</i18n.Translate>
+ </h2>
+ <div class="mt-1 text-sm text-gray-700 dark:text-gray-300">
+ <AccountSummaryNotes record={record} showEmpty />
</div>
</div>
+ </article>
+ );
+}
+
+export function AccountIdentity({
+ record,
+ routeToAccountById,
+}: {
+ record: CustomerAccountSummary;
+ routeToAccountById: (params: { cid: string }) => string;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ const identity = accountIdentity(record);
+ const accountRoute = routeToAccountById({ cid: record.h_payto });
+ const accountHref = `${accountRoute}?payto=${encodeCrockForURI(record.full_payto)}`;
+ return (
+ <div class="min-w-0 space-y-1">
+ <div class="flex min-w-0 flex-wrap items-center gap-x-1.5 gap-y-1">
+ <a
+ href={accountHref}
+ class="break-words font-semibold text-primary underline-offset-2 hover:underline focus-visible:rounded-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary dark:text-darkPrimary"
+ >
+ {identity.primary}
+ </a>
+ <PaytoTargetType paytoUri={record.full_payto} />
+ </div>
+ {identity.secondary ? (
+ <p class="break-all text-sm text-gray-600 dark:text-gray-300">
+ {identity.secondary}
+ </p>
+ ) : undefined}
+ <p class="text-xs text-gray-500 dark:text-gray-400">
+ <i18n.Translate>File no. {record.rowid}</i18n.Translate>
+ </p>
+ <details class="pt-1 text-xs text-gray-600 dark:text-gray-300">
+ <summary class="min-h-8 cursor-pointer py-1 font-semibold text-primary hover:underline dark:text-darkPrimary">
+ <i18n.Translate>Technical identifiers</i18n.Translate>
+ </summary>
+ <dl class="mt-2 space-y-2 rounded-md bg-gray-50 p-3 dark:bg-gray-900">
+ <Identifier
+ label={i18n.str`Full payto URI`}
+ value={record.full_payto}
+ />
+ <Identifier
+ label={i18n.str`Normalized payto hash`}
+ value={record.h_payto}
+ />
+ </dl>
+ </details>
+ </div>
+ );
+}
+
+function Identifier({
+ label,
+ value,
+}: {
+ label: TranslatedString;
+ value: string;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ const [copied, setCopied] = useState(false);
+ return (
+ <div>
+ <dt class="font-semibold text-gray-700 dark:text-gray-200">{label}</dt>
+ <dd class="mt-1 flex min-w-0 items-start gap-2">
+ <code class="min-w-0 flex-1 break-all text-gray-600 dark:text-gray-300">
+ {value}
+ </code>
+ <button
+ type="button"
+ class="min-h-8 shrink-0 rounded px-2 font-semibold text-primary hover:bg-primary/10 dark:text-darkPrimary"
+ onClick={async () => {
+ await navigator.clipboard.writeText(value);
+ setCopied(true);
+ }}
+ >
+ {copied ? i18n.str`Copied` : i18n.str`Copy`}
+ </button>
+ </dd>
+ </div>
+ );
+}
+
+export function AccountStatuses({
+ record,
+}: {
+ record: CustomerAccountSummary;
+}): VNode {
+ return <AccountSummaryBadges record={record} />;
+}
+
+function EmptyAccounts({
+ filtered,
+ onClear,
+}: {
+ filtered: boolean;
+ onClear: () => void;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ return (
+ <div class="rounded-lg border border-dashed border-gray-300 px-6 py-12 text-center dark:border-gray-700">
+ <h2 class="text-base font-semibold text-gray-900 dark:text-gray-100">
+ {filtered ? i18n.str`No matching accounts` : i18n.str`No accounts yet`}
+ </h2>
+ <p class="mx-auto mt-2 max-w-lg text-sm text-gray-600 dark:text-gray-300">
+ {filtered
+ ? i18n.str`No accounts match the selected filters.`
+ : i18n.str`The exchange has not recorded any AML or KYC accounts yet.`}
+ </p>
+ {filtered ? (
+ <button
+ type="button"
+ onClick={onClear}
+ class="mt-4 min-h-11 rounded-md bg-primary px-4 py-2 text-sm font-semibold text-white hover:bg-primary/90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary dark:bg-darkPrimary dark:text-gray-950"
+ >
+ <i18n.Translate>Clear filters</i18n.Translate>
+ </button>
+ ) : undefined}
+ </div>
+ );
+}
+
+function AccountsFailure({
+ title,
+ message,
+ technical,
+}: {
+ title: TranslatedString;
+ message: TranslatedString;
+ technical: unknown;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ return (
+ <div class="space-y-4">
+ <Attention type="danger" title={title}>
+ <p>{message}</p>
+ <details class="mt-3">
+ <summary class="min-h-11 cursor-pointer py-2 font-semibold underline">
+ <i18n.Translate>Technical details</i18n.Translate>
+ </summary>
+ <pre class="max-h-72 overflow-auto whitespace-pre-wrap break-words rounded-md bg-white/70 p-3 text-xs text-black">
+ {JSON.stringify(technical, null, 2)}
+ </pre>
+ </details>
+ </Attention>
+ <RetryButton />
</div>
);
}
+function RetryButton(): VNode {
+ const { i18n } = useTranslationContext();
+ return (
+ <AsyncButton
+ class="min-h-11 rounded-md bg-primary px-4 py-2 text-sm font-semibold text-white hover:bg-primary/90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary dark:bg-darkPrimary dark:text-gray-950"
+ onClick={async () => {
+ await revalidateAmlAccounts();
+ }}
+ >
+ <i18n.Translate>Retry</i18n.Translate>
+ </AsyncButton>
+ );
+}
+
+function accountFailureMessage(
+ status:
+ | HttpStatusCode.Forbidden
+ | HttpStatusCode.NotFound
+ | HttpStatusCode.Conflict,
+ i18n: ReturnType<typeof useTranslationContext>["i18n"],
+): TranslatedString {
+ switch (status) {
+ case HttpStatusCode.Forbidden:
+ return i18n.str`This officer session is not authorized to list accounts.`;
+ case HttpStatusCode.NotFound:
+ return i18n.str`The exchange does not recognize this officer session.`;
+ case HttpStatusCode.Conflict:
+ return i18n.str`This officer session is currently disabled.`;
+ default:
+ return assertUnreachable(status);
+ }
+}
+
+function exportFailureMessage(
+ status:
+ | HttpStatusCode.NoContent
+ | HttpStatusCode.NotAcceptable
+ | HttpStatusCode.Forbidden
+ | HttpStatusCode.NotFound
+ | HttpStatusCode.Conflict,
+ i18n: ReturnType<typeof useTranslationContext>["i18n"],
+): TranslatedString {
+ switch (status) {
+ case HttpStatusCode.NoContent:
+ return i18n.str`There are no matching accounts to export.`;
+ case HttpStatusCode.NotAcceptable:
+ return i18n.str`The exchange does not support the selected export format.`;
+ case HttpStatusCode.Forbidden:
+ return i18n.str`This officer session is not authorized to export accounts.`;
+ case HttpStatusCode.NotFound:
+ return i18n.str`The exchange does not recognize this officer session.`;
+ case HttpStatusCode.Conflict:
+ return i18n.str`This officer session is currently disabled.`;
+ default:
+ return assertUnreachable(status);
+ }
+}
+
export const ToInvestigateIcon = (
props?: h.JSX.SVGAttributes<SVGSVGElement>,
) => (
@@ -466,40 +698,6 @@ export const ToInvestigateIcon = (
/>
</svg>
);
-export const HighRiskIcon = (props?: h.JSX.SVGAttributes<SVGSVGElement>) => (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- fill="none"
- viewBox="0 0 24 24"
- stroke-width="1.5"
- stroke="currentColor"
- class="size-6 w-6"
- {...props}
- >
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z"
- />
- </svg>
-);
-export const OpenIcon = (props?: h.JSX.SVGAttributes<SVGSVGElement>) => (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- fill="none"
- viewBox="0 0 24 24"
- stroke-width="1.5"
- stroke="currentColor"
- class="size-6"
- {...props}
- >
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- d="M3.75 9.776c.112-.017.227-.026.344-.026h15.812c.117 0 .232.009.344.026m-16.5 0a2.25 2.25 0 0 0-1.883 2.542l.857 6a2.25 2.25 0 0 0 2.227 1.932H19.05a2.25 2.25 0 0 0 2.227-1.932l.857-6a2.25 2.25 0 0 0-1.883-2.542m-16.5 0V6A2.25 2.25 0 0 1 6 3.75h3.879a1.5 1.5 0 0 1 1.06.44l2.122 2.12a1.5 1.5 0 0 0 1.06.44H18A2.25 2.25 0 0 1 20.25 9v.776"
- />
- </svg>
-);
export const TransfersIcon = (props?: h.JSX.SVGAttributes<SVGSVGElement>) => (
<svg
@@ -526,7 +724,7 @@ export const PeopleIcon = (props?: h.JSX.SVGAttributes<SVGSVGElement>) => (
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
- class="w-6 h-6"
+ class="size-6"
{...props}
>
<path
@@ -536,221 +734,3 @@ export const PeopleIcon = (props?: h.JSX.SVGAttributes<SVGSVGElement>) => (
/>
</svg>
);
-
-export const HomeIcon = (props?: h.JSX.SVGAttributes<SVGSVGElement>) => (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- fill="none"
- viewBox="0 0 24 24"
- stroke-width="1.5"
- stroke="currentColor"
- class="w-6 h-6"
- {...props}
- >
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- d="M2.25 12l8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25"
- />
- </svg>
-);
-export const FormIcon = (props?: h.JSX.SVGAttributes<SVGSVGElement>) => (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 24 24"
- fill="currentColor"
- class="w-6 h-6"
- {...props}
- >
- <path
- fillRule="evenodd"
- d="M1.5 5.625c0-1.036.84-1.875 1.875-1.875h17.25c1.035 0 1.875.84 1.875 1.875v12.75c0 1.035-.84 1.875-1.875 1.875H3.375A1.875 1.875 0 0 1 1.5 18.375V5.625ZM21 9.375A.375.375 0 0 0 20.625 9h-7.5a.375.375 0 0 0-.375.375v1.5c0 .207.168.375.375.375h7.5a.375.375 0 0 0 .375-.375v-1.5Zm0 3.75a.375.375 0 0 0-.375-.375h-7.5a.375.375 0 0 0-.375.375v1.5c0 .207.168.375.375.375h7.5a.375.375 0 0 0 .375-.375v-1.5Zm0 3.75a.375.375 0 0 0-.375-.375h-7.5a.375.375 0 0 0-.375.375v1.5c0 .207.168.375.375.375h7.5a.375.375 0 0 0 .375-.375v-1.5ZM10.875 18.75a.375.375 0 0 0 .375-.375v-1.5a.375.375 0 0 0-.375-.375h-7.5a.375.375 0 0 0-.375.375v1.5c0 .207.168.375.375.375h7.5ZM3.375 15h7.5a.375.375 0 0 0 .375-.375v-1.5a.375.375 0 0 0-.375-.375h-7.5a.375.375 0 0 0-.375.375v1.5c0 .207.168.375.375.375Zm0-3.75h7.5a.375.375 0 0 0 .375-.375v-1.5A.375.375 0 0 0 10.875 9h-7.5A.375.375 0 0 0 3 9.375v1.5c0 .207.168.375.375.375Z"
- clipRule="evenodd"
- />
- </svg>
-);
-
-export const SearchIcon = (props?: h.JSX.SVGAttributes<SVGSVGElement>) => (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- fill="none"
- viewBox="0 0 24 24"
- stroke-width="1.5"
- stroke="currentColor"
- class="w-6 h-6"
- {...props}
- >
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z"
- />
- </svg>
-);
-
-type FilterName = "investigated" | "highRisk" | "open";
-function JumpByIdForm({
- caseByIdRoute,
- filters = {},
- onTog,
-}: {
- caseByIdRoute: RouteDefinition<{ cid: string }>;
- filters: {
- investigated?: boolean;
- highRisk?: boolean;
- opened?: boolean;
- };
- onTog: (name: FilterName, d: boolean | undefined) => void;
-}): VNode {
- const { i18n } = useTranslationContext();
- const [account, setAccount] = useState<string>("");
- const officer = useOfficer();
- const session = officer.state === "ready" ? officer.session : undefined;
- const { lib } = useExchangeApiContext();
- const [valid, setValid] = useState(false);
- const [error, setError] = useState<string>();
- const requestSequence = useRef(0);
- useEffect(() => {
- const sequence = ++requestSequence.current;
- if (!session || !account) {
- setError(undefined);
- setValid(false);
- return;
- }
- const activeSession = session;
- setError(undefined);
- setValid(false);
- const timeout = setTimeout(async function checkAccount() {
- let found = false;
- try {
- const result = await lib.exchange.getAmlAttributesForAccount(
- activeSession,
- account,
- { limit: 1 },
- );
- found = result.type === "ok";
- } catch (e) {
- console.log(e);
- }
- if (requestSequence.current !== sequence) return;
- setValid(found);
- if (!found) {
- setError(i18n.str`Invalid account`);
- }
- }, 500);
- return () => clearTimeout(timeout);
- }, [account, session]);
- return (
- <form class="mt-5 grid grid-cols-1">
- <div>
- <div class="flex flex-row">
- <div class="w-full sm:max-w-xs">
- <input
- name="account"
- onChange={(e) => {
- setAccount(e.currentTarget.value);
- }}
- class="block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6"
- placeholder={i18n.str`Search by ID`}
- />
- </div>
- <a
- href={!valid ? undefined : caseByIdRoute.url({ cid: account })}
- data-disabled={!valid}
- class="data-[disabled=true]:bg-gray-400 mt-3 inline-flex w-full items-center justify-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 sm:ml-3 sm:mt-0 sm:w-auto"
- >
- <svg
- xmlns="http://www.w3.org/2000/svg"
- fill="none"
- viewBox="0 0 24 24"
- stroke-width="1.5"
- stroke="currentColor"
- class="size-6 w-6 h-6"
- >
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- d="M13.5 4.5 21 12m0 0-7.5 7.5M21 12H3"
- />
- </svg>
- </a>
- </div>
- {!error ? undefined : <p class="mt-2 text-sm text-red-600">{error}</p>}
- </div>
- <div class="mt-2 cursor-default space-y-2">
- <InputToggle
- threeState
- name="inv"
- label={i18n.str`Under investigation: `}
- handler={{
- name: "inv",
- onChange: (x) => onTog("investigated", x),
- value: filters.investigated,
- }}
- />
- <InputToggle
- name="risk"
- label={i18n.str`High risk:`}
- handler={{
- name: "risk",
- onChange: (x) => onTog("highRisk", x),
- value: filters.highRisk,
- }}
- />
- <InputToggle
- name="open"
- label={i18n.str`Custom rules:`}
- handler={{
- name: "open",
- onChange: (x) => onTog("open", x),
- value: filters.opened,
- }}
- />
- </div>
- </form>
- );
-}
-
-// "File number,Customer,Comments,Risky,Acquisition date,Exit date\r\n"
-const fields: FieldSet<CustomerAccountSummary> = [
- {
- name: "File number",
- type: "Number",
- convert: (v) => String(v.rowid),
- },
- {
- name: "Customer",
- type: "String",
- convert: (v) => v.full_payto,
- },
- {
- name: "Comments",
- type: "String",
- convert: (v) => v.comments ?? "",
- },
- {
- name: "Increased risk business relationship",
- type: "Boolean",
- convert: (v) => (v.high_risk ? "1" : "0"),
- },
- {
- name: "Acquisition date",
- type: "DateTime",
- convert: (v) => {
- const t = AbsoluteTime.fromProtocolTimestamp(v.open_time);
- if (AbsoluteTime.isNever(t)) return "-";
- return AbsoluteTime.stringify(t);
- },
- },
- {
- name: "Exit date",
- type: "DateTime",
- convert: (v) => {
- const t = AbsoluteTime.fromProtocolTimestamp(v.close_time);
- if (AbsoluteTime.isNever(t)) return "-";
- return AbsoluteTime.stringify(t);
- },
- },
-];
-type FieldSet<T> = Field<T>[];
-type Field<T> = { name: string; type: string; convert: (o: T) => string };
diff --git a/packages/taler-exchange-aml-webui/src/pages/Dashboard.stories.tsx b/packages/taler-exchange-aml-webui/src/pages/Dashboard.stories.tsx
@@ -0,0 +1,101 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import {
+ HttpStatusCode,
+ TalerError,
+ opFixedSuccess,
+ opKnownFailure,
+} from "@gnu-taler/taler-util";
+import { dummyHttpResponse } from "@gnu-taler/taler-util/http";
+import * as tests from "@gnu-taler/web-util/testing";
+import { h, VNode } from "preact";
+import { Router } from "wouter-preact";
+import { memoryLocation } from "wouter-preact/memory-location";
+import { ExchangeAmlFrame } from "../ExchangeAmlFrame.js";
+import { Navigation } from "../Routing.js";
+import { Dashboard } from "./Dashboard.js";
+
+export default { title: "dashboard statistics" };
+
+const successExchange = {
+ getAmlKycStatistics: async (_officer: unknown, events: string[]) =>
+ opFixedSuccess(dummyHttpResponse, {
+ statistics: [
+ {
+ event: events[0],
+ counter: events[0].startsWith("DECR_") ? 3 : 12,
+ },
+ ],
+ }),
+};
+
+const { hook: dashboardLocationHook } = memoryLocation({
+ path: "/dashboard",
+ static: true,
+});
+
+function LoggedInLayout(): VNode {
+ return (
+ <Router hook={dashboardLocationHook}>
+ <ExchangeAmlFrame NavigationBar={Navigation}>
+ <Dashboard />
+ </ExchangeAmlFrame>
+ </Router>
+ );
+}
+
+export const Complete = tests.createExample(
+ Dashboard,
+ {},
+ { exchange: successExchange },
+);
+
+export const LoggedInShell = tests.createExample(
+ LoggedInLayout,
+ {},
+ { exchange: successExchange },
+);
+
+export const Partial = tests.createExample(
+ Dashboard,
+ {},
+ {
+ exchange: {
+ getAmlKycStatistics: async (_officer: unknown, events: string[]) =>
+ events[0] === "INCR_HIGH_RISK_CUSTOMER"
+ ? opKnownFailure(dummyHttpResponse, HttpStatusCode.NotFound)
+ : successExchange.getAmlKycStatistics(_officer, events),
+ },
+ },
+);
+
+export const Loading = tests.createExample(
+ Dashboard,
+ {},
+ {
+ exchange: {
+ getAmlKycStatistics: async () => new Promise<never>(() => undefined),
+ },
+ },
+);
+
+export const Failed = tests.createExample(
+ Dashboard,
+ {},
+ {
+ exchange: {
+ getAmlKycStatistics: async () => {
+ throw TalerError.fromException(
+ new Error("The exchange statistics endpoint is unavailable."),
+ );
+ },
+ },
+ },
+);
diff --git a/packages/taler-exchange-aml-webui/src/pages/Dashboard.test.tsx b/packages/taler-exchange-aml-webui/src/pages/Dashboard.test.tsx
@@ -0,0 +1,57 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import { setupI18n } from "@gnu-taler/taler-util";
+import assert from "node:assert/strict";
+import test from "node:test";
+import { h, render } from "preact";
+import { Router } from "wouter-preact";
+import { memoryLocation } from "wouter-preact/memory-location";
+import { DashboardShortcuts } from "./Dashboard.js";
+
+setupI18n("en", {});
+
+test("the case queue shortcut opens accounts under investigation", async () => {
+ const happyDomPackage = "happy-dom";
+ const { Window } = await import(happyDomPackage);
+ const window = new Window({ url: "https://aml.example/" });
+ for (const [key, value] of Object.entries({
+ window,
+ document: window.document,
+ Node: window.Node,
+ Element: window.Element,
+ HTMLElement: window.HTMLElement,
+ HTMLAnchorElement: window.HTMLAnchorElement,
+ })) {
+ Object.defineProperty(globalThis, key, {
+ configurable: true,
+ writable: true,
+ value,
+ });
+ }
+ const { hook } = memoryLocation({ path: "/dashboard", static: true });
+ const container = window.document.createElement("div");
+ render(
+ <Router hook={hook}>
+ <DashboardShortcuts />
+ </Router>,
+ container as unknown as Element,
+ );
+ const queueLink = (
+ Array.from(container.querySelectorAll("a")) as HTMLAnchorElement[]
+ ).find((link) => link.textContent?.includes("Review case queue"));
+ assert.ok(queueLink);
+ assert.equal(queueLink.getAttribute("href"), "/accounts?investigation=yes");
+ assert.match(
+ queueLink.textContent ?? "",
+ /Review accounts currently under investigation/,
+ );
+ render(null, container as unknown as Element);
+ await window.happyDOM.abort();
+});
diff --git a/packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx b/packages/taler-exchange-aml-webui/src/pages/Dashboard.tsx
@@ -21,6 +21,7 @@ import {
TranslatedString,
} from "@gnu-taler/taler-util";
import {
+ AsyncButton,
ErrorLoading,
InternationalizationAPI,
Loading,
@@ -29,9 +30,13 @@ import {
} from "@gnu-taler/web-util/browser";
import { Fragment, h, VNode } from "preact";
import { HandleSessionNotReady } from "../components/HandleAccountNotReady.js";
+import { Link } from "wouter-preact";
import { useOfficer } from "../hooks/officer.js";
-import { usePreferences } from "../hooks/preferences.js";
-import { useTopsServerStatistics } from "../hooks/server-info.js";
+import { useAmlSpaDialect } from "../hooks/preferences.js";
+import {
+ revalidateTopsServerStatistics,
+ useTopsServerStatistics,
+} from "../hooks/server-info.js";
export function Dashboard() {
const officer = useOfficer();
@@ -43,14 +48,63 @@ export function Dashboard() {
return (
<div>
- <h1 class="my-2 text-3xl font-bold tracking-tight text-gray-900 ">
+ <h1 class="my-2 text-3xl font-bold tracking-tight text-gray-900 dark:text-gray-50">
<i18n.Translate>Dashboard</i18n.Translate>
</h1>
+ <p class="text-sm text-gray-600 dark:text-gray-300">
+ <i18n.Translate>
+ Review cases requiring attention, investigate accounts, and monitor
+ AML reporting indicators.
+ </i18n.Translate>
+ </p>
+ <DashboardShortcuts />
<EventMetrics />
</div>
);
}
+export function DashboardShortcuts(): VNode {
+ const { i18n } = useTranslationContext();
+ return (
+ <div class="mt-6 grid gap-4 sm:grid-cols-2">
+ <Link
+ href="/accounts?investigation=yes"
+ class="group flex items-center gap-4 rounded-lg border border-outlineVariant bg-surface p-5 text-onSurface transition-colors hover:border-primary hover:bg-primaryContainer/30 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100 dark:hover:bg-darkPrimaryContainer/30"
+ >
+ <ShortcutIcon type="cases" />
+ <div class="min-w-0 flex-1">
+ <h2 class="font-semibold">
+ <i18n.Translate>Review case queue</i18n.Translate>
+ </h2>
+ <p class="mt-1 text-sm text-gray-700 dark:text-gray-300">
+ <i18n.Translate>
+ Review accounts currently under investigation.
+ </i18n.Translate>
+ </p>
+ </div>
+ <ChevronRight />
+ </Link>
+ <Link
+ href="/transfers"
+ class="group flex items-center gap-4 rounded-lg border border-outlineVariant bg-surface p-5 text-onSurface transition-colors hover:border-primary hover:bg-primaryContainer/30 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100 dark:hover:bg-darkPrimaryContainer/30"
+ >
+ <ShortcutIcon type="transfers" />
+ <div class="min-w-0 flex-1">
+ <h2 class="font-semibold">
+ <i18n.Translate>Inspect transfers</i18n.Translate>
+ </h2>
+ <p class="mt-1 text-sm text-gray-700 dark:text-gray-300">
+ <i18n.Translate>
+ Find credit, debit, and KYC authorization activity.
+ </i18n.Translate>
+ </p>
+ </div>
+ <ChevronRight />
+ </Link>
+ </div>
+ );
+}
+
function EventMetrics(): VNode {
const { i18n } = useTranslationContext();
// const [metricType, setMetricType] =
@@ -62,14 +116,34 @@ function EventMetrics(): VNode {
// [metricType],
// );
- const [pref] = usePreferences();
const { config } = useExchangeApiContext();
+ const dialect = useAmlSpaDialect(config.config.aml_spa_dialect);
- const dialect =
- (pref.testingDialect ? undefined : config.config.aml_spa_dialect) ??
- AmlSpaDialect.TESTING;
+ const resp = useTopsServerStatistics(dialect === AmlSpaDialect.TOPS);
- const resp = useTopsServerStatistics();
+ if (dialect === AmlSpaDialect.TESTING) {
+ return (
+ <section class="mt-6">
+ <h2 class="text-base font-semibold text-gray-900 dark:text-gray-100">
+ <i18n.Translate>Statistics</i18n.Translate>
+ </h2>
+ <div class="mt-3 rounded-lg border border-dashed border-gray-300 bg-gray-50 p-4 dark:border-gray-700 dark:bg-gray-900/60">
+ <p class="font-semibold text-gray-900 dark:text-gray-100">
+ <i18n.Translate>
+ No reporting profile for this dialect
+ </i18n.Translate>
+ </p>
+ <p class="mt-1 text-sm text-gray-600 dark:text-gray-300">
+ <i18n.Translate>
+ The testing dialect does not define dashboard statistics. Select
+ TOPS in development settings to inspect the TOPS reporting
+ profile.
+ </i18n.Translate>
+ </p>
+ </div>
+ </section>
+ );
+ }
if (!resp) {
return <Loading />;
@@ -84,12 +158,12 @@ function EventMetrics(): VNode {
}
return (
- <div class="px-4 mt-4">
- <div class="sm:flex sm:items-center mb-4">
+ <div class="mt-6">
+ <div class="mb-3 sm:flex sm:items-center">
<div class="sm:flex-auto">
- <h1 class="text-base font-semibold leading-6 text-gray-900">
+ <h2 class="text-base font-semibold leading-6 text-gray-900 dark:text-gray-100">
<i18n.Translate>Statistics</i18n.Translate>
- </h1>
+ </h2>
</div>
</div>
@@ -109,16 +183,45 @@ function EventMetrics(): VNode {
</h1>
</div> */}
- <dl class="mt-5 grid grid-cols-1 md:grid-cols-4 divide-y divide-gray-200 overflow-hidden rounded-lg bg-white shadow-lg md:divide-x md:divide-y-0">
- {Object.entries(resp.body).map(([name, number], k) => {
+ {resp.body.failures.length ? (
+ <div
+ role="alert"
+ class="mb-4 rounded-lg border border-amber-300 bg-amber-50 p-4 text-amber-950"
+ >
+ <p class="font-semibold">
+ <i18n.Translate>Some statistics are unavailable.</i18n.Translate>
+ </p>
+ <p class="mt-1 text-sm">
+ <i18n.Translate>
+ The available values are shown below. Missing values are not zero.
+ </i18n.Translate>
+ </p>
+ <AsyncButton
+ onClick={async () => {
+ await revalidateTopsServerStatistics();
+ }}
+ class="mt-3 rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white"
+ >
+ <i18n.Translate>Retry</i18n.Translate>
+ </AsyncButton>
+ </div>
+ ) : undefined}
+
+ <dl class="grid grid-cols-1 gap-px overflow-hidden rounded-lg border border-outlineVariant bg-gray-200 shadow-sm sm:grid-cols-2 xl:grid-cols-4 dark:border-gray-700 dark:bg-gray-700">
+ {Object.entries(resp.body.values).map(([name, number], k) => {
const label = labelForEvent(name, i18n, dialect);
const desc = descriptionForEvent(name, i18n, dialect);
return (
- <div class="px-4 py-5 sm:p-6" key={k}>
- <dt class="text-base font-normal text-gray-900">
+ <div
+ class="grid grid-cols-[minmax(0,1fr)_auto] items-start gap-4 bg-white px-4 py-4 sm:block sm:p-5 xl:p-6 dark:bg-gray-900"
+ key={k}
+ >
+ <dt class="text-base font-normal text-gray-900 dark:text-gray-100">
{label}
{!desc ? undefined : (
- <div class="text-xs text-gray-500">{desc}</div>
+ <div class="text-xs text-gray-500 dark:text-gray-400">
+ {desc}
+ </div>
)}
</dt>
<MetricValueNumber current={number} previous={undefined} />
@@ -280,9 +383,15 @@ function MetricValueNumber({
const rateStr = `${(Math.abs(rate) * 100).toFixed(2)}%`;
return (
<Fragment>
- <dd class="mt-1 block ">
- <div class="flex justify-start text-2xl items-baseline font-semibold text-indigo-600">
- {!current ? 0 : current}
+ <dd class="block text-right sm:mt-1 sm:text-left">
+ <div class="flex items-baseline justify-end text-2xl font-semibold text-primary sm:justify-start">
+ {current === undefined || Number.isNaN(current) ? (
+ <span class="text-base text-gray-600">
+ <i18n.Translate>Unavailable</i18n.Translate>
+ </span>
+ ) : (
+ current
+ )}
</div>
<div class="flex flex-col">
<div class="flex justify-end items-baseline text-2xl font-semibold text-indigo-600">
@@ -346,3 +455,49 @@ function MetricValueNumber({
</Fragment>
);
}
+
+function ShortcutIcon({ type }: { type: "cases" | "transfers" }): VNode {
+ return (
+ <span class="grid size-10 shrink-0 place-items-center rounded-full bg-primaryContainer text-onPrimaryContainer dark:bg-darkPrimaryContainer dark:text-darkOnPrimaryContainer">
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ viewBox="0 0 24 24"
+ stroke-width="1.5"
+ stroke="currentColor"
+ class="h-5 w-5"
+ aria-hidden="true"
+ >
+ {type === "cases" ? (
+ <path
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ d="M9 6.75h6M9 10.5h6M9 14.25h3.75M6.75 3.75h10.5A2.25 2.25 0 0 1 19.5 6v12a2.25 2.25 0 0 1-2.25 2.25H6.75A2.25 2.25 0 0 1 4.5 18V6a2.25 2.25 0 0 1 2.25-2.25Z"
+ />
+ ) : (
+ <path
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ d="m15.75 5.25 3 3m0 0-3 3m3-3H5.25m3 4.5-3 3m0 0 3 3m-3-3h13.5"
+ />
+ )}
+ </svg>
+ </span>
+ );
+}
+
+function ChevronRight(): VNode {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ fill="none"
+ viewBox="0 0 24 24"
+ stroke-width="1.5"
+ stroke="currentColor"
+ class="h-5 w-5 shrink-0 text-gray-400 transition-transform group-hover:translate-x-0.5 group-hover:text-primary"
+ aria-hidden="true"
+ >
+ <path stroke-linecap="round" stroke-linejoin="round" d="m9 18 6-6-6-6" />
+ </svg>
+ );
+}
diff --git a/packages/taler-exchange-aml-webui/src/pages/DecisionWizard.stories.tsx b/packages/taler-exchange-aml-webui/src/pages/DecisionWizard.stories.tsx
@@ -0,0 +1,288 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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 {
+ AbsoluteTime,
+ AmlDecision,
+ AmountString,
+ AvailableMeasureSummary,
+ LimitOperationType,
+ TalerAmlProperties,
+ TalerFormAttributes,
+ TOPS_AmlEventsName,
+ opFixedSuccess,
+} from "@gnu-taler/taler-util";
+import { dummyHttpResponse } from "@gnu-taler/taler-util/http";
+import * as tests from "@gnu-taler/web-util/testing";
+import { h, VNode } from "preact";
+import {
+ DecisionRequest,
+ DecisionRequestProvider,
+} from "../hooks/decision-request.js";
+import { OfficerReady } from "../hooks/officer.js";
+import {
+ effectiveRuleLimits,
+ initialRuleDraft,
+} from "../utils/rule-defaults.js";
+import { DecisionWizard, WizardSteps } from "./DecisionWizard.js";
+
+export default { title: "decision wizard" };
+
+const account = "1111111111111111111111111111111111111111111111111111";
+const fullPayto =
+ "payto://iban/CH9300762011623852957?receiver-name=Example%20Trading%20AG";
+const now = Math.floor(Date.now() / 1000);
+const timestamp = (seconds: number) => ({ t_s: seconds }) as const;
+const rule = {
+ operation_type: LimitOperationType.deposit,
+ threshold: "ARS:25000" as AmountString,
+ timeframe: { d_us: 30 * 24 * 60 * 60 * 1_000_000 },
+ measures: ["review-documents"],
+ display_priority: 20,
+ exposed: true,
+ is_and_combinator: false,
+};
+
+const currentDecision: AmlDecision = {
+ h_payto: account as never,
+ full_payto: fullPayto,
+ is_wallet: false,
+ rowid: 43 as never,
+ justification: "Enhanced monitoring is required.",
+ decision_time: timestamp(now - 3_600),
+ properties: {
+ [TalerAmlProperties.CUSTOMER_LABEL]: "Example Trading AG",
+ [TalerAmlProperties.FILE_NOTE]: "Verify the source of funds.",
+ [TalerAmlProperties.HIGH_RISK_CUSTOMER]: true,
+ },
+ limits: {
+ expiration_time: timestamp(now + 30 * 24 * 60 * 60),
+ rules: [rule],
+ custom_measures: {},
+ },
+ to_investigate: true,
+ is_active: true,
+};
+
+const measureSummary: AvailableMeasureSummary = {
+ roots: {
+ "review-documents": {
+ check_name: "identity-form",
+ prog_name: "review-documents",
+ context: { requested_document: "proof-of-address" },
+ },
+ "preserve-investigate": {
+ check_name: "SKIP",
+ prog_name: "preserve-investigate",
+ },
+ },
+ checks: {
+ "identity-form": {
+ description: "Collect proof of address",
+ requires: ["requested_document"],
+ outputs: ["full_name", "address"],
+ fallback: "manual-review",
+ },
+ },
+ programs: {
+ "review-documents": {
+ description: "Review submitted documents",
+ context: [],
+ inputs: ["full_name", "address"],
+ },
+ "preserve-investigate": {
+ description: "Keep the account under investigation",
+ context: [],
+ inputs: [],
+ },
+ },
+ default_rules: [rule],
+};
+
+const completeDecision: DecisionRequest = {
+ original: currentDecision,
+ attributes: {
+ formId: "vqf_902_1_officer",
+ formVersion: 1,
+ formSalt: "STORY_SALT",
+ expiration: AbsoluteTime.never(),
+ data: {
+ [TalerFormAttributes.FORM_ID]: "vqf_902_1_officer",
+ },
+ },
+ properties: {
+ ...currentDecision.properties,
+ [TalerAmlProperties.ACCOUNT_OPEN]: true,
+ },
+ property_overrides: [],
+ triggering_events: [TOPS_AmlEventsName.INCR_ACCOUNT_OPEN],
+ custom_events: [],
+ events_overridden: false,
+ custom_measures: {},
+ new_measures: ["review-documents"],
+ measures_and: false,
+ rules: [rule],
+ deadline: AbsoluteTime.fromMilliseconds((now + 30 * 24 * 60 * 60) * 1000),
+ rules_reviewed: true,
+ justification: "The source-of-funds documentation requires enhanced review.",
+ keep_investigating: true,
+};
+
+const officer: OfficerReady = {
+ state: "ready",
+ session: {
+ id: "4TQZQ0M6CB0JZXJ3Z1B4H7X3EVAQXX45SB9QT0NXZYKAHQXZ3EYG" as never,
+ __signingKey: new Uint8Array(32) as never,
+ },
+ expiration: AbsoluteTime.never(),
+ lock: () => opFixedSuccess(dummyHttpResponse, undefined),
+ forget: () => opFixedSuccess(dummyHttpResponse, undefined),
+};
+
+function Story({
+ step,
+ initial = completeDecision,
+ formId,
+}: {
+ step: WizardSteps;
+ initial?: DecisionRequest;
+ formId?: string;
+}): VNode {
+ return (
+ <DecisionRequestProvider initial={initial}>
+ <DecisionWizard
+ account={account}
+ fullPayto={fullPayto}
+ newAccount={false}
+ step={step}
+ formId={formId}
+ officer={officer}
+ onMove={() => undefined}
+ />
+ </DecisionRequestProvider>
+ );
+}
+
+const exchange = {
+ getAmlDecisions: async () =>
+ opFixedSuccess(dummyHttpResponse, { records: [currentDecision] }),
+ getAmlMeasures: async () => opFixedSuccess(dummyHttpResponse, measureSummary),
+};
+
+export const CustomerInformation = tests.createExample(
+ Story,
+ { step: "attributes" },
+ { exchange },
+);
+export const CustomerInformationFormSelector = tests.createExample(
+ Story,
+ {
+ step: "attributes",
+ initial: { ...completeDecision, attributes: undefined },
+ },
+ { exchange },
+);
+export const NewlySelectedCustomerInformationForm = tests.createExample(
+ Story,
+ {
+ step: "attributes",
+ initial: { ...completeDecision, attributes: undefined },
+ formId: "vqf_902_1_officer",
+ },
+ { exchange },
+);
+export const AccountProperties = tests.createExample(
+ Story,
+ { step: "properties" },
+ { exchange },
+);
+export const ReportingEvents = tests.createExample(
+ Story,
+ { step: "events" },
+ { exchange },
+);
+export const ReportingEventsWithOverrides = tests.createExample(
+ Story,
+ {
+ step: "events",
+ initial: {
+ ...completeDecision,
+ triggering_events: [TOPS_AmlEventsName.INCR_HIGH_RISK_COUNTRY],
+ custom_events: ["MANUAL_REVIEW_COMPLETED"],
+ events_overridden: true,
+ },
+ },
+ { exchange },
+);
+export const ImmediateMeasures = tests.createExample(
+ Story,
+ { step: "measures" },
+ { exchange },
+);
+export const TransactionRules = tests.createExample(
+ Story,
+ { step: "rules" },
+ { exchange },
+);
+export const CaseDisposition = tests.createExample(
+ Story,
+ { step: "justification" },
+ { exchange },
+);
+export const CaseDispositionNotUnderInvestigation = tests.createExample(
+ Story,
+ {
+ step: "justification",
+ initial: {
+ ...completeDecision,
+ original: { ...currentDecision, to_investigate: false },
+ keep_investigating: undefined,
+ },
+ },
+ { exchange },
+);
+export const ReviewAndSubmit = tests.createExample(
+ Story,
+ { step: "summary" },
+ { exchange },
+);
+export const IncompleteReview = tests.createExample(
+ Story,
+ {
+ step: "summary",
+ initial: {
+ ...completeDecision,
+ ...initialRuleDraft(currentDecision.limits),
+ },
+ },
+ { exchange },
+);
+export const DefaultRulesAwaitingReview = tests.createExample(
+ Story,
+ {
+ step: "summary",
+ newAccount: true,
+ initial: {
+ ...completeDecision,
+ original: undefined,
+ accountName: "Example Trading AG",
+ ...initialRuleDraft(
+ effectiveRuleLimits(undefined, measureSummary, false),
+ ),
+ },
+ },
+ { exchange },
+);
diff --git a/packages/taler-exchange-aml-webui/src/pages/DecisionWizard.test.ts b/packages/taler-exchange-aml-webui/src/pages/DecisionWizard.test.ts
@@ -0,0 +1,25 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import { AbsoluteTime } from "@gnu-taler/taler-util";
+import assert from "node:assert/strict";
+import test from "node:test";
+import { DecisionRequest } from "../hooks/decision-request.js";
+import { isRulesCompleted } from "./DecisionWizard.js";
+
+test("valid defaulted rules still require explicit review", () => {
+ const request: DecisionRequest = {
+ rules: [],
+ deadline: AbsoluteTime.never(),
+ rules_reviewed: false,
+ };
+
+ assert.equal(isRulesCompleted(request), false);
+ assert.equal(isRulesCompleted({ ...request, rules_reviewed: true }), true);
+});
diff --git a/packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx b/packages/taler-exchange-aml-webui/src/pages/DecisionWizard.tsx
@@ -13,23 +13,16 @@
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 {
- assertUnreachable,
- Paytos,
- PaytoType,
- Result,
- TalerError,
- TranslatedString,
-} from "@gnu-taler/taler-util";
-import { CopyButton, useTranslationContext } from "@gnu-taler/web-util/browser";
+import { assertUnreachable, TranslatedString } from "@gnu-taler/taler-util";
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { h, VNode } from "preact";
import {
DecisionRequest,
useCurrentDecisionRequest,
} from "../hooks/decision-request.js";
-import { useAccountActiveDecision } from "../hooks/decisions.js";
import { OfficerReady } from "../hooks/officer.js";
import { attributesAreComplete } from "../utils/decision-validation.js";
+import { deadlineIsValid, rulesAreValid } from "../utils/rule-validation.js";
import { Events } from "./decision/Events.js";
import { Attributes } from "./decision/Information.js";
import { Justification } from "./decision/Justification.js";
@@ -51,10 +44,10 @@ export type WizardSteps =
const STEPS_ORDER: WizardSteps[] = [
"attributes",
- "rules",
"properties",
"events",
"measures",
+ "rules",
"justification",
"summary",
];
@@ -63,7 +56,7 @@ const STEPS_ORDER_MAP = STEPS_ORDER.reduce(
(map, cur, idx, steps) => {
map[cur] = {
prev: idx === 0 ? undefined : steps[idx - 1],
- next: idx === steps.length ? undefined : steps[idx + 1],
+ next: idx === steps.length - 1 ? undefined : steps[idx + 1],
};
return map;
},
@@ -76,7 +69,12 @@ const STEPS_ORDER_MAP = STEPS_ORDER.reduce(
);
export function isRulesCompleted(request: DecisionRequest): boolean {
- return request.rules !== undefined && request.deadline !== undefined;
+ return (
+ request.rules_reviewed === true &&
+ request.rules !== undefined &&
+ rulesAreValid(request.rules) &&
+ deadlineIsValid(request.deadline)
+ );
}
export function isAttributesCompleted(request: DecisionRequest): boolean {
return attributesAreComplete(request);
@@ -107,14 +105,16 @@ export function isJustificationCompletedForNewACcount(
export function DecisionWizard({
account,
- newPayto,
+ fullPayto,
+ newAccount,
step,
formId,
onMove,
officer,
}: {
account: string;
- newPayto?: string;
+ fullPayto: string;
+ newAccount: boolean;
formId: string | undefined;
step?: WizardSteps;
officer: OfficerReady;
@@ -122,10 +122,12 @@ export function DecisionWizard({
}): VNode {
const { i18n } = useTranslationContext();
const stepOrDefault = step ?? STEPS_ORDER[0];
+ const stepInfo = getStepInfo(i18n, newAccount)[stepOrDefault];
+ const stepNumber = STEPS_ORDER.indexOf(stepOrDefault) + 1;
const content = (function () {
switch (stepOrDefault) {
case "rules":
- return <Rules newPayto={newPayto} />;
+ return <Rules fullPayto={fullPayto} />;
case "properties":
return <Properties />;
case "events":
@@ -133,7 +135,7 @@ export function DecisionWizard({
case "measures":
return <Measures />;
case "justification":
- return <Justification newPayto={newPayto} />;
+ return <Justification newAccount={newAccount} />;
case "attributes":
return <Attributes formId={formId} />;
case "summary":
@@ -141,7 +143,8 @@ export function DecisionWizard({
<Summary
account={account}
onMove={onMove}
- newPayto={newPayto}
+ fullPayto={fullPayto}
+ newAccount={newAccount}
officer={officer}
/>
);
@@ -150,103 +153,128 @@ export function DecisionWizard({
})();
return (
- <div class="min-w-60">
- <header class="flex items-center justify-between border-b border-white/5 px-4 py-4 sm:px-6 sm:py-6 lg:px-8">
- <Header account={account} newPayto={newPayto} />
- <div>{account}</div>
- <CopyButton class="" getContent={() => account} />
- </header>
-
+ <div class="space-y-6">
<WizardSteps
step={stepOrDefault}
onMove={onMove}
- newAccount={!!newPayto}
+ newAccount={newAccount}
/>
- <button
- disabled={!STEPS_ORDER_MAP[stepOrDefault].prev}
- onClick={() => {
- onMove(STEPS_ORDER_MAP[stepOrDefault].prev);
- }}
- class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm disabled:bg-gray-500 bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
+ <section
+ class="overflow-visible rounded-lg border border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-950"
+ aria-labelledby="decision-step-heading"
>
- <i18n.Translate>Prev</i18n.Translate>
- </button>
- <button
- disabled={!STEPS_ORDER_MAP[stepOrDefault].next}
- onClick={() => {
- onMove(STEPS_ORDER_MAP[stepOrDefault].next);
- }}
- class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm disabled:bg-gray-500 bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
+ <header class="rounded-t-lg border-b border-gray-200 bg-gray-50 px-4 py-4 dark:border-gray-700 dark:bg-gray-900 sm:px-6">
+ <p class="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
+ <i18n.Translate>
+ Step {stepNumber} of {STEPS_ORDER.length}
+ </i18n.Translate>
+ </p>
+ <h2
+ id="decision-step-heading"
+ class="mt-1 text-xl font-bold text-gray-950 dark:text-gray-50"
+ >
+ {stepInfo.label}
+ </h2>
+ <p class="mt-1 text-sm text-gray-600 dark:text-gray-300">
+ {stepInfo.description}
+ </p>
+ </header>
+ <div class="p-4 sm:p-6">{content}</div>
+ </section>
+ <nav
+ class="flex justify-between border-t border-gray-200 pt-4 dark:border-gray-700"
+ aria-label={i18n.str`Decision steps`}
>
- <i18n.Translate>Next</i18n.Translate>
- </button>
- {content}
+ <button
+ disabled={!STEPS_ORDER_MAP[stepOrDefault].prev}
+ onClick={() => {
+ onMove(STEPS_ORDER_MAP[stepOrDefault].prev);
+ }}
+ class="min-h-10 rounded-md border border-outline px-4 py-2 text-sm font-semibold hover:bg-surfaceContainer disabled:cursor-not-allowed disabled:border-gray-300 disabled:text-gray-500 disabled:hover:bg-transparent"
+ >
+ <i18n.Translate>Previous step</i18n.Translate>
+ </button>
+ <button
+ disabled={!STEPS_ORDER_MAP[stepOrDefault].next}
+ onClick={() => {
+ onMove(STEPS_ORDER_MAP[stepOrDefault].next);
+ }}
+ class="min-h-10 rounded-md bg-primary px-4 py-2 text-sm font-semibold text-onPrimary hover:bg-primary/90 disabled:cursor-not-allowed disabled:bg-gray-200 disabled:text-gray-700 disabled:hover:bg-gray-200 dark:bg-darkPrimary dark:text-darkOnPrimary"
+ >
+ <i18n.Translate>Next step</i18n.Translate>
+ </button>
+ </nav>
</div>
);
}
-function WizardSteps({
- step: currentStep,
- onMove,
- newAccount,
-}: {
- step: WizardSteps;
- onMove: (n: WizardSteps | undefined) => void;
- newAccount: boolean;
-}): VNode {
- const [request] = useCurrentDecisionRequest();
- const { i18n } = useTranslationContext();
- const STEP_INFO: {
- [s in WizardSteps]: {
- label: TranslatedString;
- description: TranslatedString;
- isCompleted: (r: DecisionRequest) => boolean;
- };
- } = {
+
+type StepInfo = {
+ label: TranslatedString;
+ description: TranslatedString;
+ isCompleted: (r: DecisionRequest) => boolean;
+};
+
+function getStepInfo(
+ i18n: ReturnType<typeof useTranslationContext>["i18n"],
+ newAccount: boolean,
+): Record<WizardSteps, StepInfo> {
+ return {
attributes: {
- label: i18n.str`Attributes`,
- description: i18n.str`Add more information about the customer`,
+ label: i18n.str`Customer information`,
+ description: i18n.str`Optionally add reviewed AML/KYC information to this decision.`,
isCompleted: isAttributesCompleted,
},
- rules: {
- label: i18n.str`Rules`,
- description: i18n.str`Set the limit of the operations`,
- isCompleted: isRulesCompleted,
+ properties: {
+ label: i18n.str`Account properties`,
+ description: i18n.str`Review the account state derived from the available information.`,
+ isCompleted: isPropertiesCompleted,
},
events: {
- label: i18n.str`Events`,
- description: i18n.str`Trigger notifications.`,
+ label: i18n.str`Reporting events`,
+ description: i18n.str`Review the statistical events recorded with this decision.`,
isCompleted: isEventsCompleted,
},
measures: {
- label: i18n.str`Measures`,
- description: i18n.str`Ask the customer to take action.`,
+ label: i18n.str`Immediate measures`,
+ description: i18n.str`Choose actions the customer must complete after the decision is submitted.`,
isCompleted: isMeasuresCompleted,
},
+ rules: {
+ label: i18n.str`Transaction rules`,
+ description: i18n.str`Set operation thresholds, escalation measures, and expiration behavior.`,
+ isCompleted: isRulesCompleted,
+ },
justification: {
- label: i18n.str`Justification`,
- description: i18n.str`Describe the decision.`,
+ label: i18n.str`Case disposition`,
+ description: i18n.str`Record the rationale and whether the case remains under investigation.`,
isCompleted: newAccount
? isJustificationCompletedForNewACcount
: isJustificationCompleted,
},
- properties: {
- label: i18n.str`Properties`,
- description: i18n.str`Flag the current account state.`,
- isCompleted: isPropertiesCompleted,
- },
summary: {
- label: i18n.str`Summary`,
- description: i18n.str`Review and submit.`,
+ label: i18n.str`Review and submit`,
+ description: i18n.str`Check the complete decision before signing and submitting it.`,
isCompleted: () => false,
},
};
+}
+
+function WizardSteps({
+ step: currentStep,
+ onMove,
+ newAccount,
+}: {
+ step: WizardSteps;
+ onMove: (n: WizardSteps | undefined) => void;
+ newAccount: boolean;
+}): VNode {
+ const [request] = useCurrentDecisionRequest();
+ const { i18n } = useTranslationContext();
+ const STEP_INFO = getStepInfo(i18n, newAccount);
return (
- <div class="lg:border-b lg:border-t lg:border-gray-200">
- <nav class="mx-auto max-w-7xl " aria-label="Progress">
- <ol
- role="list"
- class="overflow-hidden rounded-md lg:flex lg:rounded-none lg:border-l lg:border-r lg:border-gray-200"
- >
+ <div class="overflow-x-auto lg:overflow-visible">
+ <nav aria-label={i18n.str`Decision progress`}>
+ <ol class="flex min-w-max gap-2 pb-2 lg:grid lg:min-w-0 lg:grid-cols-7">
{STEPS_ORDER.map((stepLabel, k) => {
const info = STEP_INFO[stepLabel];
const st = info.isCompleted(request)
@@ -255,100 +283,39 @@ function WizardSteps({
? "current"
: "incomplete";
- const pos = !STEPS_ORDER_MAP[stepLabel].prev
- ? "first"
- : !STEPS_ORDER_MAP[stepLabel].next
- ? "last"
- : "middle";
-
return (
- <li class="relative lg:flex-1" key={k}>
- <div
- data-pos={pos}
- class="overflow-hidden data-[pos=first]:rounded-t-md border data-[pos=first]:border-b-0 border-gray-200 lg:border-0"
+ <li key={stepLabel}>
+ <button
+ type="button"
+ aria-current={currentStep === stepLabel ? "step" : undefined}
+ aria-label={`${info.label}: ${info.description}`}
+ data-current={currentStep === stepLabel}
+ onClick={() => onMove(stepLabel)}
+ class="flex min-h-11 items-center gap-2 rounded-md border border-gray-300 bg-white px-3 py-2 text-sm font-semibold text-gray-700 hover:border-primary hover:text-primary data-[current=true]:border-primary data-[current=true]:bg-primaryContainer data-[current=true]:text-onPrimaryContainer focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary dark:border-gray-700 dark:bg-gray-950 dark:text-gray-200 dark:data-[current=true]:border-darkPrimary dark:data-[current=true]:bg-darkPrimaryContainer dark:data-[current=true]:text-darkOnPrimaryContainer lg:h-full lg:w-full lg:justify-center lg:px-2 lg:text-center"
>
- {currentStep === stepLabel ? (
- <span
- class="absolute left-0 top-0 h-full w-1 bg-indigo-600 lg:bottom-0 lg:top-auto lg:h-1 lg:w-full"
- aria-hidden="true"
- ></span>
- ) : undefined}
- <button
- aria-current="step"
- class="group"
- onClick={() => {
- onMove(stepLabel);
- }}
+ <span
+ data-status={st}
+ class="flex size-6 shrink-0 items-center justify-center rounded-full border border-gray-400 text-xs data-[status=completed]:border-primary data-[status=completed]:bg-primary data-[status=completed]:text-onPrimary data-[status=current]:border-primary dark:data-[status=completed]:border-darkPrimary dark:data-[status=completed]:bg-darkPrimary dark:data-[status=completed]:text-darkOnPrimary dark:data-[status=current]:border-darkPrimary"
+ aria-hidden="true"
>
- <span
- data-status={st}
- class="absolute left-0 top-0 h-full w-1 data-[status=current]:bg-indigo-600 data-[status=current]:bg-transparent group-hover:bg-gray-200 lg:bottom-0 lg:top-auto lg:h-1 lg:w-full"
- aria-hidden="true"
- ></span>
- <div>
- <span class="flex items-start px-4 pt-4 text-sm font-medium">
- <span class="shrink-0">
- <span
- data-status={st}
- class="flex size-6 items-center justify-center rounded-full data-[status=completed]:bg-indigo-600 border-2 data-[status=current]:border-indigo-600 data-[status=incomplete]:border-gray-300"
- >
- <svg
- class="size-4 text-white "
- viewBox="0 0 24 24"
- fill="currentColor"
- aria-hidden="true"
- data-slot="icon"
- >
- <path
- fill-rule="evenodd"
- d="M19.916 4.626a.75.75 0 0 1 .208 1.04l-9 13.5a.75.75 0 0 1-1.154.114l-6-6a.75.75 0 0 1 1.06-1.06l5.353 5.353 8.493-12.74a.75.75 0 0 1 1.04-.207Z"
- clip-rule="evenodd"
- />
- </svg>
- </span>
- </span>
- <span
- data-status={st}
- class="ml-4 data-[status=current]:text-indigo-600"
- >
- {info.label}
- </span>
- </span>
- </div>
- <div class="p-2 text-start">
- <span class="ml-4 mt-0.5 flex min-w-0 flex-col">
- <span
- data-current={currentStep === stepLabel}
- class="text-sm font-medium data-[current=true]:text-indigo-600"
- ></span>
- <span class="text-sm font-medium text-gray-500">
- {info.description}
- </span>
- </span>
- </div>
- </button>
- {pos === "first" ? undefined : (
- <div
- data-pos={pos}
- class="absolute inset-0 left-0 top-0 hidden w-2 lg:block"
- aria-hidden="true"
- >
+ {st === "completed" ? (
<svg
- data-pos={pos}
- class="size-full text-gray-300 data-[pos=middle]:h-full data-[pos=middle]:w-full"
- viewBox="0 0 12 82"
- fill="none"
- preserveAspectRatio="none"
+ class="size-4"
+ viewBox="0 0 24 24"
+ fill="currentColor"
>
<path
- d="M0.5 0V31L10.5 41L0.5 51V82"
- stroke="currentcolor"
- vector-effect="non-scaling-stroke"
+ fill-rule="evenodd"
+ d="M19.916 4.626a.75.75 0 0 1 .208 1.04l-9 13.5a.75.75 0 0 1-1.154.114l-6-6a.75.75 0 0 1 1.06-1.06l5.353 5.353 8.493-12.74a.75.75 0 0 1 1.04-.207Z"
+ clip-rule="evenodd"
/>
</svg>
- </div>
- )}
- </div>
+ ) : (
+ k + 1
+ )}
+ </span>
+ <span>{info.label}</span>
+ </button>
</li>
);
})}
@@ -357,65 +324,3 @@ function WizardSteps({
</div>
);
}
-
-function Header({
- newPayto,
- account,
-}: {
- account: string;
- newPayto: string | undefined;
-}): VNode {
- const { i18n } = useTranslationContext();
- const isNewAccount = !!newPayto;
-
- let newPaytoParsed: Paytos.URI | undefined;
- const isNewAccountAWallet =
- newPayto === undefined
- ? undefined
- : (newPaytoParsed = Result.orUndefined(Paytos.fromString(newPayto))) ===
- undefined
- ? undefined
- : newPaytoParsed.targetType === PaytoType.TalerReserve ||
- newPaytoParsed.targetType === PaytoType.TalerReserveHttp;
-
- const activeDecision = useAccountActiveDecision(
- isNewAccount ? undefined : account,
- );
-
- const info =
- !activeDecision ||
- activeDecision instanceof TalerError ||
- activeDecision.type === "fail"
- ? undefined
- : activeDecision.body;
-
- if (!info && !isNewAccount) {
- <h1 class="text-base font-semibold leading-7 text-black">
- <i18n.Translate>loading... </i18n.Translate>
- </h1>;
- }
- // info may be undefined if this is a new account
- // for which we use the payto:// parameter
- const isWallet = info?.is_wallet ?? isNewAccountAWallet;
-
- if (isWallet === undefined) {
- return (
- <h1 class="text-base font-semibold leading-7 text-black">
- <i18n.Translate>Decision for account: </i18n.Translate>
- </h1>
- );
- }
- if (isWallet) {
- return (
- <h1 class="text-base font-semibold leading-7 text-black">
- <i18n.Translate>Decision for wallet: </i18n.Translate>
- </h1>
- );
- } else {
- return (
- <h1 class="text-base font-semibold leading-7 text-black">
- <i18n.Translate>Decision for bank account: </i18n.Translate>
- </h1>
- );
- }
-}
diff --git a/packages/taler-exchange-aml-webui/src/pages/Developer.stories.tsx b/packages/taler-exchange-aml-webui/src/pages/Developer.stories.tsx
@@ -0,0 +1,26 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import * as tests from "@gnu-taler/web-util/testing";
+import { DeveloperSettings } from "./Developer.js";
+
+export default { title: "development settings" };
+
+export const ConfiguredExchange = tests.createExample(DeveloperSettings, {
+ configuredBaseUrl: "https://exchange.example/",
+ effectiveBaseUrl: "https://exchange.example/",
+ onApply: () => undefined,
+});
+
+export const OverriddenExchange = tests.createExample(DeveloperSettings, {
+ configuredBaseUrl: "https://exchange.example/",
+ effectiveBaseUrl: "https://exchange.stage.example/",
+ initialOverride: "https://exchange.stage.example/",
+ onApply: () => undefined,
+});
diff --git a/packages/taler-exchange-aml-webui/src/pages/Developer.tsx b/packages/taler-exchange-aml-webui/src/pages/Developer.tsx
@@ -0,0 +1,305 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import {
+ AmlSpaDialect,
+ TranslatedString,
+ canonicalizeBaseUrl,
+} from "@gnu-taler/taler-util";
+import {
+ useCommonPreferences,
+ useExchangeApiContext,
+ useTranslationContext,
+} from "@gnu-taler/web-util/browser";
+import { VNode, h } from "preact";
+import { useState } from "preact/hooks";
+import { useUiSettingsContext } from "../context/ui-settings.js";
+import {
+ getAllBooleanPreferences,
+ getLabelForPreferences,
+ usePreferences,
+} from "../hooks/preferences.js";
+
+export const AML_BASE_URL_OVERRIDE_KEY = "aml-base-url";
+
+export interface DeveloperSettingsProps {
+ configuredBaseUrl?: string;
+ effectiveBaseUrl: string;
+ initialOverride?: string;
+ onApply(baseUrl: string | undefined): void;
+}
+
+function normalizeHttpBaseUrl(value: string): string {
+ const canonical = canonicalizeBaseUrl(value);
+ const protocol = new URL(canonical).protocol;
+ if (protocol !== "http:" && protocol !== "https:") {
+ throw new Error("unsupported protocol");
+ }
+ return canonical;
+}
+
+function PreferenceSwitch({
+ id,
+ label,
+ enabled,
+ onChange,
+}: {
+ id: string;
+ label: TranslatedString;
+ enabled: boolean;
+ onChange(enabled: boolean): void;
+}): VNode {
+ return (
+ <div class="flex items-center justify-between gap-6 rounded-lg border border-outlineVariant bg-surfaceContainer px-4 py-3">
+ <span id={id} class="text-sm font-medium text-onSurface">
+ {label}
+ </span>
+ <button
+ type="button"
+ role="switch"
+ aria-checked={enabled}
+ aria-labelledby={id}
+ data-enabled={enabled}
+ class="relative inline-flex h-6 w-11 shrink-0 rounded-full border-2 border-transparent bg-primary transition-colors data-[enabled=false]:bg-gray-300 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary"
+ onClick={() => onChange(!enabled)}
+ >
+ <span
+ aria-hidden="true"
+ data-enabled={enabled}
+ class="pointer-events-none inline-block h-5 w-5 translate-x-5 rounded-full bg-white shadow transition data-[enabled=false]:translate-x-0"
+ />
+ </button>
+ </div>
+ );
+}
+
+export function DeveloperSettings({
+ configuredBaseUrl,
+ effectiveBaseUrl,
+ initialOverride,
+ onApply,
+}: DeveloperSettingsProps): VNode {
+ const { i18n } = useTranslationContext();
+ const [preferences, updatePreference] = usePreferences();
+ const [{ showDebugInfo }, updateCommonPreference] = useCommonPreferences();
+ const [baseUrl, setBaseUrl] = useState(initialOverride ?? "");
+ const [error, setError] = useState<string>();
+
+ function apply(): void {
+ const requestedUrl = baseUrl.trim();
+ if (!requestedUrl) {
+ setError(undefined);
+ onApply(undefined);
+ return;
+ }
+ try {
+ const normalized = normalizeHttpBaseUrl(requestedUrl);
+ setBaseUrl(normalized);
+ setError(undefined);
+ onApply(normalized);
+ } catch {
+ setError(i18n.str`Enter a valid HTTP or HTTPS URL.`);
+ }
+ }
+
+ return (
+ <div class="mx-auto w-full max-w-3xl">
+ <h1 class="text-3xl font-bold tracking-tight text-gray-900">
+ <i18n.Translate>Development settings</i18n.Translate>
+ </h1>
+ <p class="mt-3 text-sm leading-6 text-gray-600">
+ <i18n.Translate>
+ These browser-local settings are intended for development and
+ troubleshooting.
+ </i18n.Translate>
+ </p>
+
+ <form
+ class="mt-8 space-y-5 rounded-lg border border-outlineVariant bg-white p-5 shadow-sm"
+ onSubmit={(event) => {
+ event.preventDefault();
+ apply();
+ }}
+ >
+ <div>
+ <h2 class="text-lg font-semibold text-gray-900">
+ <i18n.Translate>Exchange connection</i18n.Translate>
+ </h2>
+ <p class="mt-1 text-sm text-gray-600">
+ <i18n.Translate>
+ Changing the exchange reloads the application. The override is
+ stored only in this browser.
+ </i18n.Translate>
+ </p>
+ </div>
+
+ <div>
+ <label
+ htmlFor="exchange-base-url"
+ class="block text-sm font-semibold text-gray-900"
+ >
+ <i18n.Translate>Exchange base URL</i18n.Translate>
+ </label>
+ <input
+ id="exchange-base-url"
+ name="exchange-base-url"
+ type="url"
+ inputMode="url"
+ value={baseUrl}
+ placeholder={configuredBaseUrl}
+ aria-invalid={error !== undefined}
+ aria-describedby="exchange-base-url-help"
+ class="mt-2 block w-full rounded-md border-0 px-3 py-2 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-primary sm:text-sm"
+ onInput={(event) => {
+ setBaseUrl(event.currentTarget.value);
+ setError(undefined);
+ }}
+ />
+ <p id="exchange-base-url-help" class="mt-2 text-sm text-gray-500">
+ {configuredBaseUrl ? (
+ <i18n.Translate>
+ Leave empty to use the configured URL: {configuredBaseUrl}
+ </i18n.Translate>
+ ) : (
+ <i18n.Translate>
+ Leave empty to derive the exchange URL from this page.
+ </i18n.Translate>
+ )}
+ </p>
+ {error ? (
+ <p role="alert" class="mt-2 text-sm font-medium text-error">
+ {error}
+ </p>
+ ) : undefined}
+ </div>
+
+ <div class="rounded-md bg-surfaceContainer px-4 py-3 text-sm">
+ <span class="font-semibold text-onSurface">
+ <i18n.Translate>Currently connected to</i18n.Translate>
+ </span>{" "}
+ <code class="break-all text-onSurfaceVariant">
+ {effectiveBaseUrl}
+ </code>
+ </div>
+
+ <div class="flex flex-wrap gap-3">
+ <button
+ type="submit"
+ class="rounded-md bg-primary px-4 py-2 text-sm font-semibold text-onPrimary shadow-sm hover:bg-primaryHover"
+ >
+ <i18n.Translate>Apply and reload</i18n.Translate>
+ </button>
+ <button
+ type="button"
+ class="rounded-md bg-white px-4 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50"
+ onClick={() => {
+ setBaseUrl("");
+ setError(undefined);
+ onApply(undefined);
+ }}
+ >
+ <i18n.Translate>Use configured URL</i18n.Translate>
+ </button>
+ </div>
+ </form>
+
+ <section class="mt-8" aria-labelledby="preferences-title">
+ <h2 id="preferences-title" class="text-lg font-semibold text-gray-900">
+ <i18n.Translate>Preferences</i18n.Translate>
+ </h2>
+ <div class="mt-3 rounded-lg border border-outlineVariant bg-surfaceContainer px-4 py-4">
+ <label
+ htmlFor="aml-spa-dialect-override"
+ class="block text-sm font-semibold text-onSurface"
+ >
+ <i18n.Translate>AML SPA dialect</i18n.Translate>
+ </label>
+ <select
+ id="aml-spa-dialect-override"
+ value={preferences.dialectOverride ?? ""}
+ class="mt-2 block w-full rounded-md border-0 py-2 pl-3 pr-10 text-onSurface shadow-sm ring-1 ring-inset ring-outlineVariant focus:ring-2 focus:ring-primary sm:text-sm"
+ onChange={(event) => {
+ const value = event.currentTarget.value;
+ updatePreference(
+ "dialectOverride",
+ value === "" ? undefined : (value as AmlSpaDialect),
+ );
+ }}
+ >
+ <option value="">
+ <i18n.Translate>Use exchange configuration</i18n.Translate>
+ </option>
+ <option value={AmlSpaDialect.TOPS}>TOPS</option>
+ <option value={AmlSpaDialect.TESTING}>
+ <i18n.Translate>Testing</i18n.Translate>
+ </option>
+ </select>
+ <p class="mt-2 text-sm text-onSurfaceVariant">
+ <i18n.Translate>
+ Override how this web interface presents dialect-specific AML
+ rules and properties. The override is stored only in this browser.
+ </i18n.Translate>
+ </p>
+ </div>
+ <div class="mt-3 grid gap-3 sm:grid-cols-2">
+ {getAllBooleanPreferences().map((preference) => (
+ <PreferenceSwitch
+ key={preference}
+ id={`preference-${preference}`}
+ label={getLabelForPreferences(preference, i18n)}
+ enabled={preferences[preference]}
+ onChange={(enabled) => updatePreference(preference, enabled)}
+ />
+ ))}
+ <PreferenceSwitch
+ id="preference-show-debug-information"
+ label={i18n.str`Show debug information`}
+ enabled={showDebugInfo}
+ onChange={(enabled) =>
+ updateCommonPreference("showDebugInfo", enabled)
+ }
+ />
+ </div>
+ </section>
+ </div>
+ );
+}
+
+export function Developer(): VNode {
+ const { lib } = useExchangeApiContext();
+ return <DeveloperWithoutExchange effectiveBaseUrl={lib.exchange.baseUrl} />;
+}
+
+export function DeveloperWithoutExchange({
+ effectiveBaseUrl,
+}: {
+ effectiveBaseUrl: string;
+}): VNode {
+ const settings = useUiSettingsContext();
+ const initialOverride =
+ typeof localStorage === "undefined"
+ ? undefined
+ : (localStorage.getItem(AML_BASE_URL_OVERRIDE_KEY) ?? undefined);
+
+ return (
+ <DeveloperSettings
+ configuredBaseUrl={settings.backendBaseURL}
+ effectiveBaseUrl={effectiveBaseUrl}
+ initialOverride={initialOverride}
+ onApply={(baseUrl) => {
+ if (baseUrl) {
+ localStorage.setItem(AML_BASE_URL_OVERRIDE_KEY, baseUrl);
+ } else {
+ localStorage.removeItem(AML_BASE_URL_OVERRIDE_KEY);
+ }
+ window.location.reload();
+ }}
+ />
+ );
+}
diff --git a/packages/taler-exchange-aml-webui/src/pages/Info.stories.tsx b/packages/taler-exchange-aml-webui/src/pages/Info.stories.tsx
@@ -0,0 +1,152 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import {
+ AmlSpaDialect,
+ AmountString,
+ AvailableMeasureSummary,
+ HttpStatusCode,
+ LimitOperationType,
+ opFixedSuccess,
+ opKnownFailure,
+} from "@gnu-taler/taler-util";
+import { dummyHttpResponse } from "@gnu-taler/taler-util/http";
+import * as tests from "@gnu-taler/web-util/testing";
+import { h, VNode } from "preact";
+import { Router } from "wouter-preact";
+import { memoryLocation } from "wouter-preact/memory-location";
+import { ExchangeAmlFrame } from "../ExchangeAmlFrame.js";
+import { Navigation } from "../Routing.js";
+import { Info } from "./Info.js";
+
+export default { title: "exchange and AML configuration" };
+
+const populatedMeasures: AvailableMeasureSummary = {
+ roots: {
+ "review-documents": {
+ check_name: "identity-form",
+ prog_name: "document-review",
+ context: { requested_document: "proof-of-address" },
+ operation_type: LimitOperationType.deposit,
+ voluntary: true,
+ },
+ "notify-customer": {
+ check_name: "information-notice",
+ context: { subject: "updated-terms" },
+ voluntary: false,
+ },
+ "automatic-screening": {
+ check_name: "skip",
+ prog_name: "transaction-screening",
+ operation_type: LimitOperationType.transaction,
+ },
+ "broken-reference-example": {
+ check_name: "missing-check",
+ prog_name: "missing-program",
+ },
+ },
+ checks: {
+ "identity-form": {
+ description: "Collect and verify identity documents.",
+ description_i18n: {
+ de: "Identitätsdokumente erfassen und überprüfen.",
+ },
+ requires: ["requested_document"],
+ outputs: ["full_name", "date_of_birth", "residency"],
+ fallback: "notify-customer",
+ },
+ "information-notice": {
+ description: "Show important information to the customer.",
+ requires: ["subject"],
+ outputs: [],
+ fallback: "notify-customer",
+ },
+ },
+ programs: {
+ "document-review": {
+ description: "Evaluate the submitted identity documentation.",
+ context: ["requested_document"],
+ inputs: ["full_name", "date_of_birth"],
+ },
+ "transaction-screening": {
+ description: "Screen recent transactions for unusual patterns.",
+ context: [],
+ inputs: [],
+ },
+ },
+ default_rules: [
+ {
+ operation_type: LimitOperationType.deposit,
+ threshold: "ARS:10000" as AmountString,
+ timeframe: { d_us: 30 * 24 * 60 * 60 * 1_000_000 },
+ measures: ["review-documents"],
+ display_priority: 20,
+ exposed: true,
+ is_and_combinator: false,
+ },
+ ],
+};
+
+const emptyMeasures: AvailableMeasureSummary = {
+ roots: {},
+ checks: {},
+ programs: {},
+ default_rules: [],
+};
+
+const { hook: infoLocationHook } = memoryLocation({
+ path: "/info",
+ static: true,
+});
+
+function InfoPageShell(): VNode {
+ return (
+ <Router hook={infoLocationHook}>
+ <ExchangeAmlFrame NavigationBar={Navigation}>
+ <Info />
+ </ExchangeAmlFrame>
+ </Router>
+ );
+}
+
+export const PopulatedTops = tests.createExample(
+ InfoPageShell,
+ {},
+ {
+ amlDialect: AmlSpaDialect.TOPS,
+ exchange: {
+ getAmlMeasures: async () =>
+ opFixedSuccess(dummyHttpResponse, populatedMeasures),
+ },
+ },
+);
+
+export const EmptyTesting = tests.createExample(
+ InfoPageShell,
+ {},
+ {
+ amlDialect: AmlSpaDialect.TESTING,
+ exchange: {
+ getAmlMeasures: async () =>
+ opFixedSuccess(dummyHttpResponse, emptyMeasures),
+ },
+ },
+);
+
+export const MeasuresFailure = tests.createExample(
+ InfoPageShell,
+ {},
+ {
+ amlDialect: AmlSpaDialect.TOPS,
+ exchange: {
+ getAmlMeasures: async () =>
+ opKnownFailure(dummyHttpResponse, HttpStatusCode.Forbidden),
+ },
+ },
+);
diff --git a/packages/taler-exchange-aml-webui/src/pages/Info.test.tsx b/packages/taler-exchange-aml-webui/src/pages/Info.test.tsx
@@ -0,0 +1,107 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import { AvailableMeasureSummary, setupI18n } from "@gnu-taler/taler-util";
+import assert from "node:assert/strict";
+import test from "node:test";
+import { h, render } from "preact";
+import { localizedCheckDescription, MeasuresContent } from "./Info.js";
+
+setupI18n("en", {});
+
+test("uses the closest localized check description", () => {
+ const check = {
+ description: "English fallback",
+ description_i18n: { de: "Deutsche Beschreibung" },
+ requires: [],
+ outputs: [],
+ fallback: "fallback",
+ };
+ assert.equal(
+ localizedCheckDescription(check, "de-CH"),
+ "Deutsche Beschreibung",
+ );
+ assert.equal(localizedCheckDescription(check, "fr"), "English fallback");
+});
+
+async function installDom() {
+ const happyDomPackage = "happy-dom";
+ const { Window } = await import(happyDomPackage);
+ const window = new Window({ url: "https://aml.example/" });
+ for (const [key, value] of Object.entries({
+ window,
+ document: window.document,
+ navigator: window.navigator,
+ Node: window.Node,
+ Element: window.Element,
+ HTMLElement: window.HTMLElement,
+ })) {
+ Object.defineProperty(globalThis, key, {
+ configurable: true,
+ writable: true,
+ value,
+ });
+ }
+ return window;
+}
+
+test("renders all measure datasets and preserves unresolved references", async () => {
+ const summary: AvailableMeasureSummary = {
+ roots: {
+ automatic: {
+ check_name: "skip",
+ prog_name: "review",
+ },
+ broken: {
+ check_name: "missing-check",
+ prog_name: "missing-program",
+ context: { reason: "test" },
+ },
+ },
+ checks: {
+ form: {
+ description: "Collect information",
+ requires: ["country"],
+ outputs: ["residency"],
+ fallback: "missing-fallback",
+ },
+ },
+ programs: {
+ review: {
+ description: "Review the result",
+ context: ["case_id"],
+ inputs: ["residency"],
+ },
+ },
+ default_rules: [],
+ };
+
+ const window = await installDom();
+ const container = window.document.createElement("div");
+ render(
+ <MeasuresContent summary={summary} language="en" />,
+ container as unknown as Element,
+ );
+ const html = container.innerHTML;
+ assert.match(html, /broken/);
+ assert.match(html, /missing-check/);
+ assert.match(html, /missing-program/);
+ assert.match(html, /Unavailable reference/);
+ const skipCard = (
+ Array.from(container.querySelectorAll("article")) as HTMLElement[]
+ ).find((card) => card.textContent?.includes("skip"));
+ assert.ok(skipCard);
+ assert.match(skipCard.textContent ?? "", /Built-in check/);
+ assert.doesNotMatch(skipCard.textContent ?? "", /Unavailable reference/);
+ assert.match(html, /Collect information/);
+ assert.match(html, /Review the result/);
+ assert.match(html, /No default AML rules are configured/);
+ render(null, container as unknown as Element);
+ await window.happyDOM.abort();
+});
diff --git a/packages/taler-exchange-aml-webui/src/pages/Info.tsx b/packages/taler-exchange-aml-webui/src/pages/Info.tsx
@@ -0,0 +1,687 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import {
+ assertUnreachable,
+ AvailableMeasureSummary,
+ HttpStatusCode,
+ KycCheckInformation,
+ MeasureInformation,
+ TalerError,
+ TranslatedString,
+} from "@gnu-taler/taler-util";
+import {
+ AsyncButton,
+ ErrorLoading,
+ FailLoading,
+ Loading,
+ useExchangeApiContext,
+ useTranslationContext,
+} from "@gnu-taler/web-util/browser";
+import { h, VNode } from "preact";
+import { RulesInfo, labelForOperationType } from "../components/RulesInfo.js";
+import { useAmlSpaDialect, usePreferences } from "../hooks/preferences.js";
+import {
+ revalidateServerMeasures,
+ useServerMeasures,
+} from "../hooks/server-info.js";
+import {
+ DialectEventInfo,
+ DialectPropertyInfo,
+ getDialectInfo,
+} from "../utils/dialect-info.js";
+import { isBuiltInSkipCheck } from "../utils/measure-check.js";
+
+export function Info(): VNode {
+ const { config, url } = useExchangeApiContext();
+ const { i18n, lang } = useTranslationContext();
+ const [preferences] = usePreferences();
+ const configuredDialect = config.config.aml_spa_dialect;
+ const effectiveDialect = useAmlSpaDialect(configuredDialect);
+ const dialect = getDialectInfo(effectiveDialect, i18n);
+
+ const dialectSource = preferences.dialectOverride
+ ? i18n.str`Browser override`
+ : configuredDialect
+ ? i18n.str`Exchange configuration`
+ : i18n.str`Default fallback`;
+
+ return (
+ <div class="mx-auto max-w-6xl space-y-10 pb-12">
+ <header>
+ <h1 class="text-3xl font-bold tracking-tight text-gray-900">
+ <i18n.Translate>Exchange and AML configuration</i18n.Translate>
+ </h1>
+ <p class="mt-2 max-w-3xl text-sm text-gray-600">
+ <i18n.Translate>
+ Exchange identity, the active AML dialect, and the checks and
+ programs available to AML decisions.
+ </i18n.Translate>
+ </p>
+ </header>
+
+ <ConfigurationSection
+ title={i18n.str`Exchange`}
+ description={i18n.str`Public information reported by this exchange.`}
+ >
+ <DefinitionGrid
+ entries={[
+ [i18n.str`Base URL`, url.href],
+ [i18n.str`Protocol`, config.config.name],
+ [i18n.str`Protocol version`, config.config.version],
+ [
+ i18n.str`Implementation`,
+ config.config.implementation ?? i18n.str`Not reported`,
+ ],
+ [i18n.str`Currency`, config.config.currency],
+ ]}
+ />
+ </ConfigurationSection>
+
+ <ConfigurationSection
+ title={i18n.str`AML dialect`}
+ description={dialect.description}
+ >
+ <div class="rounded-lg border border-primary/30 bg-primaryContainer/30 p-5">
+ <div class="flex flex-wrap items-start justify-between gap-4">
+ <div>
+ <p class="text-sm font-medium text-gray-600">
+ <i18n.Translate>Effective dialect</i18n.Translate>
+ </p>
+ <div class="mt-1 flex flex-wrap items-center gap-2">
+ <span class="text-xl font-semibold text-gray-900">
+ {dialect.name}
+ </span>
+ <Code>{effectiveDialect}</Code>
+ </div>
+ </div>
+ <span class="rounded-full bg-primary px-3 py-1 text-xs font-semibold text-onPrimary">
+ {dialectSource}
+ </span>
+ </div>
+ <dl class="mt-5 grid gap-4 border-t border-primary/20 pt-4 sm:grid-cols-2">
+ <div>
+ <dt class="text-xs font-semibold uppercase tracking-wide text-gray-500">
+ <i18n.Translate>Configured dialect</i18n.Translate>
+ </dt>
+ <dd class="mt-1 text-sm text-gray-900">
+ {configuredDialect ?? i18n.str`Not specified`}
+ </dd>
+ </div>
+ <div>
+ <dt class="text-xs font-semibold uppercase tracking-wide text-gray-500">
+ <i18n.Translate>Effective dialect</i18n.Translate>
+ </dt>
+ <dd class="mt-1 text-sm text-gray-900">{effectiveDialect}</dd>
+ </div>
+ </dl>
+ </div>
+ </ConfigurationSection>
+
+ <CatalogSection
+ title={i18n.str`Account properties`}
+ description={i18n.str`Canonical properties defined by the effective dialect.`}
+ empty={i18n.str`This dialect does not define account properties.`}
+ items={dialect.properties}
+ render={(property) => <PropertyEntry property={property} />}
+ />
+
+ <CatalogSection
+ title={i18n.str`Derived events`}
+ description={i18n.str`Canonical events derived from account property changes.`}
+ empty={i18n.str`This dialect does not define derived events.`}
+ items={dialect.events}
+ render={(event) => <EventEntry event={event} />}
+ />
+
+ <ConfigurationSection
+ title={i18n.str`AML measures`}
+ description={i18n.str`Checks, programs, root measures, and default rules reported by the exchange.`}
+ >
+ <MeasuresConfiguration language={lang} />
+ </ConfigurationSection>
+ </div>
+ );
+}
+
+function ConfigurationSection({
+ title,
+ description,
+ children,
+}: {
+ title: TranslatedString;
+ description: TranslatedString;
+ children: VNode | VNode[];
+}): VNode {
+ return (
+ <section class="space-y-4">
+ <div>
+ <h2 class="text-xl font-semibold text-gray-900">{title}</h2>
+ <p class="mt-1 text-sm text-gray-600">{description}</p>
+ </div>
+ {children}
+ </section>
+ );
+}
+
+function DefinitionGrid({
+ entries,
+}: {
+ entries: Array<[TranslatedString, string | TranslatedString]>;
+}): VNode {
+ return (
+ <dl class="grid overflow-hidden rounded-lg border border-gray-200 bg-white sm:grid-cols-2 lg:grid-cols-3">
+ {entries.map(([label, value]) => (
+ <div
+ class="border-b border-gray-200 p-4 last:border-b-0 sm:border-r"
+ key={label}
+ >
+ <dt class="text-xs font-semibold uppercase tracking-wide text-gray-500">
+ {label}
+ </dt>
+ <dd class="mt-1 break-words text-sm font-medium text-gray-900">
+ {value}
+ </dd>
+ </div>
+ ))}
+ </dl>
+ );
+}
+
+function CatalogSection<T>({
+ title,
+ description,
+ empty,
+ items,
+ render,
+}: {
+ title: TranslatedString;
+ description: TranslatedString;
+ empty: TranslatedString;
+ items: T[];
+ render: (item: T) => VNode;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ const countLabel =
+ items.length === 1
+ ? i18n.str`${items.length} entry`
+ : i18n.str`${items.length} entries`;
+ return (
+ <ConfigurationSection title={title} description={description}>
+ <div class="overflow-hidden rounded-lg border border-gray-200 bg-white">
+ <div class="border-b border-gray-200 bg-gray-50 px-5 py-3 text-xs font-semibold uppercase tracking-wide text-gray-500">
+ {countLabel}
+ </div>
+ {items.length ? (
+ <ul class="divide-y divide-gray-200">
+ {items.map((item, index) => (
+ <li class="p-5" key={index}>
+ {render(item)}
+ </li>
+ ))}
+ </ul>
+ ) : (
+ <p class="p-5 text-sm text-gray-600">{empty}</p>
+ )}
+ </div>
+ </ConfigurationSection>
+ );
+}
+
+function PropertyEntry({ property }: { property: DialectPropertyInfo }): VNode {
+ return (
+ <div class="grid gap-2 md:grid-cols-[minmax(13rem,1fr)_2fr] md:gap-6">
+ <div>
+ <p class="font-semibold text-gray-900">{property.name}</p>
+ <div class="mt-1 flex flex-wrap gap-2">
+ <Code>{property.id}</Code>
+ <span class="rounded bg-gray-100 px-2 py-0.5 text-xs text-gray-700">
+ {property.valueType}
+ </span>
+ </div>
+ </div>
+ <p class="text-sm leading-6 text-gray-600">{property.description}</p>
+ </div>
+ );
+}
+
+function EventEntry({ event }: { event: DialectEventInfo }): VNode {
+ return (
+ <div class="grid gap-2 md:grid-cols-[minmax(13rem,1fr)_2fr] md:gap-6">
+ <div>
+ <p class="font-semibold text-gray-900">{event.name}</p>
+ <div class="mt-1">
+ <Code>{event.id}</Code>
+ </div>
+ </div>
+ <p class="text-sm leading-6 text-gray-600">{event.description}</p>
+ </div>
+ );
+}
+
+function MeasuresConfiguration({ language }: { language: string }): VNode {
+ const { i18n } = useTranslationContext();
+ const result = useServerMeasures();
+
+ if (result === undefined) return <Loading />;
+ if (result instanceof TalerError) {
+ return (
+ <div class="space-y-4">
+ <ErrorLoading
+ title={i18n.str`Failed to load the exchange AML measures.`}
+ error={result}
+ />
+ <RetryMeasures />
+ </div>
+ );
+ }
+ if (result.type === "fail") {
+ return (
+ <div class="space-y-4">
+ <FailLoading
+ operation={result}
+ title={i18n.str`Failed to load the exchange AML measures.`}
+ translate={(failure) => {
+ switch (failure.case) {
+ case HttpStatusCode.Forbidden:
+ return (
+ <i18n.Translate>
+ The officer session is invalid.
+ </i18n.Translate>
+ );
+ case HttpStatusCode.NotFound:
+ return (
+ <i18n.Translate>
+ The measures endpoint is not available.
+ </i18n.Translate>
+ );
+ case HttpStatusCode.Conflict:
+ return (
+ <i18n.Translate>
+ The exchange configuration changed. Reload it and try again.
+ </i18n.Translate>
+ );
+ default:
+ return assertUnreachable(failure.case);
+ }
+ }}
+ />
+ <RetryMeasures />
+ </div>
+ );
+ }
+
+ return <MeasuresContent summary={result.body} language={language} />;
+}
+
+function RetryMeasures(): VNode {
+ const { i18n } = useTranslationContext();
+ return (
+ <AsyncButton
+ onClick={async () => {
+ await revalidateServerMeasures();
+ }}
+ class="rounded-md bg-primary px-4 py-2 text-sm font-semibold text-onPrimary"
+ >
+ <i18n.Translate>Retry loading measures</i18n.Translate>
+ </AsyncButton>
+ );
+}
+
+export function MeasuresContent({
+ summary,
+ language,
+}: {
+ summary: AvailableMeasureSummary;
+ language: string;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ const roots = Object.entries(summary.roots);
+ const checks = Object.entries(summary.checks);
+ const programs = Object.entries(summary.programs);
+
+ return (
+ <div class="space-y-8">
+ <MeasureGroup title={i18n.str`Root measures`} count={roots.length}>
+ {roots.length ? (
+ <div class="grid gap-4 lg:grid-cols-2">
+ {roots.map(([name, measure]) => (
+ <RootMeasureCard
+ key={name}
+ name={name}
+ measure={measure}
+ summary={summary}
+ language={language}
+ />
+ ))}
+ </div>
+ ) : (
+ <EmptyData>
+ <i18n.Translate>No root measures are configured.</i18n.Translate>
+ </EmptyData>
+ )}
+ </MeasureGroup>
+
+ <MeasureGroup title={i18n.str`KYC checks`} count={checks.length}>
+ {checks.length ? (
+ <div class="grid gap-4 lg:grid-cols-2">
+ {checks.map(([name, check]) => (
+ <CheckCard
+ key={name}
+ name={name}
+ check={check}
+ language={language}
+ fallbackAvailable={!!summary.roots[check.fallback]}
+ />
+ ))}
+ </div>
+ ) : (
+ <EmptyData>
+ <i18n.Translate>No KYC checks are configured.</i18n.Translate>
+ </EmptyData>
+ )}
+ </MeasureGroup>
+
+ <MeasureGroup title={i18n.str`AML programs`} count={programs.length}>
+ {programs.length ? (
+ <div class="grid gap-4 lg:grid-cols-2">
+ {programs.map(([name, program]) => (
+ <DataCard
+ key={name}
+ title={name}
+ description={program.description}
+ >
+ <TokenField
+ label={i18n.str`Required context`}
+ values={program.context}
+ />
+ <TokenField
+ label={i18n.str`Required inputs`}
+ values={program.inputs}
+ />
+ </DataCard>
+ ))}
+ </div>
+ ) : (
+ <EmptyData>
+ <i18n.Translate>No AML programs are configured.</i18n.Translate>
+ </EmptyData>
+ )}
+ </MeasureGroup>
+
+ <MeasureGroup
+ title={i18n.str`Default rules`}
+ count={summary.default_rules.length}
+ >
+ {summary.default_rules.length ? (
+ <div class="overflow-hidden rounded-lg border border-gray-200 bg-white">
+ <RulesInfo rules={summary.default_rules} />
+ </div>
+ ) : (
+ <EmptyData>
+ <i18n.Translate>
+ No default AML rules are configured.
+ </i18n.Translate>
+ </EmptyData>
+ )}
+ </MeasureGroup>
+ </div>
+ );
+}
+
+function MeasureGroup({
+ title,
+ count,
+ children,
+}: {
+ title: TranslatedString;
+ count: number;
+ children: VNode;
+}): VNode {
+ return (
+ <section>
+ <div class="mb-3 flex items-center gap-2">
+ <h3 class="text-base font-semibold text-gray-900">{title}</h3>
+ <span class="rounded-full bg-gray-100 px-2 py-0.5 text-xs text-gray-600">
+ {count}
+ </span>
+ </div>
+ {children}
+ </section>
+ );
+}
+
+function RootMeasureCard({
+ name,
+ measure,
+ summary,
+ language,
+}: {
+ name: string;
+ measure: MeasureInformation;
+ summary: AvailableMeasureSummary;
+ language: string;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ const check = summary.checks[measure.check_name];
+ const isBuiltInSkip = isBuiltInSkipCheck(measure.check_name);
+ const program = measure.prog_name
+ ? summary.programs[measure.prog_name]
+ : undefined;
+ return (
+ <DataCard title={name}>
+ <ReferenceField
+ label={i18n.str`KYC check`}
+ name={measure.check_name}
+ description={
+ isBuiltInSkip
+ ? i18n.str`Built-in check that proceeds without collecting customer data.`
+ : check && localizedCheckDescription(check, language)
+ }
+ missing={!isBuiltInSkip && !check}
+ />
+ {measure.prog_name ? (
+ <ReferenceField
+ label={i18n.str`AML program`}
+ name={measure.prog_name}
+ description={program?.description}
+ missing={!program}
+ />
+ ) : (
+ <SimpleField label={i18n.str`AML program`} value={i18n.str`None`} />
+ )}
+ <SimpleField
+ label={i18n.str`Operation`}
+ value={
+ measure.operation_type
+ ? labelForOperationType(measure.operation_type, i18n)
+ : i18n.str`Not specified`
+ }
+ />
+ <SimpleField
+ label={i18n.str`Voluntary`}
+ value={measure.voluntary ? i18n.str`Yes` : i18n.str`No`}
+ />
+ <ContextField context={measure.context} />
+ </DataCard>
+ );
+}
+
+function CheckCard({
+ name,
+ check,
+ language,
+ fallbackAvailable,
+}: {
+ name: string;
+ check: KycCheckInformation;
+ language: string;
+ fallbackAvailable: boolean;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ return (
+ <DataCard
+ title={name}
+ description={localizedCheckDescription(check, language)}
+ >
+ <TokenField label={i18n.str`Required context`} values={check.requires} />
+ <TokenField label={i18n.str`Outputs`} values={check.outputs} />
+ <ReferenceField
+ label={i18n.str`Fallback measure`}
+ name={check.fallback}
+ missing={!fallbackAvailable}
+ />
+ </DataCard>
+ );
+}
+
+function DataCard({
+ title,
+ description,
+ children,
+}: {
+ title: string;
+ description?: string;
+ children: VNode | VNode[];
+}): VNode {
+ return (
+ <article class="rounded-lg border border-gray-200 bg-white p-5">
+ <Code>{title}</Code>
+ {description ? (
+ <p class="mt-3 text-sm leading-6 text-gray-700">{description}</p>
+ ) : undefined}
+ <dl class="mt-4 space-y-3">{children}</dl>
+ </article>
+ );
+}
+
+function SimpleField({
+ label,
+ value,
+}: {
+ label: TranslatedString;
+ value: string | TranslatedString;
+}): VNode {
+ return (
+ <div>
+ <dt class="text-xs font-semibold uppercase tracking-wide text-gray-500">
+ {label}
+ </dt>
+ <dd class="mt-1 text-sm text-gray-800">{value}</dd>
+ </div>
+ );
+}
+
+function ReferenceField({
+ label,
+ name,
+ description,
+ missing = false,
+}: {
+ label: TranslatedString;
+ name: string;
+ description?: string;
+ missing?: boolean;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ return (
+ <div>
+ <dt class="text-xs font-semibold uppercase tracking-wide text-gray-500">
+ {label}
+ </dt>
+ <dd class="mt-1 text-sm text-gray-800">
+ <Code>{name}</Code>{" "}
+ {missing ? (
+ <span class="font-semibold text-red-700">
+ <i18n.Translate>Unavailable reference</i18n.Translate>
+ </span>
+ ) : description ? (
+ <span class="ml-1 text-gray-600">{description}</span>
+ ) : undefined}
+ </dd>
+ </div>
+ );
+}
+
+function TokenField({
+ label,
+ values,
+}: {
+ label: TranslatedString;
+ values: string[];
+}): VNode {
+ const { i18n } = useTranslationContext();
+ return (
+ <div>
+ <dt class="text-xs font-semibold uppercase tracking-wide text-gray-500">
+ {label}
+ </dt>
+ <dd class="mt-1 flex flex-wrap gap-1.5">
+ {values.length ? (
+ values.map((value) => <Code key={value}>{value}</Code>)
+ ) : (
+ <span class="text-sm text-gray-500">
+ <i18n.Translate>None</i18n.Translate>
+ </span>
+ )}
+ </dd>
+ </div>
+ );
+}
+
+function ContextField({ context }: { context: object | undefined }): VNode {
+ const { i18n } = useTranslationContext();
+ const hasContext = context && Object.keys(context).length > 0;
+ return (
+ <div>
+ <dt class="text-xs font-semibold uppercase tracking-wide text-gray-500">
+ <i18n.Translate>Context</i18n.Translate>
+ </dt>
+ <dd class="mt-1">
+ {hasContext ? (
+ <pre class="overflow-x-auto rounded bg-gray-50 p-3 text-xs text-gray-800">
+ {JSON.stringify(context, undefined, 2)}
+ </pre>
+ ) : (
+ <span class="text-sm text-gray-500">
+ <i18n.Translate>None</i18n.Translate>
+ </span>
+ )}
+ </dd>
+ </div>
+ );
+}
+
+function EmptyData({ children }: { children: VNode }): VNode {
+ return (
+ <p class="rounded-lg border border-dashed border-gray-300 bg-gray-50 p-5 text-sm text-gray-600">
+ {children}
+ </p>
+ );
+}
+
+function Code({ children }: { children: string }): VNode {
+ return (
+ <code class="break-all rounded bg-gray-100 px-1.5 py-0.5 text-xs font-medium text-gray-800">
+ {children}
+ </code>
+ );
+}
+
+export function localizedCheckDescription(
+ check: KycCheckInformation,
+ language: string,
+): string {
+ const baseLanguage = language.split("-")[0];
+ return (
+ check.description_i18n?.[language] ??
+ check.description_i18n?.[baseLanguage] ??
+ check.description
+ );
+}
diff --git a/packages/taler-exchange-aml-webui/src/pages/OfficerAccess.stories.tsx b/packages/taler-exchange-aml-webui/src/pages/OfficerAccess.stories.tsx
@@ -0,0 +1,237 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import {
+ AbsoluteTime,
+ HttpStatusCode,
+ OfficerId,
+ Password,
+ TalerError,
+ TalerErrorCode,
+ opFixedSuccess,
+ opKnownFailure,
+} from "@gnu-taler/taler-util";
+import { dummyHttpResponse } from "@gnu-taler/taler-util/http";
+import * as tests from "@gnu-taler/web-util/testing";
+import { h, VNode } from "preact";
+import { Router } from "wouter-preact";
+import { memoryLocation } from "wouter-preact/memory-location";
+import { CreateSession } from "../components/CreateSession.js";
+import { AccessCheckStatus } from "../components/AccessCheckStatus.js";
+import { OfficerEnrollment } from "../components/OfficerEnrollment.js";
+import { UnlockSession } from "../components/UnlockSession.js";
+import { ExchangeAmlFrame } from "../ExchangeAmlFrame.js";
+import {
+ OfficerLocked,
+ OfficerNotFound,
+ OfficerReady,
+} from "../hooks/officer.js";
+import { OfficerAccessGate } from "../Routing.js";
+
+export default { title: "officer access" };
+
+const publicKey =
+ "4TQZQ0M6CB0JZXJ3Z1B4H7X3EVAQXX45SB9QT0NXZYKAHQXZ3EYG" as OfficerId;
+
+const readyOfficer: OfficerReady = {
+ state: "ready",
+ session: {
+ id: publicKey,
+ __signingKey: new Uint8Array(32) as any,
+ },
+ expiration: AbsoluteTime.fromMilliseconds(Date.now() + 60 * 60 * 1000),
+ lock: () => opFixedSuccess(dummyHttpResponse, undefined),
+ forget: () => opFixedSuccess(dummyHttpResponse, undefined),
+};
+
+const lockedOfficer: OfficerLocked = {
+ state: "locked",
+ id: publicKey,
+ officer_name: "Alice Example",
+ tryUnlock: async (_password: Password) =>
+ opFixedSuccess(dummyHttpResponse, undefined),
+ forget: () => opFixedSuccess(dummyHttpResponse, undefined),
+};
+
+const missingOfficer: OfficerNotFound = {
+ state: "not-found",
+ create: async (_password: Password) =>
+ opFixedSuccess(dummyHttpResponse, publicKey),
+};
+
+function LockedFrame(): VNode {
+ return (
+ <ExchangeAmlFrame officer={lockedOfficer}>
+ <UnlockSession officer={lockedOfficer} />
+ </ExchangeAmlFrame>
+ );
+}
+
+function MissingFrame(): VNode {
+ return (
+ <ExchangeAmlFrame officer={missingOfficer}>
+ <CreateSession officer={missingOfficer} />
+ </ExchangeAmlFrame>
+ );
+}
+
+function EnrollmentFrame(): VNode {
+ return (
+ <ExchangeAmlFrame officer={readyOfficer}>
+ <OfficerEnrollment
+ officer={readyOfficer}
+ signupEmail="aml-admin@exchange.example"
+ onRetry={async () => undefined}
+ />
+ </ExchangeAmlFrame>
+ );
+}
+
+function CompatibilityFrame(): VNode {
+ return (
+ <ExchangeAmlFrame>
+ <AccessCheckStatus
+ title="Checking compatibility"
+ description="Verifying that this web application is compatible with the exchange."
+ />
+ </ExchangeAmlFrame>
+ );
+}
+
+export const NewSession = tests.createExample(MissingFrame, {});
+export const SessionLocked = tests.createExample(LockedFrame, {});
+export const EnrollmentRequired = tests.createExample(EnrollmentFrame, {});
+export const CompatibilityCheckInProgress = tests.createExample(
+ CompatibilityFrame,
+ {},
+);
+
+export const AccessCheckInProgress = tests.createExample(
+ OfficerAccessGate,
+ { officer: readyOfficer },
+ {
+ exchange: {
+ getAmlOfficer: async () => new Promise<never>(() => undefined),
+ },
+ },
+);
+
+export const EnrollmentRejected = tests.createExample(
+ OfficerAccessGate,
+ { officer: readyOfficer },
+ {
+ exchange: {
+ getAmlOfficer: async () =>
+ opKnownFailure(dummyHttpResponse, HttpStatusCode.Forbidden),
+ },
+ },
+);
+
+export const AccessCheckFailed = tests.createExample(
+ OfficerAccessGate,
+ { officer: readyOfficer },
+ {
+ exchange: {
+ getAmlOfficer: async () => {
+ throw TalerError.fromException(
+ new Error("The exchange could not be reached."),
+ );
+ },
+ },
+ },
+);
+
+export const PreV40Exchange = tests.createExample(
+ OfficerAccessGate,
+ { officer: readyOfficer },
+ { exchangeVersion: "39:0:5" },
+);
+
+export const InvalidSignature = tests.createExample(
+ OfficerAccessGate,
+ { officer: readyOfficer },
+ {
+ exchange: {
+ getAmlOfficer: async () => ({
+ ...opKnownFailure(dummyHttpResponse, HttpStatusCode.Forbidden),
+ detail: {
+ code: TalerErrorCode.EXCHANGE_GENERIC_AML_OFFICER_GET_SIGNATURE_INVALID,
+ },
+ }),
+ },
+ },
+);
+
+const { hook: sessionLocationHook } = memoryLocation({
+ path: "/profile",
+ static: true,
+});
+
+const { hook: readOnlyDecisionLocationHook } = memoryLocation({
+ path: "/decide/ACCOUNT/PAYTO",
+ static: true,
+});
+
+function OfficerSessionAccess(): VNode {
+ return (
+ <Router hook={sessionLocationHook}>
+ <OfficerAccessGate officer={readyOfficer} />
+ </Router>
+ );
+}
+
+function ReadOnlyDecisionAccess(): VNode {
+ return (
+ <Router hook={readOnlyDecisionLocationHook}>
+ <OfficerAccessGate officer={readyOfficer} />
+ </Router>
+ );
+}
+
+export const ReadOnlyOfficer = tests.createExample(
+ OfficerSessionAccess,
+ {},
+ {
+ exchange: {
+ getAmlOfficer: async () =>
+ opFixedSuccess(dummyHttpResponse, {
+ officer_name: "Alice Example",
+ read_only: true,
+ }),
+ },
+ },
+);
+
+export const ReadWriteOfficer = tests.createExample(
+ OfficerSessionAccess,
+ {},
+ {
+ exchange: {
+ getAmlOfficer: async () =>
+ opFixedSuccess(dummyHttpResponse, {
+ officer_name: "Alice Example",
+ read_only: false,
+ }),
+ },
+ },
+);
+
+export const ReadOnlyDecisionBlocked = tests.createExample(
+ ReadOnlyDecisionAccess,
+ {},
+ {
+ exchange: {
+ getAmlOfficer: async () =>
+ opFixedSuccess(dummyHttpResponse, {
+ officer_name: "Alice Example",
+ read_only: true,
+ }),
+ },
+ },
+);
diff --git a/packages/taler-exchange-aml-webui/src/pages/Profile.tsx b/packages/taler-exchange-aml-webui/src/pages/Profile.tsx
@@ -13,74 +13,234 @@
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 { Duration } from "@gnu-taler/taler-util";
import {
+ CopyButton,
+ Time,
useExchangeApiContext,
useTranslationContext,
} from "@gnu-taler/web-util/browser";
-import { h } from "preact";
-import { useOfficer } from "../hooks/officer.js";
+import { Fragment, h } from "preact";
+import { useState } from "preact/hooks";
+import { ConfirmationModal } from "../components/ConfirmationModal.js";
import { HandleSessionNotReady } from "../components/HandleAccountNotReady.js";
-import { useUiSettingsContext } from "../context/ui-settings.js";
+import { useOfficerInfoContext } from "../context/officer-info.js";
+import { useOfficer } from "../hooks/officer.js";
const TALER_SCREEN_ID = 112;
export function Profile() {
const officer = useOfficer();
- const settings = useUiSettingsContext();
- const { lib } = useExchangeApiContext();
+ const officerInfo = useOfficerInfoContext();
+ const { url: exchangeBaseUrl } = useExchangeApiContext();
const { i18n } = useTranslationContext();
+ const [confirmRemoval, setConfirmRemoval] = useState(false);
if (officer.state !== "ready") {
return <HandleSessionNotReady officer={officer} />;
}
- const url = new URL("./", lib.exchange.baseUrl);
- const signupEmail = settings.signupEmail ?? `aml-signup@${url.hostname}`;
-
return (
- <div>
- <h1 class="my-2 text-3xl font-bold tracking-tight text-gray-900 ">
- <i18n.Translate>Session public key</i18n.Translate>
- </h1>
- <div class="max-w-xl text-base leading-7 text-gray-700 lg:max-w-lg">
- <p class="mt-6 font-mono break-all">{officer.session.id}</p>
- </div>
- <p>
- <a
- href={`mailto:${signupEmail}?subject=${encodeURIComponent(
- "AML activation request",
- )}&body=${encodeURIComponent(
- `Please activate my AML session\n\nSession PubKey: ${officer.session.id}`,
- )}`}
- target="_blank"
- rel="noreferrer"
- class="m-4 block rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
+ <>
+ <div class="max-w-3xl space-y-6 text-gray-700 dark:text-gray-300">
+ <header>
+ <h1 class="text-3xl font-bold tracking-tight text-gray-900 dark:text-gray-100">
+ <i18n.Translate>Session and access</i18n.Translate>
+ </h1>
+ <p class="mt-2 max-w-2xl text-base leading-7">
+ <i18n.Translate>
+ Review this officer's exchange access and manage the unlocked key
+ in this browser.
+ </i18n.Translate>
+ </p>
+ </header>
+
+ <section
+ aria-labelledby="officer-access-title"
+ class="rounded-lg border border-outlineVariant bg-white p-5 shadow-sm dark:bg-gray-900"
>
- <i18n.Translate>Request session activation</i18n.Translate>
- </a>
- </p>
- <p>
- <button
- type="button"
- onClick={() => {
- officer.lock();
- }}
- class="m-4 block rounded-md border-0 bg-gray-200 px-3 py-2 text-center text-sm text-black shadow-sm "
+ <h2
+ id="officer-access-title"
+ class="text-lg font-bold text-gray-900 dark:text-gray-100"
+ >
+ <i18n.Translate>Officer access</i18n.Translate>
+ </h2>
+ <dl class="mt-4 divide-y divide-outlineVariant text-sm">
+ <div class="grid gap-1 py-3 first:pt-0 sm:grid-cols-[10rem_minmax(0,1fr)] sm:gap-4">
+ <dt class="font-semibold text-gray-900 dark:text-gray-100">
+ <i18n.Translate>Officer name</i18n.Translate>
+ </dt>
+ <dd>{officerInfo.officer_name}</dd>
+ </div>
+ <div class="grid gap-1 py-3 sm:grid-cols-[10rem_minmax(0,1fr)] sm:gap-4">
+ <dt class="font-semibold text-gray-900 dark:text-gray-100">
+ <i18n.Translate>Permissions</i18n.Translate>
+ </dt>
+ <dd>
+ <span
+ class={`inline-flex rounded-full px-2.5 py-1 text-xs font-semibold ${
+ officerInfo.read_only
+ ? "bg-amber-100 text-amber-900 dark:bg-amber-900/40 dark:text-amber-100"
+ : "bg-green-100 text-green-900 dark:bg-green-900/40 dark:text-green-100"
+ }`}
+ >
+ {officerInfo.read_only ? (
+ <i18n.Translate>Read-only</i18n.Translate>
+ ) : (
+ <i18n.Translate>Read and write</i18n.Translate>
+ )}
+ </span>
+ </dd>
+ </div>
+ <div class="grid gap-1 py-3 pb-0 sm:grid-cols-[10rem_minmax(0,1fr)] sm:gap-4">
+ <dt class="font-semibold text-gray-900 dark:text-gray-100">
+ <i18n.Translate>Exchange base URL</i18n.Translate>
+ </dt>
+ <dd>
+ <code class="break-all text-xs sm:text-sm">
+ {exchangeBaseUrl.href}
+ </code>
+ </dd>
+ </div>
+ </dl>
+ </section>
+
+ <section
+ aria-labelledby="session-security-title"
+ class="rounded-lg border border-outlineVariant bg-white p-5 shadow-sm dark:bg-gray-900"
>
- <i18n.Translate>Lock session</i18n.Translate>
- </button>
- </p>
- <p>
- <button
- type="button"
- onClick={() => {
- officer.forget();
- }}
- class="m-4 block rounded-md bg-red-600 px-3 py-2 text-center text-sm text-white shadow-sm hover:bg-red-500 "
+ <div class="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
+ <div>
+ <h2
+ id="session-security-title"
+ class="text-lg font-bold text-gray-900 dark:text-gray-100"
+ >
+ <i18n.Translate>Session security</i18n.Translate>
+ </h2>
+ <p class="mt-1 text-sm leading-6">
+ <i18n.Translate>
+ Lock the session when you leave this device unattended.
+ </i18n.Translate>
+ </p>
+ </div>
+ <button
+ type="button"
+ onClick={() => {
+ officer.lock();
+ }}
+ class="inline-flex min-h-11 shrink-0 items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-semibold text-onPrimary hover:bg-primary/90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary"
+ >
+ <i18n.Translate>Lock now</i18n.Translate>
+ </button>
+ </div>
+
+ <dl class="mt-4 divide-y divide-outlineVariant text-sm">
+ <div class="grid gap-1 py-3 first:pt-0 sm:grid-cols-[10rem_minmax(0,1fr)] sm:gap-4">
+ <dt class="font-semibold text-gray-900 dark:text-gray-100">
+ <i18n.Translate>Status</i18n.Translate>
+ </dt>
+ <dd>
+ <span class="inline-flex items-center gap-2 font-semibold text-green-800 dark:text-green-200">
+ <span
+ aria-hidden="true"
+ class="size-2 rounded-full bg-green-600 dark:bg-green-400"
+ />
+ <i18n.Translate>Unlocked</i18n.Translate>
+ </span>
+ </dd>
+ </div>
+ <div class="grid gap-1 py-3 sm:grid-cols-[10rem_minmax(0,1fr)] sm:gap-4">
+ <dt class="font-semibold text-gray-900 dark:text-gray-100">
+ <i18n.Translate>Locks automatically</i18n.Translate>
+ </dt>
+ <dd>
+ <div class="font-semibold text-gray-900 dark:text-gray-100">
+ <Time
+ timestamp={officer.expiration}
+ relative={Duration.fromSpec({ days: 1 })}
+ format="PPpp"
+ />
+ </div>
+ <div class="mt-1 text-xs text-gray-600 dark:text-gray-400">
+ <i18n.Translate>Exact time</i18n.Translate>:{" "}
+ <Time format="PPpp" timestamp={officer.expiration} />
+ </div>
+ </dd>
+ </div>
+ </dl>
+
+ <details class="border-t border-outlineVariant pt-3">
+ <summary class="min-h-11 cursor-pointer py-2 font-semibold text-gray-900 hover:text-primary focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary dark:text-gray-100">
+ <i18n.Translate>Officer public key</i18n.Translate>
+ </summary>
+ <div class="mt-2 flex items-start gap-2 rounded-md bg-surfaceContainer p-3">
+ <code class="min-w-0 flex-1 break-all text-xs sm:text-sm">
+ {officer.session.id}
+ </code>
+ <CopyButton
+ class="inline-flex min-h-11 shrink-0 items-center gap-2 rounded-md border border-outline bg-white px-3 py-2 text-sm font-semibold text-gray-900 hover:bg-gray-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary dark:bg-gray-900 dark:text-gray-100 dark:hover:bg-gray-800"
+ getContent={() => officer.session.id}
+ >
+ <span class="sr-only sm:not-sr-only">
+ <i18n.Translate>Copy public key</i18n.Translate>
+ </span>
+ </CopyButton>
+ </div>
+ </details>
+ </section>
+
+ <section
+ aria-labelledby="remove-key-title"
+ class="border-t border-outlineVariant pt-5"
>
- <i18n.Translate>Forget session</i18n.Translate>
- </button>
- </p>
- </div>
+ <h2
+ id="remove-key-title"
+ class="text-lg font-bold text-gray-900 dark:text-gray-100"
+ >
+ <i18n.Translate>Remove key from this browser</i18n.Translate>
+ </h2>
+ <p class="mt-2 max-w-2xl text-sm leading-6">
+ <i18n.Translate>
+ Removing this key deletes the officer key from this browser. It
+ does not revoke or change the officer's access at the exchange.
+ Ask the exchange operator to revoke access if needed.
+ </i18n.Translate>
+ </p>
+ <button
+ type="button"
+ onClick={() => setConfirmRemoval(true)}
+ class="mt-4 inline-flex min-h-11 items-center justify-center rounded-md border border-error px-4 py-2 text-sm font-semibold text-error hover:bg-errorContainer focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-error dark:border-red-300 dark:text-red-300 dark:hover:bg-red-950/50"
+ >
+ <i18n.Translate>Remove key</i18n.Translate>
+ </button>
+ </section>
+ </div>
+
+ <ConfirmationModal
+ open={confirmRemoval}
+ title={<i18n.Translate>Remove officer key?</i18n.Translate>}
+ confirmLabel={<i18n.Translate>Remove key</i18n.Translate>}
+ onClose={() => setConfirmRemoval(false)}
+ onConfirm={() => {
+ setConfirmRemoval(false);
+ void officer.forget();
+ }}
+ >
+ <div class="space-y-3">
+ <p>
+ <i18n.Translate>
+ This deletes the officer key from this browser. You will need to
+ create and enroll a new key to use the AML WebUI here again.
+ </i18n.Translate>
+ </p>
+ <p>
+ <i18n.Translate>
+ This does not revoke the officer at the exchange. Ask the exchange
+ operator to revoke its access if the key may be compromised.
+ </i18n.Translate>
+ </p>
+ </div>
+ </ConfirmationModal>
+ </>
);
}
diff --git a/packages/taler-exchange-aml-webui/src/pages/Search.stories.tsx b/packages/taler-exchange-aml-webui/src/pages/Search.stories.tsx
@@ -0,0 +1,58 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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 * as tests from "@gnu-taler/web-util/testing";
+import { h, VNode } from "preact";
+import { Router } from "wouter-preact";
+import { memoryLocation } from "wouter-preact/memory-location";
+import { ExchangeAmlFrame } from "../ExchangeAmlFrame.js";
+import { Navigation } from "../Routing.js";
+import { Search, WalletForm } from "./Search.js";
+
+export default { title: "find account" };
+
+const { hook: searchLocationHook } = memoryLocation({
+ path: "/search",
+ static: true,
+});
+
+function LoggedInFindAccount(): VNode {
+ return (
+ <Router hook={searchLocationHook}>
+ <ExchangeAmlFrame NavigationBar={Navigation}>
+ <Search
+ routeToAccountById={({ cid }) => `#/account/${cid}`}
+ onNewDecision={() => undefined}
+ />
+ </ExchangeAmlFrame>
+ </Router>
+ );
+}
+
+export const LoggedInShell = tests.createExample(LoggedInFindAccount, {});
+
+function WalletLookupForm(): VNode {
+ return (
+ <ExchangeAmlFrame>
+ <div class="mx-auto max-w-2xl space-y-4 py-8">
+ <h1 class="text-3xl font-bold">Find wallet account</h1>
+ <WalletForm onSearch={() => undefined} />
+ </div>
+ </ExchangeAmlFrame>
+ );
+}
+
+export const WalletLookup = tests.createExample(WalletLookupForm, {});
diff --git a/packages/taler-exchange-aml-webui/src/pages/Search.test.tsx b/packages/taler-exchange-aml-webui/src/pages/Search.test.tsx
@@ -0,0 +1,76 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import { Paytos } from "@gnu-taler/taler-util";
+import assert from "node:assert/strict";
+import test from "node:test";
+import {
+ createWalletPayto,
+ parseWalletExchangeAddress,
+ walletExchangeAddressFromBaseUrl,
+} from "./Search.js";
+
+const reservePub = "4TQZQ0M6CB0JZXJ3Z1B4H7X3EVAQXX45SB9QT0NXZYKAHQXZ3EYG";
+
+test("wallet exchange default matches the exchange payto address", () => {
+ assert.deepEqual(
+ walletExchangeAddressFromBaseUrl("https://exchange.example/exchange/"),
+ { address: "exchange.example/exchange", isHttp: false },
+ );
+ assert.deepEqual(
+ walletExchangeAddressFromBaseUrl("http://localhost:8081/exchange/"),
+ { address: "localhost:8081/exchange", isHttp: true },
+ );
+});
+
+test("wallet exchange input accepts the scheme-less base address", () => {
+ assert.ok(parseWalletExchangeAddress("exchange.example"));
+ assert.ok(parseWalletExchangeAddress("exchange.example:8443"));
+ assert.ok(parseWalletExchangeAddress("exchange.example/exchange"));
+ assert.equal(
+ parseWalletExchangeAddress("https://exchange.example/exchange/"),
+ undefined,
+ );
+ assert.equal(
+ parseWalletExchangeAddress("exchange.example/exchange/"),
+ undefined,
+ );
+
+ const payto = createWalletPayto("exchange.example", reservePub);
+ assert.ok(payto);
+ assert.equal(
+ Paytos.toFullString(payto),
+ `payto://taler-reserve/exchange.example/${reservePub}`,
+ );
+ assert.equal(
+ createWalletPayto("https://exchange.example/", reservePub),
+ undefined,
+ );
+
+ const subpathPayto = createWalletPayto(
+ "exchange.example/exchange",
+ reservePub,
+ );
+ assert.ok(subpathPayto);
+ assert.equal(
+ Paytos.toFullString(subpathPayto),
+ `payto://taler-reserve/exchange.example/exchange/${reservePub}`,
+ );
+
+ const httpPayto = createWalletPayto(
+ "localhost:8081/exchange",
+ reservePub,
+ true,
+ );
+ assert.ok(httpPayto);
+ assert.equal(
+ Paytos.toFullString(httpPayto),
+ `payto://taler-reserve-http/localhost:8081/exchange/${reservePub}`,
+ );
+});
diff --git a/packages/taler-exchange-aml-webui/src/pages/Search.tsx b/packages/taler-exchange-aml-webui/src/pages/Search.tsx
@@ -14,7 +14,6 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import {
- AbsoluteTime,
assertUnreachable,
BitcoinBech32,
encodeCrock,
@@ -41,9 +40,6 @@ import {
FormUI,
InternationalizationAPI,
Loading,
- Pagination,
- RouteDefinition,
- Time,
UIFormElementConfig,
useExchangeApiContext,
useForm,
@@ -51,11 +47,12 @@ import {
} from "@gnu-taler/web-util/browser";
import { h, VNode } from "preact";
import { useState } from "preact/hooks";
+import { useLocation } from "wouter-preact";
import { BitcoinSewgit } from "../../../taler-util/src/segwit_addr.js";
import { HandleSessionNotReady } from "../components/HandleAccountNotReady.js";
+import { useOfficerInfoContext } from "../context/officer-info.js";
import { useAccountDecisions } from "../hooks/decisions.js";
import { useOfficer } from "../hooks/officer.js";
-import { ToInvestigateIcon } from "./AccountList.js";
const TALER_SCREEN_ID = 111;
@@ -64,7 +61,7 @@ export function Search({
routeToAccountById,
}: {
onNewDecision: (account: string, payto: string) => void;
- routeToAccountById: RouteDefinition<{ cid: string }>;
+ routeToAccountById: (params: { cid: string }) => string;
}) {
const officer = useOfficer();
const { i18n } = useTranslationContext();
@@ -83,66 +80,129 @@ export function Search({
}
return (
- <div>
- <h1 class="my-2 text-3xl font-bold tracking-tight text-gray-900 ">
- <i18n.Translate>Search account</i18n.Translate>
- </h1>
+ <div class="space-y-8">
+ <header>
+ <h1 class="text-3xl font-bold tracking-tight text-gray-950 dark:text-gray-50">
+ <i18n.Translate>Find account</i18n.Translate>
+ </h1>
+ <p class="mt-2 max-w-2xl text-sm text-gray-600 dark:text-gray-300">
+ <i18n.Translate>
+ Look up an account by its payto information or normalized payto
+ hash.
+ </i18n.Translate>
+ </p>
+ </header>
+ <section aria-labelledby="find-by-payto-heading">
+ <h2
+ id="find-by-payto-heading"
+ class="text-lg font-semibold text-gray-900 dark:text-gray-100"
+ >
+ <i18n.Translate>Find by payto</i18n.Translate>
+ </h2>
+ <div class="mt-4 space-y-6">
+ <FormUI design={design} model={paytoForm.model} />
+ </div>
+ {(function () {
+ if (paytoForm.status.status !== "ok") return undefined;
+ switch (paytoForm.status.result.paytoType) {
+ case "iban":
+ return <IbanForm onSearch={setPayto} />;
+ case "generic":
+ return <GenericForm onSearch={setPayto} />;
+ case "x-taler-bank":
+ return <XTalerBankForm onSearch={setPayto} />;
+ case "wallet":
+ return <WalletForm onSearch={setPayto} />;
+ default:
+ return assertUnreachable(paytoForm.status.result.paytoType);
+ }
+ })()}
+ {!paytoUri ? undefined : (
+ <ShowResult
+ payto={paytoUri}
+ onNewDecision={onNewDecision}
+ routeToAccountById={routeToAccountById}
+ />
+ )}
+ </section>
+ <HashLookup routeToAccountById={routeToAccountById} />
+ </div>
+ );
+}
+
+function HashLookup({
+ routeToAccountById,
+}: {
+ routeToAccountById: (params: { cid: string }) => string;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ const [, navigate] = useLocation();
+ const [accountHash, setAccountHash] = useState("");
+ const normalized = accountHash.trim().toUpperCase();
+ const valid = /^[0-9A-HJKMNP-TV-Z]{52}$/.test(normalized);
+ return (
+ <details class="rounded-lg border border-gray-200 bg-gray-50 p-4 dark:border-gray-700 dark:bg-gray-900/60">
+ <summary class="min-h-11 cursor-pointer py-2 text-sm font-semibold text-primary dark:text-darkPrimary">
+ <i18n.Translate>Find by normalized payto hash</i18n.Translate>
+ </summary>
<form
- class="space-y-6"
- noValidate
- onSubmit={(e) => {
- e.preventDefault();
+ class="mt-3 max-w-2xl"
+ onSubmit={(event) => {
+ event.preventDefault();
+ if (!valid) return;
+ navigate(routeToAccountById({ cid: normalized }).replace(/^#/, ""));
}}
- autoCapitalize="none"
- autoCorrect="off"
>
- <FormUI design={design} model={paytoForm.model} />
+ <label class="block text-sm font-semibold text-gray-800 dark:text-gray-200">
+ <i18n.Translate>Normalized payto hash</i18n.Translate>
+ <input
+ name="account-hash"
+ value={accountHash}
+ onInput={(event) => setAccountHash(event.currentTarget.value)}
+ spellcheck={false}
+ autocomplete="off"
+ class="mt-1 block min-h-11 w-full rounded-md border-gray-300 bg-white font-mono text-sm text-gray-950 focus:border-primary focus:ring-primary dark:border-gray-600 dark:bg-gray-950 dark:text-gray-100"
+ />
+ </label>
+ {accountHash && !valid ? (
+ <p class="mt-2 text-sm text-red-700 dark:text-red-300">
+ <i18n.Translate>
+ Enter a valid 52-character normalized payto hash.
+ </i18n.Translate>
+ </p>
+ ) : undefined}
+ <button
+ type="submit"
+ disabled={!valid}
+ class="mt-3 min-h-11 rounded-md bg-primary px-4 py-2 text-sm font-semibold text-white hover:bg-primary/90 disabled:cursor-not-allowed disabled:bg-gray-600 disabled:text-white dark:bg-darkPrimary dark:text-gray-950 dark:disabled:bg-gray-600 dark:disabled:text-white"
+ >
+ <i18n.Translate>Open account</i18n.Translate>
+ </button>
</form>
-
- {(function () {
- if (paytoForm.status.status !== "ok") return undefined;
- switch (paytoForm.status.result.paytoType) {
- case "iban": {
- return <IbanForm onSearch={setPayto} />;
- }
- case "generic": {
- return <GenericForm onSearch={setPayto} />;
- }
- case "x-taler-bank": {
- return <XTalerBankForm onSearch={setPayto} />;
- }
- case "wallet": {
- return <WalletForm onSearch={setPayto} />;
- }
- default: {
- return assertUnreachable(paytoForm.status.result.paytoType);
- }
- }
- })()}
- {!paytoUri ? undefined : (
- <ShowResult
- payto={paytoUri}
- onNewDecision={onNewDecision}
- routeToAccountById={routeToAccountById}
- />
- )}
- </div>
+ </details>
);
}
+/*
+ * Payto-specific search forms remain below. They construct and normalize the
+ * address before the account history is queried.
+ */
+
function ShowResult({
payto,
routeToAccountById,
onNewDecision,
}: {
- routeToAccountById: RouteDefinition<{ cid: string }>;
+ routeToAccountById: (params: { cid: string }) => string;
payto: Paytos.URI;
onNewDecision: (account: string, payto: string) => void;
}): VNode {
- const paytoStr = Paytos.toNormalizedString(payto);
- const account = encodeCrock(Paytos.hashFull(paytoStr));
+ const normalizedPayto = Paytos.toNormalizedString(payto);
+ const fullPayto = Paytos.toFullString(payto);
+ const account = encodeCrock(Paytos.hashFull(normalizedPayto));
const { i18n } = useTranslationContext();
+ const officerInfo = useOfficerInfoContext();
const history = useAccountDecisions(account);
if (!history) {
@@ -193,123 +253,109 @@ function ShowResult({
}
if (history.body.length) {
+ const latest = history.body[0];
return (
- <div class="mt-8">
- <div class="mb-2">
+ <section
+ aria-labelledby="account-found-heading"
+ class="mt-8 rounded-lg border border-gray-200 bg-white p-5 shadow-sm dark:border-gray-700 dark:bg-gray-900"
+ >
+ <div class="flex flex-col gap-5 sm:flex-row sm:items-start sm:justify-between">
+ <div class="min-w-0">
+ <h2
+ id="account-found-heading"
+ class="text-lg font-semibold text-gray-950 dark:text-gray-50"
+ >
+ <i18n.Translate>Account found</i18n.Translate>
+ </h2>
+ <p class="mt-1 text-sm text-gray-600 dark:text-gray-300">
+ <i18n.Translate>
+ This account has an AML decision history. Open its case to
+ review current rules, measures, attributes, and past decisions.
+ </i18n.Translate>
+ </p>
+ </div>
<a
- href={routeToAccountById.url({
+ href={`${routeToAccountById({
cid: account,
- })}
- class="text-indigo-600 hover:text-indigo-900"
+ })}?payto=${encodeCrockForURI(fullPayto)}`}
+ class="inline-flex min-h-11 shrink-0 items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-semibold text-onPrimary hover:bg-primary/90 dark:bg-darkPrimary dark:text-darkOnPrimary"
>
- <i18n.Translate>Check account details</i18n.Translate>
+ <i18n.Translate>Open account case</i18n.Translate>
</a>
</div>
- <div class="sm:flex sm:items-center">
- <div class="sm:flex-auto">
- <div>
- <h1 class="text-base font-semibold leading-6 text-gray-900">
- <i18n.Translate>Account most recent decisions</i18n.Translate>
- </h1>
- </div>
+ <dl class="mt-5 grid gap-4 border-t border-gray-200 pt-5 text-sm dark:border-gray-700 sm:grid-cols-2">
+ <div>
+ <dt class="font-medium text-gray-600 dark:text-gray-300">
+ <i18n.Translate>Normalized payto hash</i18n.Translate>
+ </dt>
+ <dd class="mt-1 break-all font-mono text-gray-950 dark:text-gray-100">
+ {account}
+ </dd>
</div>
- </div>
-
- <div class="flow-root">
- <div class="overflow-x-auto">
- {!history.body.length ? (
- <div>empty result </div>
- ) : (
- <div class="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
- <table class="min-w-full divide-y divide-gray-300">
- <thead>
- <tr>
- <th
- scope="col"
- class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 w-80"
- >
- <i18n.Translate>When</i18n.Translate>
- </th>
- <th
- scope="col"
- class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 w-80"
- >
- <i18n.Translate>Justification</i18n.Translate>
- </th>
- <th
- scope="col"
- class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900 w-40"
- >
- <i18n.Translate>Status</i18n.Translate>
- </th>
- </tr>
- </thead>
- <tbody class="divide-y divide-gray-200 bg-white">
- {history.body.map((r, idx) => {
- return (
- <tr key={r.h_payto} class="hover:bg-gray-100 ">
- <td class="whitespace-nowrap px-3 py-5 text-sm text-gray-500 ">
- <Time
- format="dd/MM/yyyy HH:mm"
- timestamp={AbsoluteTime.fromProtocolTimestamp(
- r.decision_time,
- )}
- />
- </td>
- <td class="whitespace-nowrap px-3 py-5 text-sm text-gray-500 ">
- {r.justification}
- </td>
- <td class="whitespace-nowrap px-3 py-5 text-sm text-gray-900">
- {idx === 0 ? (
- <span class="inline-flex items-center rounded-md bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10">
- <i18n.Translate>LATEST</i18n.Translate>
- </span>
- ) : undefined}
- {r.is_active ? (
- <span class="inline-flex items-center rounded-md bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10">
- <i18n.Translate>ACTIVE</i18n.Translate>
- </span>
- ) : undefined}
- {r.to_investigate ? (
- <span title={i18n.str`Requires investigation`}>
- <ToInvestigateIcon />
- </span>
- ) : undefined}
- </td>
- </tr>
- );
- })}
- </tbody>
- </table>
- <Pagination
- onFirstPage={history.loadFirst}
- onPrevious={history.loadPrev}
- onNext={history.loadNext}
- />
- </div>
- )}
+ <div>
+ <dt class="font-medium text-gray-600 dark:text-gray-300">
+ <i18n.Translate>Payto URI</i18n.Translate>
+ </dt>
+ <dd class="mt-1 break-all font-mono text-gray-950 dark:text-gray-100">
+ {fullPayto}
+ </dd>
</div>
- </div>
- </div>
+ <div>
+ <dt class="font-medium text-gray-600 dark:text-gray-300">
+ <i18n.Translate>Current decision</i18n.Translate>
+ </dt>
+ <dd class="mt-1 text-gray-950 dark:text-gray-100">
+ {latest.is_active ? (
+ <i18n.Translate>Active</i18n.Translate>
+ ) : (
+ <i18n.Translate>No active decision</i18n.Translate>
+ )}
+ </dd>
+ </div>
+ <div>
+ <dt class="font-medium text-gray-600 dark:text-gray-300">
+ <i18n.Translate>Case status</i18n.Translate>
+ </dt>
+ <dd class="mt-1 text-gray-950 dark:text-gray-100">
+ {latest.to_investigate ? (
+ <i18n.Translate>Investigation required</i18n.Translate>
+ ) : (
+ <i18n.Translate>No investigation requested</i18n.Translate>
+ )}
+ </dd>
+ </div>
+ </dl>
+ </section>
);
}
return (
<div class="mt-4">
<Attention title={i18n.str`Account not found`} type="warning">
- <i18n.Translate>
- There is no history known for this account yet.
- </i18n.Translate>
-
+ <p>
+ <i18n.Translate>
+ There is no history known for this account yet.
+ </i18n.Translate>
+ </p>
<button
+ type="button"
+ disabled={officerInfo.read_only}
+ aria-describedby={
+ officerInfo.read_only ? "read-only-search-explanation" : undefined
+ }
onClick={async () => {
- onNewDecision(account, encodeCrockForURI(paytoStr));
+ onNewDecision(account, encodeCrockForURI(fullPayto));
}}
- class="text-indigo-600 hover:text-indigo-900"
+ class="mt-4 inline-flex min-h-11 items-center rounded-md bg-primary px-4 py-2 text-sm font-semibold text-onPrimary hover:bg-primary/90 disabled:cursor-not-allowed disabled:bg-gray-200 disabled:text-gray-700 disabled:hover:bg-gray-200 dark:bg-darkPrimary dark:text-darkOnPrimary dark:disabled:bg-gray-700 dark:disabled:text-gray-300"
>
- <i18n.Translate>
- You can make a decision for this account anyway.
- </i18n.Translate>
+ <i18n.Translate>Start a decision for this account</i18n.Translate>
</button>
+ {officerInfo.read_only ? (
+ <span id="read-only-search-explanation" class="block pt-2 text-sm">
+ <i18n.Translate>
+ Read-only officers cannot create AML decisions.
+ </i18n.Translate>
+ </span>
+ ) : undefined}
</Attention>
</div>
);
@@ -339,25 +385,24 @@ function XTalerBankForm({
);
return (
- <form
- class="space-y-6"
- noValidate
- onSubmit={(e) => {
- e.preventDefault();
- }}
- autoCapitalize="none"
- autoCorrect="off"
- >
- <FormUI design={design} model={form.model} />
+ <div class="space-y-6">
+ <FormUI
+ design={design}
+ model={form.model}
+ onSubmit={() => {
+ if (paytoUri) onSearch(paytoUri);
+ }}
+ />
<button
- disabled={form.status.status === "fail"}
- class="disabled:bg-gray-100 disabled:text-gray-500 m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
+ type="button"
+ disabled={!paytoUri}
onClick={() => onSearch(paytoUri)}
+ class="mt-4 min-h-11 w-fit rounded-md bg-primary px-4 py-2 text-sm font-semibold text-onPrimary hover:bg-primary/90 disabled:cursor-not-allowed disabled:bg-gray-200 disabled:text-gray-700 disabled:hover:bg-gray-200 dark:bg-darkPrimary dark:text-darkOnPrimary dark:disabled:bg-gray-700 dark:disabled:text-gray-300"
>
<i18n.Translate>Search</i18n.Translate>
</button>
- </form>
+ </div>
);
}
@@ -382,74 +427,70 @@ function IbanForm({
);
return (
- <form
- class="space-y-6"
- noValidate
- onSubmit={(e) => {
- e.preventDefault();
- }}
- autoCapitalize="none"
- autoCorrect="off"
- >
- <FormUI design={design} model={form.model} />
+ <div class="space-y-6">
+ <FormUI
+ design={design}
+ model={form.model}
+ onSubmit={() => {
+ if (paytoUri) onSearch(paytoUri);
+ }}
+ />
<button
- disabled={form.status.status === "fail"}
- class="disabled:bg-gray-100 disabled:text-gray-500 m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
+ type="button"
+ disabled={!paytoUri}
onClick={() => onSearch(paytoUri)}
+ class="mt-4 min-h-11 w-fit rounded-md bg-primary px-4 py-2 text-sm font-semibold text-onPrimary hover:bg-primary/90 disabled:cursor-not-allowed disabled:bg-gray-200 disabled:text-gray-700 disabled:hover:bg-gray-200 dark:bg-darkPrimary dark:text-darkOnPrimary dark:disabled:bg-gray-700 dark:disabled:text-gray-300"
>
<i18n.Translate>Search</i18n.Translate>
</button>
- </form>
+ </div>
);
}
-function WalletForm({
+export function WalletForm({
onSearch,
}: {
onSearch: (p: Paytos.URI | undefined) => void;
}): VNode {
const { i18n } = useTranslationContext();
const { config } = useExchangeApiContext();
+ const defaultExchange = walletExchangeAddressFromBaseUrl(
+ config.keys.base_url,
+ );
const design: FormDesign = {
type: "single-column",
fields: walletFields(i18n),
};
- const form = useForm<PaytoUriTalerForm>(
- design,
- {
- exchange: config.keys.base_url,
- },
- // createTalerPaytoValidator(i18n),
- );
- const pub = Paytos.parseReservePub(form.status.result.reservePub);
-
- let paytoUri = undefined;
- if (form.status.status !== "fail" && Result.isOk(pub)) {
- paytoUri = Paytos.createTalerReserve(
- form.status.result.exchange,
- pub.value,
- );
- }
+ const form = useForm<PaytoUriTalerForm>(design, {
+ exchange: defaultExchange?.address ?? "",
+ });
+ const paytoUri =
+ form.status.status === "ok"
+ ? createWalletPayto(
+ form.status.result.exchange,
+ form.status.result.reservePub,
+ defaultExchange?.isHttp ?? false,
+ )
+ : undefined;
return (
- <form
- class="space-y-6"
- noValidate
- onSubmit={(e) => {
- e.preventDefault();
- }}
- autoCapitalize="none"
- autoCorrect="off"
- >
- <FormUI design={design} model={form.model} />
+ <div class="space-y-6">
+ <FormUI
+ design={design}
+ model={form.model}
+ onSubmit={() => {
+ if (paytoUri) onSearch(paytoUri);
+ }}
+ />
<button
- disabled={form.status.status === "fail"}
- class="disabled:bg-gray-100 disabled:text-gray-500 m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
+ type="button"
+ disabled={!paytoUri}
onClick={() => onSearch(paytoUri)}
+ class="mt-4 min-h-11 w-fit rounded-md bg-primary px-4 py-2 text-sm font-semibold text-onPrimary hover:bg-primary/90 disabled:cursor-not-allowed disabled:bg-gray-200 disabled:text-gray-700 disabled:hover:bg-gray-200 dark:bg-darkPrimary dark:text-darkOnPrimary dark:disabled:bg-gray-700 dark:disabled:text-gray-300"
>
<i18n.Translate>Search</i18n.Translate>
</button>
- </form>
+ </div>
);
}
@@ -473,24 +514,23 @@ function GenericForm({
paytoUri = Result.orUndefined(Paytos.fromString(form.status.result.payto));
}
return (
- <form
- class="space-y-6"
- noValidate
- onSubmit={(e) => {
- e.preventDefault();
- }}
- autoCapitalize="none"
- autoCorrect="off"
- >
- <FormUI design={design} model={form.model} />
+ <div class="space-y-6">
+ <FormUI
+ design={design}
+ model={form.model}
+ onSubmit={() => {
+ if (paytoUri) onSearch(paytoUri);
+ }}
+ />
<button
- disabled={form.status.status === "fail"}
- class="disabled:bg-gray-100 disabled:text-gray-500 m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
+ type="button"
+ disabled={!paytoUri}
onClick={() => onSearch(paytoUri)}
+ class="mt-4 min-h-11 w-fit rounded-md bg-primary px-4 py-2 text-sm font-semibold text-onPrimary hover:bg-primary/90 disabled:cursor-not-allowed disabled:bg-gray-200 disabled:text-gray-700 disabled:hover:bg-gray-200 dark:bg-darkPrimary dark:text-darkOnPrimary dark:disabled:bg-gray-700 dark:disabled:text-gray-300"
>
<i18n.Translate>Search</i18n.Translate>
</button>
- </form>
+ </div>
);
}
@@ -512,10 +552,60 @@ interface PaytoUriTalerBankForm {
}
interface PaytoUriTalerForm {
- exchange: HostPortPath;
+ exchange: string;
reservePub: string;
}
+export function parseWalletExchangeAddress(
+ value: string,
+): HostPortPath | undefined {
+ if (
+ !value ||
+ value.trim() !== value ||
+ value.includes("://") ||
+ value.endsWith("/")
+ ) {
+ return undefined;
+ }
+ return Paytos.parseHostPortPath(value);
+}
+
+export interface WalletExchangeAddress {
+ address: string;
+ isHttp: boolean;
+}
+
+export function walletExchangeAddressFromBaseUrl(
+ baseUrl: string,
+): WalletExchangeAddress | undefined {
+ try {
+ const url = new URL(baseUrl);
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
+ return undefined;
+ }
+ const basePath = url.pathname.replace(/^\/+|\/+$/g, "");
+ return {
+ address: `${url.host}${basePath ? `/${basePath}` : ""}`,
+ isHttp: url.protocol === "http:",
+ };
+ } catch {
+ return undefined;
+ }
+}
+
+export function createWalletPayto(
+ exchangeAddress: string,
+ reservePub: string,
+ isHttp = false,
+): Paytos.URI | undefined {
+ const exchange = parseWalletExchangeAddress(exchangeAddress);
+ const pub = Paytos.parseReservePub(reservePub);
+ if (!exchange || Result.isError(pub)) return undefined;
+ return isHttp
+ ? Paytos.createTalerReserveHttp(exchange, pub.value)
+ : Paytos.createTalerReserve(exchange, pub.value);
+}
+
const paytoTypeField: (
i18n: InternationalizationAPI,
) => UIFormElementConfig[] = (i18n) => [
@@ -775,17 +865,15 @@ const walletFields: (i18n: InternationalizationAPI) => UIFormElementConfig[] = (
id: "exchange",
type: "text",
required: true,
- label: i18n.str`Host`,
- help: i18n.str`Exchange hostname`,
- placeholder: i18n.str`exchange.taler.net`,
+ label: i18n.str`Exchange address`,
+ help: i18n.str`Exchange host and optional base path, without the scheme or trailing slash`,
+ placeholder: i18n.str`exchange.taler.net/exchange`,
validator(value) {
return !value
? i18n.str`Required`
- : value.endsWith("/")
- ? i18n.str`Remove last '/'`
- : !Paytos.parseHostPortPath(value)
- ? i18n.str`Invalid value`
- : undefined;
+ : !parseWalletExchangeAddress(value)
+ ? i18n.str`Enter an exchange host and optional base path without a scheme or trailing slash`
+ : undefined;
},
},
{
diff --git a/packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.stories.tsx b/packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.stories.tsx
@@ -0,0 +1,52 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import { TalerFormAttributes } from "@gnu-taler/taler-util";
+import {
+ preloadedForms,
+ useFormMeta,
+ useTranslationContext,
+} from "@gnu-taler/web-util/browser";
+import * as tests from "@gnu-taler/web-util/testing";
+import { VNode, h } from "preact";
+import { SubmittedAttributeViews } from "./ShowCollectedInfo.js";
+
+export default { title: "collected information" };
+
+const context = {
+ tos_url: "https://exchange.demo.taler.net/terms",
+ tos_version: "exchange-tos-v4",
+ provider_name: "Taler Operations AG",
+};
+const data = {
+ [TalerFormAttributes.FORM_ID]: "accept-tos",
+ [TalerFormAttributes.FORM_VERSION]: 1,
+ [TalerFormAttributes.ACCEPTED_TERMS_OF_SERVICE]: "exchange-tos-v4",
+ [TalerFormAttributes.DOWNLOADED_TERMS_OF_SERVICE]: true,
+};
+
+function AcceptedTermsViews(): VNode {
+ const { i18n } = useTranslationContext();
+ const form = preloadedForms(i18n).find(({ id }) => id === "accept-tos")!;
+ const state = useFormMeta(form, context, data);
+ return (
+ <div class="max-w-4xl rounded-lg border border-gray-200 bg-white p-6 dark:border-gray-700 dark:bg-gray-950">
+ <h2 class="mb-4 text-lg font-semibold">Submitted values</h2>
+ <SubmittedAttributeViews
+ form={form}
+ design={state.design}
+ model={state.model}
+ context={context}
+ data={data}
+ />
+ </div>
+ );
+}
+
+export const AcceptedTerms = tests.createExample(AcceptedTermsViews, {});
diff --git a/packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.test.tsx b/packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.test.tsx
@@ -0,0 +1,190 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import { TalerFormAttributes, i18n, setupI18n } from "@gnu-taler/taler-util";
+import {
+ FormMetadata,
+ preloadedForms,
+ useFormMeta,
+} from "@gnu-taler/web-util/browser";
+import assert from "node:assert/strict";
+import test from "node:test";
+import { h, render } from "preact";
+import { SubmittedAttributeViews } from "./ShowCollectedInfo.js";
+
+setupI18n("en", {});
+
+async function eventually(assertion: () => void): Promise<void> {
+ let lastError: unknown;
+ for (let attempt = 0; attempt < 10; attempt++) {
+ try {
+ assertion();
+ return;
+ } catch (error) {
+ lastError = error;
+ await new Promise((resolve) => setTimeout(resolve, 0));
+ }
+ }
+ throw lastError;
+}
+
+async function installDom() {
+ const happyDomPackage = "happy-dom";
+ const { Window } = await import(happyDomPackage);
+ const window = new Window({ url: "https://aml.example/" });
+ for (const [key, value] of Object.entries({
+ window,
+ document: window.document,
+ navigator: window.navigator,
+ Node: window.Node,
+ Element: window.Element,
+ Event: window.Event,
+ MouseEvent: window.MouseEvent,
+ KeyboardEvent: window.KeyboardEvent,
+ HTMLElement: window.HTMLElement,
+ HTMLButtonElement: window.HTMLButtonElement,
+ HTMLInputElement: window.HTMLInputElement,
+ MutationObserver: window.MutationObserver,
+ })) {
+ Object.defineProperty(globalThis, key, {
+ configurable: true,
+ writable: true,
+ value,
+ });
+ }
+ return window;
+}
+
+const termsContext = {
+ tos_url: "https://exchange.example/terms",
+ tos_version: "terms-v7",
+ provider_name: "Example Exchange",
+};
+const termsData = {
+ [TalerFormAttributes.FORM_ID]: "accept-tos",
+ [TalerFormAttributes.FORM_VERSION]: 1,
+ [TalerFormAttributes.ACCEPTED_TERMS_OF_SERVICE]: "terms-v7",
+ [TalerFormAttributes.DOWNLOADED_TERMS_OF_SERVICE]: true,
+ attachment: {
+ ENCODING: "base64",
+ CONTENTS: "hidden-payload",
+ FILENAME: "evidence.pdf",
+ },
+};
+
+test("submitted attributes switch between officer, customer, and JSON views", async () => {
+ const window = await installDom();
+ const form = preloadedForms(i18n).find(({ id }) => id === "accept-tos");
+ assert.ok(form);
+ const acceptTosForm = form;
+
+ function Harness() {
+ const state = useFormMeta(acceptTosForm, termsContext, termsData);
+ return (
+ <SubmittedAttributeViews
+ form={acceptTosForm}
+ design={state.design}
+ model={state.model}
+ context={termsContext}
+ data={termsData}
+ />
+ );
+ }
+
+ const container = window.document.createElement("div");
+ render(<Harness />, container as unknown as Element);
+ const tabs = Array.from(
+ container.querySelectorAll('[role="tab"]'),
+ ) as HTMLButtonElement[];
+ const tab = (name: string): HTMLButtonElement => {
+ const button = tabs.find((candidate) => candidate.textContent === name);
+ assert.ok(
+ button,
+ `missing ${name}; rendered tabs: ${tabs.map((candidate) => candidate.textContent).join(", ")}`,
+ );
+ return button;
+ };
+ const officerTab = tab("Officer view");
+ const customerTab = tab("Customer view");
+ const jsonTab = tab("JSON view");
+ assert.equal(officerTab.getAttribute("aria-selected"), "true");
+ assert.match(container.textContent, /Accepted terms versionterms-v7/);
+ assert.equal(container.querySelector('[type="checkbox"]'), null);
+
+ customerTab.click();
+ await eventually(() => {
+ assert.equal(customerTab.getAttribute("aria-selected"), "true");
+ assert.ok(container.querySelector('[type="checkbox"]'));
+ });
+ const checkbox = container.querySelector(
+ '[type="checkbox"]',
+ ) as HTMLInputElement | null;
+ assert.ok(checkbox);
+ assert.equal(checkbox.disabled, true);
+
+ jsonTab.click();
+ await eventually(() => {
+ assert.equal(jsonTab.getAttribute("aria-selected"), "true");
+ assert.match(container.textContent, /"ACCEPTED_TERMS_OF_SERVICE"/);
+ });
+ assert.match(container.textContent, /\[\.\.\. skipped \.\.\.\]/);
+ assert.doesNotMatch(container.textContent, /hidden-payload/);
+
+ render(null, container as unknown as Element);
+ await window.happyDOM.abort();
+});
+
+test("forms without an officer view default to the customer form", async () => {
+ const window = await installDom();
+ const form: FormMetadata = {
+ id: "plain-form",
+ version: 1,
+ label: "Plain form",
+ config: {
+ type: "single-column",
+ fields: [{ id: "note", type: "text", label: "Note" }],
+ },
+ };
+
+ function Harness() {
+ const state = useFormMeta(form, {}, { note: "Submitted note" });
+ return (
+ <SubmittedAttributeViews
+ form={form}
+ design={state.design}
+ model={state.model}
+ context={{}}
+ data={{ note: "Submitted note" }}
+ />
+ );
+ }
+
+ const container = window.document.createElement("div");
+ render(<Harness />, container as unknown as Element);
+ const tabs = Array.from(
+ container.querySelectorAll('[role="tab"]'),
+ ) as HTMLButtonElement[];
+ assert.equal(
+ tabs.find((candidate) => candidate.textContent === "Officer view"),
+ undefined,
+ );
+ const customerTab = tabs.find(
+ (candidate) => candidate.textContent === "Customer view",
+ );
+ assert.ok(customerTab);
+ assert.equal(customerTab.getAttribute("aria-selected"), "true");
+ const textbox = container.querySelector(
+ '[type="text"]',
+ ) as HTMLInputElement | null;
+ assert.ok(textbox);
+ assert.equal(textbox.disabled, true);
+
+ render(null, container as unknown as Element);
+ await window.happyDOM.abort();
+});
diff --git a/packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx b/packages/taler-exchange-aml-webui/src/pages/ShowCollectedInfo.tsx
@@ -15,23 +15,29 @@
*/
import {
+ AbsoluteTime,
assertUnreachable,
HttpStatusCode,
TalerError,
TalerFormAttributes,
+ TranslatedString,
} from "@gnu-taler/taler-util";
import {
Attention,
ErrorLoading,
FailLoading,
- FormMetadata,
+ type FormMetadata,
+ type FormDesign,
+ type FormModel,
FormUI,
Loading,
- RouteDefinition,
+ Time,
+ redactFileContents,
useFormMeta,
useTranslationContext,
} from "@gnu-taler/web-util/browser";
-import { Fragment, h, VNode } from "preact";
+import { ComponentChildren, h, VNode } from "preact";
+import { useId, useRef, useState } from "preact/hooks";
import { useUiFormsContext } from "../context/ui-forms.js";
import { useAccountInformationAround } from "../hooks/account.js";
@@ -45,8 +51,8 @@ export function ShowCollectedInfo({
}: {
rowId: number;
account: string;
- routeToShowCollectedInfo: RouteDefinition<{ cid: string; rowId: string }>;
- routeToAccountById: RouteDefinition<{ cid: string }>;
+ routeToShowCollectedInfo: (params: { cid: string; rowId: string }) => string;
+ routeToAccountById: (params: { cid: string }) => string;
}): VNode {
const { i18n } = useTranslationContext();
const { forms } = useUiFormsContext();
@@ -103,21 +109,29 @@ export function ShowCollectedInfo({
const { event, previousId, nextId } = details.body;
if (!event) {
return (
- <Attention type="warning" title={i18n.str`Collection event not found`}>
+ <CollectionProblem
+ account={account}
+ routeToAccountById={routeToAccountById}
+ title={i18n.str`Collection event not found`}
+ >
<i18n.Translate>
There is no collection event with ID {rowId} for this account.
</i18n.Translate>
- </Attention>
+ </CollectionProblem>
);
}
if (!event.attributes) {
return (
- <Attention type="warning" title={i18n.str`Attributes unavailable`}>
+ <CollectionProblem
+ account={account}
+ routeToAccountById={routeToAccountById}
+ title={i18n.str`Attributes unavailable`}
+ >
<i18n.Translate>
The collection event does not contain readable attributes.
</i18n.Translate>
- </Attention>
+ </CollectionProblem>
);
}
const FORM_ID = event.attributes[TalerFormAttributes.FORM_ID] as
@@ -128,12 +142,16 @@ export function ShowCollectedInfo({
| undefined;
if (!FORM_ID) {
return (
- <Attention type="warning" title={i18n.str`Form identifier missing`}>
+ <CollectionProblem
+ account={account}
+ routeToAccountById={routeToAccountById}
+ title={i18n.str`Form identifier missing`}
+ >
<i18n.Translate>
The collected information does not identify the form used to create
it.
</i18n.Translate>
- </Attention>
+ </CollectionProblem>
);
}
@@ -141,11 +159,15 @@ export function ShowCollectedInfo({
if (!formsWithId.length) {
return (
- <Attention type="warning" title={i18n.str`Form not available`}>
+ <CollectionProblem
+ account={account}
+ routeToAccountById={routeToAccountById}
+ title={i18n.str`Form not available`}
+ >
<i18n.Translate>
Form {FORM_ID} is not configured in this AML Web UI.
</i18n.Translate>
- </Attention>
+ </CollectionProblem>
);
}
@@ -174,6 +196,9 @@ export function ShowCollectedInfo({
data={event.attributes ?? {}}
routeToAccountById={routeToAccountById}
expectedVersion={FORM_VERSION}
+ rowId={rowId}
+ collectionTime={AbsoluteTime.fromProtocolTimestamp(event.collection_time)}
+ byAmlOfficer={event.by_aml_officer}
previousId={previousId}
nextId={nextId}
routeToShowCollectedInfo={routeToShowCollectedInfo}
@@ -187,6 +212,9 @@ function ShowForm({
account,
routeToAccountById,
expectedVersion,
+ rowId,
+ collectionTime,
+ byAmlOfficer,
previousId,
routeToShowCollectedInfo,
nextId,
@@ -194,9 +222,12 @@ function ShowForm({
form: FormMetadata;
data: object;
account: string;
- routeToAccountById: RouteDefinition<{ cid: string }>;
+ routeToAccountById: (params: { cid: string }) => string;
expectedVersion: number | undefined;
- routeToShowCollectedInfo: RouteDefinition<{ cid: string; rowId: string }>;
+ rowId: number;
+ collectionTime: AbsoluteTime;
+ byAmlOfficer: boolean;
+ routeToShowCollectedInfo: (params: { cid: string; rowId: string }) => string;
previousId?: number;
nextId?: number;
}): VNode {
@@ -208,60 +239,277 @@ function ShowForm({
const { model, design } = useFormMeta(form, formContext, data);
return (
- <Fragment>
+ <article class="mx-auto max-w-5xl space-y-6">
+ <header class="space-y-4 border-b border-gray-200 pb-6 dark:border-gray-700">
+ <a
+ href={routeToAccountById({ cid: account })}
+ class="inline-flex min-h-10 items-center rounded-md text-sm font-semibold text-primary hover:underline dark:text-darkPrimary"
+ >
+ <span aria-hidden="true">←</span>
+ <span class="ml-2">
+ <i18n.Translate>Back to account</i18n.Translate>
+ </span>
+ </a>
+ <div>
+ <p class="text-sm font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
+ <i18n.Translate>Collected AML/KYC information</i18n.Translate>
+ </p>
+ <h1 class="mt-1 text-3xl font-bold tracking-tight text-gray-950 dark:text-gray-50">
+ {form.label}
+ </h1>
+ </div>
+ <dl class="grid gap-3 text-sm sm:grid-cols-2 lg:grid-cols-4">
+ <CollectionMetadata label={i18n.str`Form`}>
+ <code class="font-mono text-xs">
+ {form.id} · v{expectedVersion ?? form.version}
+ </code>
+ </CollectionMetadata>
+ <CollectionMetadata label={i18n.str`Collected`}>
+ <Time timestamp={collectionTime} format="dd MMM yyyy, HH:mm" />
+ </CollectionMetadata>
+ <CollectionMetadata label={i18n.str`Source`}>
+ {byAmlOfficer ? (
+ <i18n.Translate>AML officer</i18n.Translate>
+ ) : (
+ <i18n.Translate>Customer process</i18n.Translate>
+ )}
+ </CollectionMetadata>
+ <CollectionMetadata label={i18n.str`Event ID`}>
+ <code class="font-mono text-xs">{rowId}</code>
+ </CollectionMetadata>
+ </dl>
+ </header>
{differentVersion ? (
expectedVersion === undefined ? (
<Attention type="warning" title={i18n.str`Different form version`}>
<i18n.Translate>
- The collected information don't have the form version used.
+ The collected information does not identify the form version used.
+ The latest configured version is shown and field labels may differ
+ from those used at collection time.
</i18n.Translate>
</Attention>
) : (
<Attention type="warning" title={i18n.str`Different form version`}>
<i18n.Translate>
- The collected information used the form version "{expectedVersion}
- " but is not available.
+ Form version {expectedVersion} is not configured in this AML Web
+ UI. Version {form.version} is shown and field labels may differ.
</i18n.Translate>
</Attention>
)
) : undefined}
- <div class="my-4">
- <a
- href={routeToAccountById.url({ cid: account })}
- class="mt-3 inline-flex w-full items-center justify-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 sm:ml-3 sm:mt-0 sm:w-auto"
- >
- <i18n.Translate>Case details</i18n.Translate>
- </a>
- <a
+ <nav
+ aria-label={i18n.str`Collected information events`}
+ class="flex flex-wrap gap-3"
+ >
+ <EventNavigationLink
+ label={i18n.str`Older event`}
href={
previousId === undefined
? undefined
- : routeToShowCollectedInfo.url({
+ : routeToShowCollectedInfo({
cid: account,
rowId: String(previousId),
})
}
- data-disabled={previousId === undefined}
- class="mt-3 inline-flex w-full items-center justify-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 sm:ml-3 sm:mt-0 sm:w-auto data-[disabled=true]:bg-gray-500"
- >
- <i18n.Translate>Previous event</i18n.Translate>
- </a>
- <a
+ />
+ <EventNavigationLink
+ label={i18n.str`Newer event`}
href={
nextId === undefined
? undefined
- : routeToShowCollectedInfo.url({
+ : routeToShowCollectedInfo({
cid: account,
rowId: String(nextId),
})
}
- data-disabled={nextId === undefined}
- class="mt-3 inline-flex w-full items-center justify-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 sm:ml-3 sm:mt-0 sm:w-auto data-[disabled=true]:bg-gray-500"
- >
- <i18n.Translate>Next event</i18n.Translate>
- </a>
+ />
+ </nav>
+ <section class="rounded-lg border border-gray-200 bg-white p-4 dark:border-gray-700 dark:bg-gray-950 sm:p-6">
+ <h2 class="mb-4 text-lg font-semibold text-gray-950 dark:text-gray-50">
+ <i18n.Translate>Submitted values</i18n.Translate>
+ </h2>
+ <SubmittedAttributeViews
+ form={form}
+ design={design}
+ model={model}
+ context={formContext}
+ data={data as Record<string, unknown>}
+ />
+ </section>
+ </article>
+ );
+}
+
+type SubmittedAttributeView = "officer" | "customer" | "json";
+
+export function SubmittedAttributeViews({
+ form,
+ design,
+ model,
+ context,
+ data,
+}: {
+ form: FormMetadata;
+ design: FormDesign;
+ model: FormModel;
+ context: unknown;
+ data: Readonly<Record<string, unknown>>;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ const OfficerView = form.officerView;
+ const [selected, setSelected] = useState<SubmittedAttributeView>(
+ OfficerView ? "officer" : "customer",
+ );
+ const id = `submitted-attributes-${useId()}`;
+ const tabRefs = useRef<
+ Partial<Record<SubmittedAttributeView, HTMLButtonElement>>
+ >({});
+ const tabs: Array<{ id: SubmittedAttributeView; label: string }> = [
+ ...(OfficerView
+ ? [{ id: "officer" as const, label: i18n.str`Officer view` }]
+ : []),
+ { id: "customer", label: i18n.str`Customer view` },
+ { id: "json", label: i18n.str`JSON view` },
+ ];
+
+ function moveFocus(currentIndex: number, event: KeyboardEvent): void {
+ let nextIndex: number | undefined;
+ switch (event.key) {
+ case "ArrowLeft":
+ nextIndex = (currentIndex - 1 + tabs.length) % tabs.length;
+ break;
+ case "ArrowRight":
+ nextIndex = (currentIndex + 1) % tabs.length;
+ break;
+ case "Home":
+ nextIndex = 0;
+ break;
+ case "End":
+ nextIndex = tabs.length - 1;
+ break;
+ default:
+ return;
+ }
+ event.preventDefault();
+ const next = tabs[nextIndex].id;
+ setSelected(next);
+ tabRefs.current[next]?.focus();
+ }
+
+ return (
+ <div>
+ <div
+ role="tablist"
+ aria-label={i18n.str`Submitted information view`}
+ class="mb-5 flex flex-wrap gap-1 border-b border-gray-200 dark:border-gray-700"
+ >
+ {tabs.map((tab, index) => (
+ <button
+ key={tab.id}
+ ref={(element) => {
+ if (element) tabRefs.current[tab.id] = element;
+ }}
+ type="button"
+ id={`${id}-tab-${tab.id}`}
+ role="tab"
+ aria-selected={selected === tab.id}
+ aria-controls={`${id}-panel-${tab.id}`}
+ tabIndex={selected === tab.id ? 0 : -1}
+ onClick={() => setSelected(tab.id)}
+ onKeyDown={(event) => moveFocus(index, event)}
+ class="-mb-px min-h-10 border-b-2 border-transparent px-3 py-2 text-sm font-semibold text-gray-600 hover:border-gray-300 hover:text-gray-950 aria-selected:border-primary aria-selected:text-primary dark:text-gray-300 dark:hover:border-gray-600 dark:hover:text-gray-50 dark:aria-selected:border-darkPrimary dark:aria-selected:text-darkPrimary"
+ >
+ {tab.label}
+ </button>
+ ))}
+ </div>
+ <div
+ id={`${id}-panel-${selected}`}
+ role="tabpanel"
+ aria-labelledby={`${id}-tab-${selected}`}
+ >
+ {selected === "officer" && OfficerView ? (
+ <OfficerView design={design} context={context} data={data} />
+ ) : selected === "customer" ? (
+ <FormUI design={design} model={model} disabled />
+ ) : (
+ <pre class="max-h-[36rem] overflow-auto rounded-md bg-gray-950 p-4 text-xs leading-5 text-gray-100">
+ {JSON.stringify(redactFileContents(data), undefined, 2)}
+ </pre>
+ )}
</div>
- <FormUI design={design} model={model} disabled />
- </Fragment>
+ </div>
+ );
+}
+
+function CollectionMetadata({
+ label,
+ children,
+}: {
+ label: string;
+ children: ComponentChildren;
+}): VNode {
+ return (
+ <div>
+ <dt class="font-semibold text-gray-900 dark:text-gray-100">{label}</dt>
+ <dd class="mt-1 text-gray-700 dark:text-gray-300">{children}</dd>
+ </div>
+ );
+}
+
+function EventNavigationLink({
+ href,
+ label,
+}: {
+ href: string | undefined;
+ label: string;
+}): VNode {
+ if (!href) {
+ return (
+ <span
+ aria-disabled="true"
+ class="inline-flex min-h-10 items-center rounded-md border border-gray-300 px-4 py-2 text-sm font-semibold text-gray-500 dark:border-gray-700 dark:text-gray-500"
+ >
+ {label}
+ </span>
+ );
+ }
+ return (
+ <a
+ href={href}
+ class="inline-flex min-h-10 items-center rounded-md border border-outline px-4 py-2 text-sm font-semibold hover:bg-surfaceContainer focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary"
+ >
+ {label}
+ </a>
+ );
+}
+
+function CollectionProblem({
+ account,
+ routeToAccountById,
+ title,
+ children,
+}: {
+ account: string;
+ routeToAccountById: (params: { cid: string }) => string;
+ title: TranslatedString;
+ children: ComponentChildren;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ return (
+ <div class="mx-auto max-w-5xl space-y-4">
+ <a
+ href={routeToAccountById({ cid: account })}
+ class="inline-flex min-h-10 items-center rounded-md text-sm font-semibold text-primary hover:underline dark:text-darkPrimary"
+ >
+ <span aria-hidden="true">←</span>
+ <span class="ml-2">
+ <i18n.Translate>Back to account</i18n.Translate>
+ </span>
+ </a>
+ <Attention type="warning" title={title}>
+ {children}
+ </Attention>
+ </div>
);
}
diff --git a/packages/taler-exchange-aml-webui/src/pages/Transfers.stories.tsx b/packages/taler-exchange-aml-webui/src/pages/Transfers.stories.tsx
@@ -0,0 +1,241 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+import {
+ AmlDecision,
+ CustomerAccountSummary,
+ ExchangeTransferListEntry,
+ HttpStatusCode,
+ TalerExchangeHttpClient,
+ opFixedSuccess,
+ opKnownFailure,
+} from "@gnu-taler/taler-util";
+import { dummyHttpResponse } from "@gnu-taler/taler-util/http";
+import * as tests from "@gnu-taler/web-util/testing";
+import { VNode, h } from "preact";
+import { AccountCaseShell } from "../components/AccountCaseShell.js";
+import { Transfers } from "./Transfers.js";
+
+export default { title: "transfer activity page" };
+
+const account = "1111111111111111111111111111111111111111111111111111";
+const fullPayto =
+ "payto://iban/POFICHBEXXX/CH9300762011623852957?receiver-name=Example%20Trading%20AG";
+const walletFullPayto = `payto://taler-reserve/exchange.example/${"0".repeat(52)}`;
+const now = Math.floor(Date.now() / 1000);
+const timestamp = (seconds: number) => ({ t_s: seconds }) as const;
+const routeToAccountById = ({ cid }: { cid: string }) => `#/account/${cid}`;
+
+const transfers: ExchangeTransferListEntry[] = [
+ {
+ rowid: 103 as never,
+ payto_uri: fullPayto,
+ amount: "CHF:1250.50" as never,
+ execution_time: timestamp(now - 45 * 60),
+ },
+ {
+ rowid: 102 as never,
+ payto_uri:
+ "payto://x-taler-bank/bank.example/customers/alice?receiver-name=Alice",
+ amount: "CHF:48" as never,
+ execution_time: timestamp(now - 3 * 60 * 60),
+ },
+ {
+ rowid: 101 as never,
+ payto_uri: "payto://example-network/customer-42",
+ amount: "CHF:9.95" as never,
+ execution_time: timestamp(now - 26 * 60 * 60),
+ },
+ {
+ rowid: 100 as never,
+ payto_uri: "not-a-valid-payto-target",
+ amount: "CHF:1" as never,
+ execution_time: { t_s: "never" },
+ },
+];
+
+const walletCredits: ExchangeTransferListEntry[] = [
+ {
+ rowid: 203 as never,
+ payto_uri: walletFullPayto,
+ amount: "CHF:75" as never,
+ execution_time: timestamp(now - 20 * 60),
+ },
+ {
+ rowid: 202 as never,
+ payto_uri: walletFullPayto,
+ amount: "CHF:12.50" as never,
+ execution_time: timestamp(now - 4 * 60 * 60),
+ },
+];
+
+const walletDecision: AmlDecision = {
+ h_payto: account as never,
+ full_payto: walletFullPayto,
+ is_wallet: true,
+ rowid: 44 as never,
+ justification: "Wallet account confirmed for P2P monitoring.",
+ decision_time: timestamp(now - 60 * 60),
+ limits: {
+ expiration_time: { t_s: "never" },
+ rules: [],
+ custom_measures: {},
+ },
+ to_investigate: false,
+ is_active: true,
+};
+
+const bankSummary: CustomerAccountSummary = {
+ h_payto: account as never,
+ full_payto: fullPayto as never,
+ customer_label: "Example Trading Group",
+ high_risk: true,
+ comments: "Review the unusually large incoming settlement.",
+ rowid: 1042 as never,
+ open_time: timestamp(now - 30 * 24 * 60 * 60),
+ close_time: { t_s: "never" },
+ to_investigate: true,
+};
+
+const walletSummary: CustomerAccountSummary = {
+ h_payto: account as never,
+ full_payto: walletFullPayto as never,
+ customer_label: "Wallet customer",
+ high_risk: false,
+ system_note: "BELOW_ACCOUNT_OPENING_THRESHOLD",
+ rowid: 1043 as never,
+ open_time: { t_s: "never" },
+ close_time: { t_s: "never" },
+ to_investigate: false,
+};
+
+function successfulExchange(
+ records = transfers,
+): Partial<TalerExchangeHttpClient> {
+ const response = async () =>
+ opFixedSuccess(dummyHttpResponse, { transfers: records });
+ return {
+ getTransfersCredit: response,
+ getTransfersDebit: response,
+ getTransfersKycAuth: response,
+ getWalletCredit: response,
+ };
+}
+
+const props = { routeToAccountById };
+
+export const Incoming = tests.createExample(
+ Transfers,
+ { ...props, initialDirection: "credit" as const },
+ { exchange: successfulExchange() },
+);
+
+export const Outgoing = tests.createExample(
+ Transfers,
+ { ...props, initialDirection: "debit" as const },
+ { exchange: successfulExchange() },
+);
+
+export const KycAuthorization = tests.createExample(
+ Transfers,
+ { ...props, initialDirection: "kyc-auth" as const },
+ { exchange: successfulExchange() },
+);
+
+export const WalletCreditsP2P = tests.createExample(
+ Transfers,
+ { ...props, initialDirection: "wallet-credit" as const },
+ { exchange: successfulExchange(walletCredits) },
+);
+
+export const Empty = tests.createExample(Transfers, props, {
+ exchange: successfulExchange([]),
+});
+
+export const Loading = tests.createExample(Transfers, props, {
+ exchange: {
+ getTransfersCredit: async () => await new Promise<never>(() => undefined),
+ },
+});
+
+export const Failure = tests.createExample(Transfers, props, {
+ exchange: {
+ getTransfersCredit: async () =>
+ opKnownFailure(dummyHttpResponse, HttpStatusCode.Conflict),
+ },
+});
+
+function EmbeddedAccountCase(): VNode {
+ return (
+ <AccountCaseShell
+ account={account}
+ fullPayto={fullPayto}
+ activeView="transfers"
+ routeToAccounts="#/accounts"
+ routeToOverview={`#/account/${account}`}
+ routeToTransfers={`#/account/${account}/transfers`}
+ routeToHistory={`#/account/${account}/history`}
+ onNewDecision={() => undefined}
+ >
+ <Transfers
+ account={account as never}
+ embedded
+ routeToAccountById={routeToAccountById}
+ />
+ </AccountCaseShell>
+ );
+}
+
+export const EmbeddedInAccountCase = tests.createExample(
+ EmbeddedAccountCase,
+ {},
+ {
+ exchange: {
+ ...successfulExchange(),
+ getAmlAccounts: async () =>
+ opFixedSuccess(dummyHttpResponse, { accounts: [bankSummary] }),
+ getAmlDecisions: async () =>
+ opFixedSuccess(dummyHttpResponse, { records: [] }),
+ },
+ },
+);
+
+function EmbeddedWalletAccountCase(): VNode {
+ return (
+ <AccountCaseShell
+ account={account}
+ fullPayto={walletFullPayto}
+ activeView="transfers"
+ routeToAccounts="#/accounts"
+ routeToOverview={`#/account/${account}`}
+ routeToTransfers={`#/account/${account}/transfers`}
+ routeToHistory={`#/account/${account}/history`}
+ onNewDecision={() => undefined}
+ >
+ <Transfers
+ account={account as never}
+ embedded
+ routeToAccountById={routeToAccountById}
+ />
+ </AccountCaseShell>
+ );
+}
+
+export const EmbeddedWalletCredits = tests.createExample(
+ EmbeddedWalletAccountCase,
+ {},
+ {
+ exchange: {
+ ...successfulExchange(walletCredits),
+ getAmlAccounts: async () =>
+ opFixedSuccess(dummyHttpResponse, { accounts: [walletSummary] }),
+ getAmlDecisions: async () =>
+ opFixedSuccess(dummyHttpResponse, { records: [walletDecision] }),
+ },
+ },
+);
diff --git a/packages/taler-exchange-aml-webui/src/pages/Transfers.test.ts b/packages/taler-exchange-aml-webui/src/pages/Transfers.test.ts
@@ -0,0 +1,73 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+import { ExchangeTransferListEntry } from "@gnu-taler/taler-util";
+import { de, enUS } from "date-fns/locale";
+import assert from "node:assert/strict";
+import test from "node:test";
+import {
+ groupTransfersByDate,
+ transferCategoriesForAccount,
+} from "./Transfers.js";
+
+const transfer = (
+ rowid: number,
+ execution_time: ExchangeTransferListEntry["execution_time"],
+): ExchangeTransferListEntry => ({
+ rowid: rowid as never,
+ payto_uri: "payto://iban/DE89370400440532013000",
+ amount: "EUR:1" as never,
+ execution_time,
+});
+
+test("transfers are grouped under locale-aware dates", () => {
+ const records = [
+ transfer(3, { t_s: Date.UTC(2026, 7, 30, 12) / 1000 }),
+ transfer(2, { t_s: Date.UTC(2026, 7, 30, 8) / 1000 }),
+ transfer(1, { t_s: Date.UTC(2026, 7, 29, 8) / 1000 }),
+ ];
+
+ const english = groupTransfersByDate(records, enUS, "Unknown date");
+ const german = groupTransfersByDate(records, de, "Unbekanntes Datum");
+
+ assert.deepEqual(
+ english.map((group) => [group.label, group.transactions.length]),
+ [
+ ["08/30/2026", 2],
+ ["08/29/2026", 1],
+ ],
+ );
+ assert.deepEqual(
+ german.map((group) => group.label),
+ ["30.08.2026", "29.08.2026"],
+ );
+});
+
+test("unknown execution times have a visible date group", () => {
+ const groups = groupTransfersByDate(
+ [transfer(1, { t_s: "never" })],
+ enUS,
+ "Unknown date",
+ );
+ assert.equal(groups[0]?.label, "Unknown date");
+});
+
+test("transfer categories follow the account classification", () => {
+ assert.deepEqual(transferCategoriesForAccount(true), ["wallet-credit"]);
+ assert.deepEqual(transferCategoriesForAccount(false), [
+ "credit",
+ "debit",
+ "kyc-auth",
+ ]);
+ assert.deepEqual(transferCategoriesForAccount(undefined), [
+ "credit",
+ "debit",
+ "kyc-auth",
+ "wallet-credit",
+ ]);
+});
diff --git a/packages/taler-exchange-aml-webui/src/pages/Transfers.tsx b/packages/taler-exchange-aml-webui/src/pages/Transfers.tsx
@@ -18,8 +18,7 @@ import {
AmountJson,
Amounts,
assertUnreachable,
- encodeCrock,
- Paytos,
+ ExchangeTransferListEntry,
HttpStatusCode,
PaytoHash,
} from "@gnu-taler/taler-util";
@@ -32,53 +31,116 @@ import {
Loading,
Pagination,
RenderAmount,
- RouteDefinition,
Time,
useExchangeApiContext,
useForm,
useTranslationContext,
} from "@gnu-taler/web-util/browser";
-import { format } from "date-fns";
-import { Fragment, h, VNode } from "preact";
-import { useTransferList } from "../hooks/transfers.js";
-import { Profile } from "./Profile.js";
+import { format, Locale } from "date-fns";
+import { ComponentChildren, Fragment, h, VNode } from "preact";
+import { useAccountCaseContext } from "../components/AccountCaseShell.js";
+import { PaytoTargetCompact } from "../components/PaytoTargetDetails.js";
+import { TransferCategory, useTransferList } from "../hooks/transfers.js";
+
+export interface TransferDateGroup {
+ label: string;
+ transactions: ExchangeTransferListEntry[];
+}
+
+export function groupTransfersByDate(
+ transactions: ExchangeTransferListEntry[],
+ dateLocale: Locale,
+ unknownDate: string,
+): TransferDateGroup[] {
+ const groups = new Map<string, ExchangeTransferListEntry[]>();
+ for (const transaction of transactions) {
+ const label =
+ transaction.execution_time.t_s === "never"
+ ? unknownDate
+ : format(transaction.execution_time.t_s * 1000, "P", {
+ locale: dateLocale,
+ });
+ const current = groups.get(label) ?? [];
+ current.push(transaction);
+ groups.set(label, current);
+ }
+ return Array.from(groups, ([label, groupedTransactions]) => ({
+ label,
+ transactions: groupedTransactions,
+ }));
+}
+
+export function transferCategoriesForAccount(
+ targetIsWallet: boolean | undefined,
+): TransferCategory[] {
+ if (targetIsWallet === true) return ["wallet-credit"];
+ if (targetIsWallet === false) return ["credit", "debit", "kyc-auth"];
+ return ["credit", "debit", "kyc-auth", "wallet-credit"];
+}
export function Transfers({
routeToAccountById,
account,
+ embedded = false,
+ initialDirection = "credit",
}: {
- routeToAccountById: RouteDefinition<{ cid: string }>;
+ routeToAccountById: (params: { cid: string }) => string;
account?: PaytoHash;
+ embedded?: boolean;
+ initialDirection?: TransferCategory;
}): VNode {
const { i18n, dateLocale } = useTranslationContext();
const { config } = useExchangeApiContext();
+ const caseContext = useAccountCaseContext();
+ const accountCase =
+ embedded && account && caseContext?.account === account
+ ? caseContext
+ : undefined;
+ const walletOnly = accountCase?.targetIsWallet === true;
+ const bankOnly = accountCase?.targetIsWallet === false;
+ const classificationPending = accountCase?.classificationPending === true;
type FormType = {
- direction: "credit" | "debit" | "kyc-auth";
+ direction: TransferCategory;
threshold: AmountJson;
};
+ const bankCategoryChoices = [
+ {
+ label: i18n.str`Incoming`,
+ value: "credit" as const,
+ },
+ {
+ label: i18n.str`Outgoing`,
+ value: "debit" as const,
+ },
+ {
+ label: i18n.str`KYC authorization`,
+ value: "kyc-auth" as const,
+ },
+ ];
+ const availableCategories = transferCategoriesForAccount(
+ accountCase?.targetIsWallet,
+ );
+ const categoryChoices = [
+ ...bankCategoryChoices,
+ {
+ label: i18n.str`Wallet credits (P2P)`,
+ value: "wallet-credit" as const,
+ },
+ ].filter((choice) => availableCategories.includes(choice.value));
const design: FormDesign = {
type: "single-column",
fields: [
- {
- type: "choiceHorizontal",
- id: "direction",
- label: i18n.str`Direction`,
- choices: [
- {
- label: i18n.str`Credit`,
- value: "credit",
- },
- {
- label: i18n.str`Debit`,
- value: "debit",
- },
- {
- label: i18n.str`KYC Auth`,
- value: "kyc-auth",
- },
- ],
- },
+ ...(walletOnly || classificationPending
+ ? []
+ : [
+ {
+ type: "choiceHorizontal" as const,
+ id: "direction",
+ label: i18n.str`Transfer category`,
+ choices: categoryChoices,
+ },
+ ]),
{
type: "amount",
id: "threshold",
@@ -89,11 +151,16 @@ export function Transfers({
],
};
- const form = useForm<FormType>(design, { direction: "credit" });
+ const form = useForm<FormType>(design, { direction: initialDirection });
- const direction = form.status.result.direction as
+ const selectedDirection = form.status.result.direction as
| FormType["direction"]
| undefined;
+ const direction = classificationPending
+ ? undefined
+ : walletOnly
+ ? "wallet-credit"
+ : selectedDirection;
const threshold = form.status.result.threshold;
@@ -103,21 +170,94 @@ export function Transfers({
account,
});
- const theMoneyIsDirectedToTheExchange = direction === "debit";
+ const isOutgoing = direction === "debit";
+ const isWalletCredit = direction === "wallet-credit";
const searchingForAnAccount = account !== undefined;
+ const renderPage = (children: ComponentChildren): VNode => {
+ const contents = (
+ <Fragment>
+ <header class="space-y-2 border-b border-gray-200 pb-6 dark:border-gray-700">
+ {embedded ? undefined : (
+ <p class="text-sm font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
+ <i18n.Translate>Exchange transfer activity</i18n.Translate>
+ </p>
+ )}
+ {embedded ? (
+ <h2 class="text-2xl font-semibold tracking-tight text-gray-950 dark:text-gray-50">
+ {walletOnly ? (
+ <i18n.Translate>Wallet credit activity</i18n.Translate>
+ ) : (
+ <i18n.Translate>Transfer activity</i18n.Translate>
+ )}
+ </h2>
+ ) : (
+ <h1 class="text-3xl font-bold tracking-tight text-gray-950 dark:text-gray-50">
+ {searchingForAnAccount ? (
+ <i18n.Translate>Transfer activity for account</i18n.Translate>
+ ) : (
+ <i18n.Translate>Transfer activity</i18n.Translate>
+ )}
+ </h1>
+ )}
+ <p class="text-sm text-gray-600 dark:text-gray-300">
+ {walletOnly ? (
+ <i18n.Translate>
+ Inspect successful P2P credits received by this wallet. Requests
+ that were not paid are not shown.
+ </i18n.Translate>
+ ) : bankOnly ? (
+ <i18n.Translate>
+ Inspect effective bank transfers observed by the exchange.
+ Credit transfers are incoming, debit transfers are outgoing, and
+ bounced or drain transfers are not included.
+ </i18n.Translate>
+ ) : (
+ <i18n.Translate>
+ Inspect effective transfers observed by the exchange. Incoming,
+ outgoing, and KYC authorization entries are bank transfers.
+ Wallet credits are successful P2P transfers into wallets.
+ </i18n.Translate>
+ )}
+ </p>
+ {!account || embedded ? undefined : (
+ <a
+ href={routeToAccountById({ cid: account })}
+ class="inline-flex min-h-10 max-w-full items-center rounded-md text-sm font-semibold text-primary hover:underline dark:text-darkPrimary"
+ >
+ <span aria-hidden="true">←</span>
+ <span class="ml-2 break-all font-mono text-xs">{account}</span>
+ </a>
+ )}
+ </header>
+ {classificationPending ? undefined : (
+ <section aria-label={i18n.str`Transfer filters`} class="min-w-0">
+ <FormUI design={design} model={form.model} />
+ </section>
+ )}
+ {children}
+ </Fragment>
+ );
+ return embedded ? (
+ <section aria-label={i18n.str`Transfer activity`} class="space-y-6">
+ {contents}
+ </section>
+ ) : (
+ <article class="mx-auto max-w-6xl space-y-6">{contents}</article>
+ );
+ };
if (!resp) {
- return <Loading />;
+ return renderPage(<Loading />);
}
if (resp instanceof Error) {
- return (
+ return renderPage(
<ErrorLoading
title={i18n.str`Failed to load transfer list.`}
error={resp}
- />
+ />,
);
}
if (resp.type === "fail") {
- return (
+ return renderPage(
<FailLoading
operation={resp}
title={i18n.str`Failed to load the transfer list.`}
@@ -148,256 +288,212 @@ export function Transfers({
assertUnreachable(d.case);
}
}}
- />
+ />,
);
}
const transactions = resp.body;
if (!direction) {
- return (
- <>
- <FormUI design={design} model={form.model} />
+ return renderPage(
+ <Fragment>
<Attention type="low" title={i18n.str`Select transaction type`}>
<i18n.Translate>
Please select a transaction type to show transactions.
</i18n.Translate>
</Attention>
- </>
+ </Fragment>,
);
}
if (!transactions.length) {
- return (
- <div class="px-4 mt-8">
- <div class="sm:flex sm:items-center">
- <div class="sm:flex-auto">
- {searchingForAnAccount ? (
- <h1 class="text-base font-semibold leading-6 text-gray-900">
- <i18n.Translate>Transfers history for account</i18n.Translate>{" "}
- <a
- href={routeToAccountById.url({
- cid: account,
- })}
- class="text-indigo-600 hover:text-indigo-900 font-mono"
- >
- {account}
- </a>
- </h1>
- ) : (
- <h1 class="text-base font-semibold leading-6 text-gray-900">
- <i18n.Translate>Transfers history</i18n.Translate>
- </h1>
- )}
- </div>
- </div>
- <FormUI design={design} model={form.model} />
-
- <Attention type="low" title={i18n.str`No transfers yet.`}>
- {searchingForAnAccount ? (
- <i18n.Translate>
- There are no transfers for this account.
- </i18n.Translate>
- ) : (
- <i18n.Translate>
- There are no transfers reported to the exchange with the current
- threshold.
- </i18n.Translate>
- )}
- </Attention>
- </div>
+ return renderPage(
+ <Attention
+ type="low"
+ title={
+ isWalletCredit
+ ? i18n.str`No wallet credits yet.`
+ : i18n.str`No transfers yet.`
+ }
+ >
+ {isWalletCredit && searchingForAnAccount ? (
+ <i18n.Translate>
+ There are no P2P credits for this wallet.
+ </i18n.Translate>
+ ) : isWalletCredit ? (
+ <i18n.Translate>
+ There are no wallet credits reported to the exchange with the
+ current threshold.
+ </i18n.Translate>
+ ) : searchingForAnAccount ? (
+ <i18n.Translate>
+ There are no transfers for this account.
+ </i18n.Translate>
+ ) : (
+ <i18n.Translate>
+ There are no transfers reported to the exchange with the current
+ threshold.
+ </i18n.Translate>
+ )}
+ </Attention>,
);
}
- const txByDate = transactions.reduce(
- (prev, cur) => {
- const d =
- cur.execution_time.t_s === "never"
- ? ""
- : format(cur.execution_time.t_s * 1000, "dd/MM/yyyy", {
- locale: dateLocale,
- });
- if (!prev[d]) {
- prev[d] = [];
- }
- prev[d].push(cur);
- return prev;
- },
- {} as Record<string, typeof transactions>,
+ const txByDate = groupTransfersByDate(
+ transactions,
+ dateLocale,
+ i18n.str`Unknown date`,
);
- return (
- <div class="px-4 mt-8">
- <div class="sm:flex sm:items-center">
- <div class="sm:flex-auto">
- {searchingForAnAccount ? (
- <h1 class="text-base font-semibold leading-6 text-gray-900">
- <i18n.Translate>Transfers history for account</i18n.Translate>{" "}
- <a
- href={routeToAccountById.url({
- cid: account,
- })}
- class="text-indigo-600 hover:text-indigo-900 font-mono"
- >
- {account}
- </a>
- </h1>
- ) : (
- <h1 class="text-base font-semibold leading-6 text-gray-900">
- <i18n.Translate>Transfers history</i18n.Translate>
- </h1>
- )}
- </div>
- </div>
- <FormUI design={design} model={form.model} />
-
- <div class="-mx-4 mt-5 ring-1 ring-gray-300 sm:mx-0 rounded-lg min-w-fit bg-white">
- <table class="min-w-full divide-y divide-gray-300">
- <thead>
- <tr>
- <th
- scope="col"
- class="pl-2 py-3.5 text-left text-sm font-semibold text-gray-900 "
- >{i18n.str`Date`}</th>
- <th
- scope="col"
- class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900 "
- >{i18n.str`Amount`}</th>
- <th
- scope="col"
- class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900 "
- >{i18n.str`Account`}</th>
- {/* <th
+ return renderPage(
+ <div class="min-w-0 rounded-lg border border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-950">
+ <table class="w-full table-fixed divide-y divide-gray-300 dark:divide-gray-700 sm:table-auto">
+ <thead class="bg-gray-50 dark:bg-gray-900">
+ <tr>
+ <th
+ scope="col"
+ class="pl-2 py-3.5 text-left text-sm font-semibold text-gray-900 "
+ >{i18n.str`Time`}</th>
+ <th
+ scope="col"
+ class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900 "
+ >{i18n.str`Amount`}</th>
+ <th
+ scope="col"
+ class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900 "
+ >
+ {isWalletCredit ? i18n.str`Wallet` : i18n.str`Account`}
+ </th>
+ {/* <th
scope="col"
class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900 "
>{i18n.str`Subject`}</th> */}
- </tr>
- </thead>
- <tbody>
- {Object.entries(txByDate).map(([date, txs], idx) => {
- return (
- <Fragment key={idx}>
- <tr class="border-t border-gray-200">
- <th
- colSpan={4}
- scope="colgroup"
- class="bg-gray-50 py-2 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-3"
+ </tr>
+ </thead>
+ <tbody>
+ {txByDate.map(({ label, transactions: txs }) => {
+ return (
+ <Fragment key={label}>
+ <tr class="border-t border-gray-200">
+ <th
+ colSpan={3}
+ scope="colgroup"
+ class="bg-gray-50 py-2 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-3 dark:bg-gray-900 dark:text-gray-100"
+ >
+ {label}
+ </th>
+ </tr>
+ {txs.map((item) => {
+ return (
+ <tr
+ key={String(item.rowid)}
+ class="border-b border-gray-200 last:border-none"
>
- {date}
- </th>
- </tr>
- {txs.map((item, item_idx) => {
- const hashPayto = encodeCrock(
- Paytos.hashNormalized(item.payto_uri),
- );
-
- return (
- <tr
- key={item_idx}
- class="border-b border-gray-200 last:border-none"
- >
- <td class="relative py-2 pl-2 pr-2 text-sm ">
- <div class="font-medium text-gray-900">
+ <td class="relative py-2 pl-2 pr-2 text-sm ">
+ <div class="font-medium text-gray-900 dark:text-gray-100">
+ {item.execution_time.t_s === "never" ? (
+ i18n.str`Unknown time`
+ ) : (
<Time
- format="HH:mm:ss"
+ format="pp"
timestamp={AbsoluteTime.fromProtocolTimestamp(
item.execution_time,
)}
- // relative={Duration.fromSpec({ days: 1 })}
/>
- </div>
- <dl class="font-normal sm:hidden">
- <dt class="sr-only sm:hidden">
- <i18n.Translate>Amount</i18n.Translate>
- </dt>
- <dd class="mt-1 truncate text-gray-700">
- {theMoneyIsDirectedToTheExchange
+ )}
+ </div>
+ <dl class="font-normal sm:hidden">
+ <dt class="sr-only sm:hidden">
+ <i18n.Translate>Amount</i18n.Translate>
+ </dt>
+ <dd class="mt-1 text-gray-700 dark:text-gray-300">
+ {isWalletCredit
+ ? i18n.str`credited`
+ : isOutgoing
? i18n.str`sent`
: i18n.str`received`}{" "}
- {item.amount ? (
- <span
- data-negative={
- theMoneyIsDirectedToTheExchange
- ? "true"
- : "false"
- }
- class="data-[negative=false]:text-green-600 data-[negative=true]:text-red-600"
- >
- <RenderAmount
- value={Amounts.parseOrThrow(item.amount)}
- spec={config.config.currency_specification}
- />
- </span>
- ) : (
- <span class="text-grey-500">
- <{i18n.str`Invalid value`}>
- </span>
- )}
- </dd>
+ {item.amount ? (
+ <span
+ data-negative={isOutgoing ? "true" : "false"}
+ class="data-[negative=false]:text-green-600 data-[negative=true]:text-red-600"
+ >
+ <RenderAmount
+ value={Amounts.parseOrThrow(item.amount)}
+ spec={config.config.currency_specification}
+ />
+ </span>
+ ) : (
+ <span class="text-gray-500">
+ <{i18n.str`Invalid value`}>
+ </span>
+ )}
+ </dd>
- <dt class="sr-only sm:hidden">
+ <dt class="sr-only sm:hidden">
+ {isWalletCredit ? (
+ <i18n.Translate>Wallet</i18n.Translate>
+ ) : (
<i18n.Translate>Account</i18n.Translate>
- </dt>
- <dd class="mt-1 truncate text-gray-500 sm:hidden">
- <a
- href={routeToAccountById.url({
- cid: hashPayto,
- })}
- class="text-indigo-600 hover:text-indigo-900 font-mono"
- >
- {theMoneyIsDirectedToTheExchange
+ )}
+ </dt>
+ <dd class="mt-2 min-w-0 text-gray-500 sm:hidden">
+ <span class="mb-1 block text-xs">
+ {isWalletCredit
+ ? i18n.str`Wallet`
+ : isOutgoing
? i18n.str`to`
- : i18n.str`from`}{" "}
- {item.payto_uri}
- </a>
- </dd>
- {/* <dd class="mt-1 text-gray-500 sm:hidden">
+ : i18n.str`from`}
+ </span>
+ <PaytoTargetCompact
+ paytoUri={item.payto_uri}
+ routeToAccountById={routeToAccountById}
+ />
+ </dd>
+ {/* <dd class="mt-1 text-gray-500 sm:hidden">
<pre class="break-words w-56 whitespace-break-spaces p-2 rounded-md mx-auto my-2 bg-gray-100">
{item.subject}
</pre>
</dd> */}
- </dl>
- </td>
- <td
- data-negative={
- theMoneyIsDirectedToTheExchange ? "true" : "false"
- }
- class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500 "
- >
- {item.amount ? (
- <RenderAmount
- value={Amounts.parseOrThrow(item.amount)}
- negative={theMoneyIsDirectedToTheExchange}
- withColor
- spec={config.config.currency_specification}
- />
- ) : (
- <span class="text-grey-500">
- <
- {i18n.str`Invalid value`}>
- </span>
- )}
- </td>
- <td class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500">
- <a
- href={routeToAccountById.url({
- cid: hashPayto,
- })}
- class="text-indigo-600 hover:text-indigo-900 font-mono"
- >
- {item.payto_uri}
- </a>
- </td>
- </tr>
- );
- })}
- </Fragment>
- );
- })}
- </tbody>
- </table>
+ </dl>
+ </td>
+ <td
+ data-negative={isOutgoing ? "true" : "false"}
+ class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500 "
+ >
+ {item.amount ? (
+ <RenderAmount
+ value={Amounts.parseOrThrow(item.amount)}
+ negative={isOutgoing}
+ withColor
+ spec={config.config.currency_specification}
+ />
+ ) : (
+ <span class="text-gray-500">
+ <
+ {i18n.str`Invalid value`}>
+ </span>
+ )}
+ </td>
+ <td class="hidden min-w-0 px-3 py-3.5 text-sm text-gray-500 sm:table-cell">
+ <PaytoTargetCompact
+ paytoUri={item.payto_uri}
+ routeToAccountById={routeToAccountById}
+ />
+ </td>
+ </tr>
+ );
+ })}
+ </Fragment>
+ );
+ })}
+ </tbody>
+ </table>
- <Pagination onFirstPage={resp.loadFirst} onNext={resp.loadNext} />
- </div>
- </div>
+ <Pagination
+ currentPage={resp.currentPage}
+ onFirstPage={resp.loadFirst}
+ onPrevious={resp.loadPrev}
+ onNext={resp.loadNext}
+ />
+ </div>,
);
}
diff --git a/packages/taler-exchange-aml-webui/src/pages/decision/Events.test.tsx b/packages/taler-exchange-aml-webui/src/pages/decision/Events.test.tsx
@@ -0,0 +1,131 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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 assert from "node:assert/strict";
+import test from "node:test";
+import { setupI18n } from "@gnu-taler/taler-util";
+import { Fragment, h, render } from "preact";
+import {
+ DecisionRequest,
+ DecisionRequestProvider,
+ useCurrentDecisionRequest,
+} from "../../hooks/decision-request.js";
+import { ShowEventForm } from "./Events.js";
+
+setupI18n("en", {});
+
+async function installDom() {
+ const happyDomPackage = "happy-dom";
+ const { Window } = await import(happyDomPackage);
+ const window = new Window({ url: "https://aml.example/" });
+ for (const [key, value] of Object.entries({
+ window,
+ document: window.document,
+ navigator: window.navigator,
+ Node: window.Node,
+ Element: window.Element,
+ Event: window.Event,
+ MouseEvent: window.MouseEvent,
+ HTMLElement: window.HTMLElement,
+ HTMLButtonElement: window.HTMLButtonElement,
+ HTMLInputElement: window.HTMLInputElement,
+ MutationObserver: window.MutationObserver,
+ })) {
+ Object.defineProperty(globalThis, key, {
+ configurable: true,
+ writable: true,
+ value,
+ });
+ }
+ return window;
+}
+
+async function eventually(assertion: () => void): Promise<void> {
+ let lastError: unknown;
+ for (let attempt = 0; attempt < 50; attempt++) {
+ try {
+ assertion();
+ return;
+ } catch (error) {
+ lastError = error;
+ await new Promise((resolve) => setTimeout(resolve, 0));
+ }
+ }
+ throw lastError;
+}
+
+test("reset restores all derived events and preserves custom events", async () => {
+ const window = await installDom();
+ const initial: DecisionRequest = {
+ triggering_events: ["MANUAL_EVENT"],
+ custom_events: ["CUSTOM_EVENT"],
+ events_overridden: true,
+ };
+ let observed: Readonly<DecisionRequest> = initial;
+
+ function RequestObserver() {
+ [observed] = useCurrentDecisionRequest();
+ return <Fragment />;
+ }
+
+ function Harness({ showForm }: { showForm: boolean }) {
+ return (
+ <DecisionRequestProvider initial={initial}>
+ <RequestObserver />
+ {showForm ? (
+ <ShowEventForm
+ events={{
+ triggered: ["DERIVED_EVENT"],
+ rest: ["MANUAL_EVENT"],
+ }}
+ />
+ ) : undefined}
+ </DecisionRequestProvider>
+ );
+ }
+
+ const container = window.document.createElement("div");
+ window.document.body.append(container);
+ render(<Harness showForm />, container as unknown as Element);
+
+ const resetButton = (
+ Array.from(container.querySelectorAll("button")) as HTMLButtonElement[]
+ ).find((button) => button.textContent === "Reset to derived events");
+ assert.ok(resetButton);
+ resetButton.click();
+
+ await eventually(() => {
+ assert.match(container.textContent ?? "", /DERIVED_EVENT/);
+ assert.doesNotMatch(container.textContent ?? "", /MANUAL_EVENT/);
+ assert.equal(
+ (
+ Array.from(container.querySelectorAll("button")) as HTMLButtonElement[]
+ ).some((button) => button.textContent === "Reset to derived events"),
+ false,
+ );
+ });
+
+ render(<Harness showForm={false} />, container as unknown as Element);
+ await eventually(() => {
+ assert.deepEqual(observed.triggering_events, ["DERIVED_EVENT"]);
+ assert.deepEqual(observed.custom_events, ["CUSTOM_EVENT"]);
+ assert.equal(observed.events_overridden, false);
+ });
+
+ render(null, container as unknown as Element);
+ container.remove();
+ await window.happyDOM.abort();
+});
diff --git a/packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx b/packages/taler-exchange-aml-webui/src/pages/decision/Events.tsx
@@ -15,6 +15,7 @@
*/
import {
AmlDecision,
+ AmlSpaDialect,
EventsDerivation_TOPS,
TalerFormAttributes,
} from "@gnu-taler/taler-util";
@@ -24,6 +25,8 @@ import {
InternationalizationAPI,
onComponentUnload,
SelectUiChoice,
+ UIFormElementConfig,
+ useExchangeApiContext,
useForm,
useTranslationContext,
} from "@gnu-taler/web-util/browser";
@@ -32,6 +35,7 @@ import {
DecisionRequest,
useCurrentDecisionRequest,
} from "../../hooks/decision-request.js";
+import { useAmlSpaDialect } from "../../hooks/preferences.js";
const TALER_SCREEN_ID = 108;
@@ -43,29 +47,36 @@ const TALER_SCREEN_ID = 108;
*/
export function Events(): VNode {
const [request] = useCurrentDecisionRequest();
+ const { config } = useExchangeApiContext();
+ const dialect = useAmlSpaDialect(config.config.aml_spa_dialect);
- const events = calculateEventsBasedOnState(request.original, request);
+ const events = calculateEventsBasedOnState(
+ request.original,
+ request,
+ dialect,
+ );
return <ShowEventForm events={events} />;
}
-function ShowEventForm({ events: calculatedEvents }: { events: Events }) {
+export function ShowEventForm({
+ events: calculatedEvents,
+}: {
+ events: Events;
+}) {
const { i18n } = useTranslationContext();
const [request, updateRequest] = useCurrentDecisionRequest();
const design = formDesign(i18n, calculatedEvents);
- const calculated =
- request.triggering_events === undefined
+ const selected =
+ !request.events_overridden || request.triggering_events === undefined
? calculatedEvents.triggered
- : request.triggering_events.filter((name) =>
- calculatedEvents.triggered.includes(name),
- );
+ : request.triggering_events;
+
+ const calculated = selected.filter((name) =>
+ calculatedEvents.triggered.includes(name),
+ );
- const rest =
- request.triggering_events === undefined
- ? []
- : request.triggering_events.filter((name) =>
- calculatedEvents.rest.includes(name),
- );
+ const rest = selected.filter((name) => calculatedEvents.rest.includes(name));
const form = useForm<FormType>(design, {
calculated,
@@ -73,6 +84,15 @@ function ShowEventForm({ events: calculatedEvents }: { events: Events }) {
custom: (request.custom_events ?? []).map((name) => ({ name })),
});
+ const selectedBuiltIn = [
+ ...(form.status.result.calculated ?? []),
+ ...(form.status.result.rest ?? []),
+ ];
+ const hasManualOverride = !sameStringSet(
+ selectedBuiltIn,
+ calculatedEvents.triggered,
+ );
+
onComponentUnload(() => {
updateRequest("onload event", {
custom_events: Array.from(
@@ -82,15 +102,42 @@ function ShowEventForm({ events: calculatedEvents }: { events: Events }) {
.filter((name): name is string => !!name),
),
),
- triggering_events: [
- ...(form.status.result.calculated ?? []),
- ...(form.status.result.rest ?? []),
- ],
+ triggering_events: selectedBuiltIn,
+ events_overridden: hasManualOverride,
});
});
return (
- <div>
+ <div class="space-y-4">
+ <p class="mb-3 text-sm text-gray-600">
+ {hasManualOverride ? (
+ <i18n.Translate>
+ The built-in event selection differs from the events derived from
+ the proposed account state.
+ </i18n.Translate>
+ ) : (
+ <i18n.Translate>
+ Built-in events are derived from changes to the proposed account
+ properties. They are stored for reporting and statistics; they do
+ not notify the customer.
+ </i18n.Translate>
+ )}
+ </p>
+ {hasManualOverride ? (
+ <button
+ type="button"
+ onClick={() => {
+ form.update({
+ calculated: calculatedEvents.triggered,
+ rest: [],
+ custom: form.status.result.custom ?? [],
+ });
+ }}
+ class="min-h-10 rounded-md border border-outline px-4 py-2 text-sm font-semibold hover:bg-surfaceContainer focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary"
+ >
+ <i18n.Translate>Reset to derived events</i18n.Translate>
+ </button>
+ ) : undefined}
<FormUI design={design} model={form.model} />
</div>
);
@@ -113,57 +160,69 @@ const formDesign = (
triggered: string[];
rest: string[];
},
-): FormDesign => ({
- type: "double-column",
- sections: [
- {
- title: i18n.str`Events`,
- description: i18n.str`The events will be triggered only after the decision has been confirmed.`,
- fields: [
- {
- type: "selectMultiple",
- id: "calculated",
- label: i18n.str`Calculated`,
- help: i18n.str`Events based on properties and new attributes that should be triggered`,
- choices: events.triggered.map(
- (name) =>
- ({
- label: name,
- value: name,
- }) as SelectUiChoice,
- ),
- },
- {
- type: "selectMultiple",
- id: "rest",
- label: i18n.str`Others`,
- help: i18n.str`Events that can be triggered manually`,
- choices: events.rest.map(
- (name) =>
- ({
- label: name,
- value: name,
- }) as SelectUiChoice,
- ),
- },
- {
- id: "custom",
- type: "array",
- label: i18n.str`Custom list`,
- help: i18n.str`Events without built-in support.`,
- labelFieldId: "name",
- fields: [
- {
- type: "text",
- label: i18n.str`Name`,
- id: "name",
- },
- ],
- },
- ],
- },
- ],
-});
+): FormDesign => {
+ const fields: UIFormElementConfig[] = [];
+ if (events.triggered.length) {
+ fields.push({
+ type: "selectMultiple",
+ id: "calculated",
+ label: i18n.str`Calculated`,
+ help: i18n.str`Events derived from proposed property changes and submitted information.`,
+ choices: events.triggered.map(
+ (name) =>
+ ({
+ label: name,
+ value: name,
+ }) as SelectUiChoice,
+ ),
+ });
+ }
+ if (events.rest.length) {
+ fields.push({
+ type: "selectMultiple",
+ id: "rest",
+ label: i18n.str`Other built-in events`,
+ help: i18n.str`Additional events that may be recorded manually.`,
+ choices: events.rest.map(
+ (name) =>
+ ({
+ label: name,
+ value: name,
+ }) as SelectUiChoice,
+ ),
+ });
+ }
+ fields.push({
+ id: "custom",
+ type: "array",
+ label: i18n.str`Custom events`,
+ help: i18n.str`Operator-defined event names that are not part of the selected dialect.`,
+ labelFieldId: "name",
+ fields: [
+ {
+ type: "text",
+ label: i18n.str`Name`,
+ id: "name",
+ },
+ ],
+ });
+ return {
+ type: "double-column",
+ sections: [
+ {
+ title: i18n.str`Events recorded with this decision`,
+ description: i18n.str`Events are added only after the decision is successfully submitted.`,
+ fields,
+ },
+ ],
+ };
+};
+
+function sameStringSet(left: string[], right: string[]): boolean {
+ const a = Array.from(new Set(left)).sort();
+ const b = Array.from(new Set(right)).sort();
+ return a.length === b.length && a.every((value, index) => value === b[index]);
+}
// function labelForEvent_tops(
// event: TOPS_AmlEventsName,
@@ -226,12 +285,13 @@ const formDesign = (
// }
// }
-function calculateEventsBasedOnState(
+export function calculateEventsBasedOnState(
currentState: AmlDecision | undefined,
request: DecisionRequest,
- // i18n: InternationalizationAPI,
+ dialect: AmlSpaDialect,
): Events {
const init: Events = { triggered: [], rest: [] };
+ if (dialect !== AmlSpaDialect.TOPS) return init;
const form = (request.attributes?.data ?? {}) as Record<string, unknown>;
const formId = form[TalerFormAttributes.FORM_ID]! as string;
return Object.entries(EventsDerivation_TOPS).reduce((prev, [name, info]) => {
diff --git a/packages/taler-exchange-aml-webui/src/pages/decision/Information.test.ts b/packages/taler-exchange-aml-webui/src/pages/decision/Information.test.ts
@@ -0,0 +1,101 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+import { AbsoluteTime } from "@gnu-taler/taler-util";
+import { FormMetadata } from "@gnu-taler/web-util/browser";
+import assert from "node:assert/strict";
+import test from "node:test";
+import { h, render } from "preact";
+import {
+ initialAttributesExpiration,
+ latestFormsById,
+ SelectedFormMetadata,
+} from "./Information.js";
+
+function formMetadata(
+ id: string,
+ version: number,
+ description?: string,
+): FormMetadata {
+ return {
+ id,
+ version,
+ label: `${id} human-readable name`,
+ description,
+ config: { type: "single-column", fields: [] },
+ };
+}
+
+async function renderSelectedForm(form: FormMetadata) {
+ // Keep the Node-only DOM implementation out of the browser test bundle.
+ const happyDomPackage = "happy-dom";
+ const { Window } = await import(happyDomPackage);
+ const window = new Window({ url: "https://aml.example/" });
+ for (const [key, value] of Object.entries({
+ window,
+ document: window.document,
+ Node: window.Node,
+ Element: window.Element,
+ })) {
+ Object.defineProperty(globalThis, key, {
+ configurable: true,
+ writable: true,
+ value,
+ });
+ }
+ const container = window.document.createElement("div");
+ render(h(SelectedFormMetadata, { form }), container as unknown as Element);
+ return { container, window };
+}
+
+test("new customer information defaults to never expiring", () => {
+ const expiration = initialAttributesExpiration(undefined);
+ assert.equal(AbsoluteTime.isNever(expiration), true);
+});
+
+test("saved customer information expiration is preserved", () => {
+ const saved = AbsoluteTime.fromMilliseconds(Date.UTC(2030, 0, 15));
+ assert.equal(initialAttributesExpiration(saved), saved);
+});
+
+test("the form selector retains only the latest version of each form", () => {
+ const latest = latestFormsById([
+ formMetadata("identity", 1),
+ formMetadata("address", 1),
+ formMetadata("identity", 3),
+ formMetadata("identity", 2),
+ ]);
+
+ assert.deepEqual(
+ latest.map(({ id, version }) => ({ id, version })),
+ [
+ { id: "identity", version: 3 },
+ { id: "address", version: 1 },
+ ],
+ );
+});
+
+test("selected form metadata includes human and technical details", async () => {
+ const { container: view, window } = await renderSelectedForm(
+ formMetadata("identity", 3, "Use this form to verify identity."),
+ );
+ assert.match(view.textContent, /identity human-readable name/);
+ assert.match(view.textContent, /Use this form to verify identity\./);
+ assert.match(view.textContent, /identity · v3/);
+ await window.happyDOM.abort();
+});
+
+test("selected form metadata omits a missing description cleanly", async () => {
+ const { container: view, window } = await renderSelectedForm(
+ formMetadata("custom", 1),
+ );
+ assert.equal(view.querySelector("[data-form-description]"), null);
+ assert.match(view.textContent, /custom human-readable name/);
+ assert.match(view.textContent, /custom · v1/);
+ await window.happyDOM.abort();
+});
diff --git a/packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx b/packages/taler-exchange-aml-webui/src/pages/decision/Information.tsx
@@ -33,12 +33,40 @@ import {
useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { h, VNode } from "preact";
-import { useEffect, useMemo, useState } from "preact/compat";
+import { useCallback, useEffect, useMemo, useState } from "preact/compat";
import { useUiFormsContext } from "../../context/ui-forms.js";
import { useCurrentDecisionRequest } from "../../hooks/decision-request.js";
+import { ExpirationShortcuts } from "../../components/ExpirationShortcuts.js";
const TALER_SCREEN_ID = 107;
+export function initialAttributesExpiration(
+ expiration: AbsoluteTime | undefined,
+): AbsoluteTime {
+ return expiration ?? AbsoluteTime.never();
+}
+
+export function SelectedFormMetadata({ form }: { form: FormMetadata }): VNode {
+ return (
+ <div class="mt-1 min-w-0">
+ <p class="break-words text-base font-semibold text-gray-950 dark:text-gray-50">
+ {form.label}
+ </p>
+ {form.description ? (
+ <p
+ class="mt-1 text-sm leading-6 text-gray-600 dark:text-gray-300"
+ data-form-description
+ >
+ {form.description}
+ </p>
+ ) : undefined}
+ <p class="mt-2 break-all font-mono text-xs text-gray-500 dark:text-gray-400">
+ {form.id} · v{form.version}
+ </p>
+ </div>
+ );
+}
+
/**
* Mark for further investigation and explain decision
* @param param0
@@ -56,20 +84,16 @@ export function Attributes({
formByState ?? defaultForm,
);
const { forms } = useUiFormsContext();
+ const selectForm = useCallback((formId: string | undefined) => {
+ setSelectedFormId(formId);
+ }, []);
const theForm = !selectedFormId
? undefined
: findLatestVersionOfFormWithId(forms, selectedFormId);
if (!theForm) {
- return (
- <SelectForm
- forms={forms}
- onSelectForm={(f) => {
- setSelectedFormId(f);
- }}
- />
- );
+ return <SelectForm forms={forms} onSelectForm={selectForm} />;
}
return (
@@ -90,7 +114,10 @@ function FillCustomerData({
changeForm: () => void;
}): VNode {
const [request, updateRequest] = useCurrentDecisionRequest();
- const [expiration, setExpiration] = useState(request.attributes?.expiration);
+ const [expiration, setExpiration] = useState(() =>
+ initialAttributesExpiration(request.attributes?.expiration),
+ );
+ const [referenceNow] = useState(() => AbsoluteTime.now());
const formSalt = useMemo(
() =>
request.attributes?.formId === theForm.id &&
@@ -112,14 +139,34 @@ function FillCustomerData({
name: "expiration",
};
- // FIXME: What about forms with context?
- let formDesign: FormDesign = useMemo(() => {
- if (typeof theForm.config === "function") {
- return theForm.config({});
- } else {
- return theForm.config;
- }
- }, [theForm]);
+ const storedContext =
+ request.attributes?.data &&
+ TalerFormAttributes.FORM_CONTEXT in request.attributes.data
+ ? (request.attributes.data[TalerFormAttributes.FORM_CONTEXT] as object)
+ : {};
+ const emptyContextDesign: FormDesign = { type: "single-column", fields: [] };
+ const contextForm = useForm<Record<string, unknown>>(
+ theForm.contextForm ?? emptyContextDesign,
+ storedContext,
+ );
+ const [rawContext, setRawContext] = useState(() =>
+ JSON.stringify(storedContext, undefined, 2),
+ );
+ const [rawContextError, setRawContextError] = useState<string>();
+ const context = theForm.contextForm
+ ? contextForm.status.result
+ : (() => {
+ try {
+ return JSON.parse(rawContext || "{}") as Record<string, unknown>;
+ } catch {
+ return {};
+ }
+ })();
+
+ const formDesign: FormDesign =
+ typeof theForm.config === "function"
+ ? theForm.config(context)
+ : theForm.config;
/* FIXME: Should we always add FORM ID and VERSION into data? */
const form = useForm<object>(formDesign, request.attributes?.data ?? {});
@@ -129,9 +176,13 @@ function FillCustomerData({
[TalerFormAttributes.FORM_ID]: theForm.id,
[TalerFormAttributes.FORM_VERSION]: theForm.version,
[TalerFormAttributes.FORM_SALT]: formSalt,
+ [TalerFormAttributes.FORM_CONTEXT]: context,
};
- const errors = form.status.errors;
+ const errors =
+ form.status.errors ??
+ contextForm.status.errors ??
+ (rawContextError ? { FORM_CONTEXT: rawContextError } : undefined);
onComponentUnload(() => {
updateRequest("unload info", {
@@ -154,44 +205,98 @@ function FillCustomerData({
<div>
<div class="sm:flex sm:items-center">
<div class="sm:flex-auto">
- <h1 class="text-base font-semibold text-gray-900">
- <i18n.Translate>Complete the form</i18n.Translate>
- </h1>
+ <h3 class="text-base font-semibold text-gray-900 dark:text-gray-100">
+ <i18n.Translate>Add customer information</i18n.Translate>
+ </h3>
<p class="mt-2 text-sm text-gray-700">
<i18n.Translate>
- These measures will ask the customer for information.
+ The completed form is attached to this AML decision as reviewed
+ account information. It does not create a customer-facing measure.
</i18n.Translate>
</p>
</div>
</div>
- <div class="flex flex-column justify-between my-4">
- <div>
- <h1>
- Form: {theForm.id} ({theForm.version})
- </h1>
- <a
- class="text-indigo-700 cursor-pointer p-2 text-sm leading-6 font-semibold"
+ <div class="my-4 grid gap-4 lg:grid-cols-[minmax(0,1fr)_minmax(20rem,2fr)] lg:items-start">
+ <div class="min-w-0">
+ <p class="text-sm font-semibold text-gray-900 dark:text-gray-100">
+ <i18n.Translate>Selected form</i18n.Translate>
+ </p>
+ <SelectedFormMetadata form={theForm} />
+ <button
+ type="button"
+ class="mt-2 min-h-10 rounded-md border border-outline px-3 py-2 text-sm font-semibold hover:bg-surfaceContainer"
onClick={() => {
changeForm();
}}
>
- <i18n.Translate>change form</i18n.Translate>
- </a>
+ <i18n.Translate>Choose another form</i18n.Translate>
+ </button>
+ </div>
+ <div>
+ <ExpirationShortcuts
+ referenceNow={referenceNow}
+ onChange={setExpiration}
+ />
+ <InputAbsoluteTime
+ label={i18n.str`Expiration`}
+ help={i18n.str`Expiration date of the information filled in this form.`}
+ name="expiration"
+ pattern="dd/MM/yyyy"
+ handler={expirationHandler}
+ />
</div>
- <InputAbsoluteTime
- label={i18n.str`Expiration`}
- help={i18n.str`Expiration date of the information filled in this form.`}
- name="expiration"
- pattern="dd/MM/yyyy"
- handler={expirationHandler}
- />
</div>
<div>
+ {theForm.contextForm ? (
+ <div class="mb-6 rounded-lg border border-gray-200 p-4 dark:border-gray-700">
+ <h3 class="mb-2 font-semibold">
+ <i18n.Translate>Form context</i18n.Translate>
+ </h3>
+ <FormUI design={theForm.contextForm} model={contextForm.model} />
+ </div>
+ ) : (
+ <details class="mb-6 rounded-lg border border-gray-200 p-4 dark:border-gray-700">
+ <summary class="cursor-pointer text-sm font-semibold text-gray-900 dark:text-gray-100">
+ <i18n.Translate>Advanced form context</i18n.Translate>
+ </summary>
+ <p class="mt-2 text-sm text-gray-600 dark:text-gray-300">
+ <i18n.Translate>
+ Only change this operator-defined JSON when the form
+ documentation requires additional context.
+ </i18n.Translate>
+ </p>
+ <label class="mt-4 block text-sm font-medium text-gray-700 dark:text-gray-300">
+ <i18n.Translate>Context as JSON</i18n.Translate>
+ <textarea
+ class="mt-2 min-h-32 w-full rounded-md border-gray-300 font-mono text-sm dark:border-gray-700 dark:bg-gray-950"
+ value={rawContext}
+ onInput={(event) => {
+ const value = event.currentTarget.value;
+ setRawContext(value);
+ try {
+ JSON.parse(value || "{}");
+ setRawContextError(undefined);
+ } catch (error) {
+ setRawContextError(
+ error instanceof Error ? error.message : String(error),
+ );
+ }
+ }}
+ />
+ </label>
+ </details>
+ )}
+ {rawContextError ? (
+ <Attention type="danger" title={i18n.str`Invalid JSON`}>
+ {rawContextError}
+ </Attention>
+ ) : undefined}
{expirationInvalid ? (
<Attention type="danger" title={i18n.str`Invalid expiration`}>
<i18n.Translate>
- Attributes require an expiration date in the future.
+ Attributes require an expiration date in the future or set to
+ Never.
</i18n.Translate>
</Attention>
) : undefined}
@@ -221,7 +326,7 @@ function SelectForm({
useEffect(() => {
onSelectForm(fid);
- }, [fid]);
+ }, [fid, onSelectForm]);
onComponentUnload(() => {
updateRequest("unload info no form", {
@@ -248,14 +353,16 @@ const formDesign = (
sections: [
{
title: i18n.str`Include new information`,
- description: i18n.str`Select a form to submit new information about the customer or continue to the next step`,
+ description: i18n.str`This step is optional. Select a form to attach newly reviewed AML/KYC information, or continue without one.`,
fields: [
{
id: "formId",
type: "selectOne",
- label: i18n.str`Form:`,
- choices: mi.map((f) => ({
+ label: i18n.str`AML/KYC form`,
+ placeholder: i18n.str`Search AML/KYC forms`,
+ choices: latestFormsById(mi).map((f) => ({
label: f.label,
+ description: f.description,
value: f.id,
})),
},
@@ -264,6 +371,17 @@ const formDesign = (
],
});
+export function latestFormsById(forms: FormMetadata[]): FormMetadata[] {
+ const latest = new Map<string, FormMetadata>();
+ for (const form of forms) {
+ const current = latest.get(form.id);
+ if (!current || form.version > current.version) {
+ latest.set(form.id, form);
+ }
+ }
+ return Array.from(latest.values());
+}
+
function findLatestVersionOfFormWithId(
forms: FormMetadata[],
formId: string,
diff --git a/packages/taler-exchange-aml-webui/src/pages/decision/Justification.test.tsx b/packages/taler-exchange-aml-webui/src/pages/decision/Justification.test.tsx
@@ -0,0 +1,145 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import { setupI18n } from "@gnu-taler/taler-util";
+import assert from "node:assert/strict";
+import test from "node:test";
+import { Fragment, h, render } from "preact";
+import {
+ DecisionRequest,
+ DecisionRequestProvider,
+ useCurrentDecisionRequest,
+} from "../../hooks/decision-request.js";
+import {
+ initialInvestigationStatus,
+ InvestigationStatusChoice,
+ Justification,
+} from "./Justification.js";
+
+setupI18n("en", {});
+
+async function installDom() {
+ const happyDomPackage = "happy-dom";
+ const { Window } = await import(happyDomPackage);
+ const window = new Window({ url: "https://aml.example/" });
+ for (const [key, value] of Object.entries({
+ window,
+ document: window.document,
+ navigator: window.navigator,
+ Node: window.Node,
+ Element: window.Element,
+ Event: window.Event,
+ MouseEvent: window.MouseEvent,
+ HTMLElement: window.HTMLElement,
+ HTMLInputElement: window.HTMLInputElement,
+ MutationObserver: window.MutationObserver,
+ })) {
+ Object.defineProperty(globalThis, key, {
+ configurable: true,
+ writable: true,
+ value,
+ });
+ }
+ return window;
+}
+
+async function eventually(assertion: () => void): Promise<void> {
+ let lastError: unknown;
+ for (let attempt = 0; attempt < 50; attempt++) {
+ try {
+ assertion();
+ return;
+ } catch (error) {
+ lastError = error;
+ await new Promise((resolve) => setTimeout(resolve, 0));
+ }
+ }
+ throw lastError;
+}
+
+test("draft disposition takes precedence, otherwise the current status is used", () => {
+ const underInvestigation = {
+ to_investigate: true,
+ } as DecisionRequest["original"];
+ assert.equal(
+ initialInvestigationStatus({ original: underInvestigation }),
+ true,
+ );
+ assert.equal(
+ initialInvestigationStatus({
+ original: underInvestigation,
+ keep_investigating: false,
+ }),
+ false,
+ );
+ assert.equal(initialInvestigationStatus({}), false);
+});
+
+test("case disposition shows current and future status and stores the selection", async () => {
+ const window = await installDom();
+ const initial: DecisionRequest = {
+ original: { to_investigate: true } as DecisionRequest["original"],
+ justification: "Continue reviewing the account.",
+ };
+ let observed: Readonly<DecisionRequest> = initial;
+
+ function RequestObserver() {
+ [observed] = useCurrentDecisionRequest();
+ return <Fragment />;
+ }
+
+ function Harness({ showForm }: { showForm: boolean }) {
+ return (
+ <DecisionRequestProvider initial={initial}>
+ <RequestObserver />
+ {showForm ? <Justification newAccount={false} /> : undefined}
+ </DecisionRequestProvider>
+ );
+ }
+
+ const container = window.document.createElement("div");
+ window.document.body.append(container);
+ render(<Harness showForm />, container as unknown as Element);
+
+ const currentStatus = container.querySelector('[data-status="active"]');
+ assert.equal(currentStatus?.textContent, "Under investigation");
+ const choices = Array.from(
+ container.querySelectorAll('input[type="radio"]'),
+ ) as HTMLInputElement[];
+ assert.equal(choices.length, 2);
+ assert.equal(
+ choices.find((choice) => choice.value === "true")?.checked,
+ true,
+ );
+ const notInvestigating = choices.find((choice) => choice.value === "false");
+ assert.ok(notInvestigating);
+ notInvestigating.click();
+ await eventually(() => assert.equal(notInvestigating.checked, true));
+ await eventually(() => assert.equal(observed.keep_investigating, false));
+
+ render(<Harness showForm={false} />, container as unknown as Element);
+ await eventually(() => assert.equal(observed.keep_investigating, false));
+
+ render(
+ <InvestigationStatusChoice
+ current={false}
+ selected={false}
+ onChange={() => undefined}
+ />,
+ container as unknown as Element,
+ );
+ assert.equal(
+ container.querySelector('[data-status="inactive"]')?.textContent,
+ "Not under investigation",
+ );
+
+ render(null, container as unknown as Element);
+ container.remove();
+ await window.happyDOM.abort();
+});
diff --git a/packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx b/packages/taler-exchange-aml-webui/src/pages/decision/Justification.tsx
@@ -13,7 +13,6 @@
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 { PaytoString } from "@gnu-taler/taler-util";
import {
FormDesign,
FormUI,
@@ -23,7 +22,11 @@ import {
useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { h, VNode } from "preact";
-import { useCurrentDecisionRequest } from "../../hooks/decision-request.js";
+import { useId, useState } from "preact/hooks";
+import {
+ DecisionRequest,
+ useCurrentDecisionRequest,
+} from "../../hooks/decision-request.js";
const TALER_SCREEN_ID = 106;
@@ -32,23 +35,23 @@ const TALER_SCREEN_ID = 106;
* @param param0
* @returns
*/
-export function Justification({ newPayto }: { newPayto?: string }): VNode {
- const isNewAccount = !!newPayto;
-
+export function Justification({ newAccount }: { newAccount: boolean }): VNode {
const { i18n } = useTranslationContext();
const [request, updateRequest] = useCurrentDecisionRequest();
- const design = formDesign(i18n, isNewAccount);
+ const design = formDesign(i18n, newAccount);
+ const currentInvestigationStatus = request.original?.to_investigate;
+ const [investigationStatus, setInvestigationStatus] = useState(
+ initialInvestigationStatus(request),
+ );
const form = useForm<FormType>(design, {
- investigate:
- request.keep_investigating ?? request.original?.to_investigate ?? false,
justification: request.justification,
accountName: request.accountName,
});
onComponentUnload(() => {
updateRequest("unload justification", {
- keep_investigating: !!form.status.result.investigate,
+ keep_investigating: investigationStatus,
justification: form.status.result.justification ?? "",
accountName: form.status.result.accountName ?? "",
});
@@ -57,14 +60,130 @@ export function Justification({ newPayto }: { newPayto?: string }): VNode {
return (
<div>
<FormUI design={design} model={form.model} />
+ <InvestigationStatusChoice
+ current={currentInvestigationStatus}
+ selected={investigationStatus}
+ onChange={(next) => {
+ setInvestigationStatus(next);
+ updateRequest("change investigation status", {
+ keep_investigating: next,
+ });
+ }}
+ />
</div>
);
}
+export function initialInvestigationStatus(
+ request: Readonly<DecisionRequest>,
+): boolean {
+ return (
+ request.keep_investigating ?? request.original?.to_investigate ?? false
+ );
+}
+
+export function InvestigationStatusChoice({
+ current,
+ selected,
+ onChange,
+}: {
+ current: boolean | undefined;
+ selected: boolean;
+ onChange: (next: boolean) => void;
+}): VNode {
+ const { i18n } = useTranslationContext();
+ const groupName = `investigation-status-${useId()}`;
+ const helpId = `${groupName}-help`;
+ const choices = [
+ {
+ value: true,
+ label: i18n.str`Under investigation`,
+ description: i18n.str`The account will be included in the AML investigation queue.`,
+ },
+ {
+ value: false,
+ label: i18n.str`Not under investigation`,
+ description: i18n.str`The account will not be included in the AML investigation queue.`,
+ },
+ ];
+
+ return (
+ <section class="mt-6 space-y-5 border-t border-gray-200 pt-6 dark:border-gray-700">
+ <div>
+ <h2 class="text-sm font-semibold text-gray-900 dark:text-gray-100">
+ <i18n.Translate>Current investigation status</i18n.Translate>
+ </h2>
+ <p class="mt-2">
+ <span
+ data-status={
+ current === undefined
+ ? "unknown"
+ : current
+ ? "active"
+ : "inactive"
+ }
+ class="inline-flex rounded-full border px-2.5 py-1 text-sm font-semibold data-[status=active]:border-amber-300 data-[status=active]:bg-amber-50 data-[status=active]:text-amber-900 data-[status=inactive]:border-gray-300 data-[status=inactive]:bg-gray-50 data-[status=inactive]:text-gray-700 data-[status=unknown]:border-gray-300 data-[status=unknown]:bg-gray-50 data-[status=unknown]:text-gray-600 dark:data-[status=active]:border-amber-700 dark:data-[status=active]:bg-amber-950/40 dark:data-[status=active]:text-amber-200 dark:data-[status=inactive]:border-gray-600 dark:data-[status=inactive]:bg-gray-900 dark:data-[status=inactive]:text-gray-200 dark:data-[status=unknown]:border-gray-600 dark:data-[status=unknown]:bg-gray-900 dark:data-[status=unknown]:text-gray-300"
+ >
+ {current === undefined ? (
+ <i18n.Translate>No previous decision</i18n.Translate>
+ ) : current ? (
+ <i18n.Translate>Under investigation</i18n.Translate>
+ ) : (
+ <i18n.Translate>Not under investigation</i18n.Translate>
+ )}
+ </span>
+ </p>
+ </div>
+
+ <fieldset aria-describedby={helpId}>
+ <legend class="text-sm font-semibold text-gray-900 dark:text-gray-100">
+ <i18n.Translate>
+ Investigation status after this decision
+ </i18n.Translate>
+ </legend>
+ <p id={helpId} class="mt-1 text-sm text-gray-500 dark:text-gray-400">
+ <i18n.Translate>
+ Choose whether the account should remain in the AML investigation
+ queue after this decision is submitted.
+ </i18n.Translate>
+ </p>
+ <div class="mt-3 grid gap-3 sm:grid-cols-2">
+ {choices.map((choice) => {
+ const choiceId = `${groupName}-${choice.value ? "active" : "inactive"}`;
+ return (
+ <label
+ key={String(choice.value)}
+ for={choiceId}
+ data-selected={selected === choice.value}
+ class="relative cursor-pointer rounded-lg border border-gray-300 bg-white p-4 shadow-sm hover:border-primary/70 focus-within:outline focus-within:outline-2 focus-within:outline-offset-2 focus-within:outline-primary data-[selected=true]:border-primary data-[selected=true]:bg-primaryContainer/30 data-[selected=true]:ring-1 data-[selected=true]:ring-primary dark:border-gray-600 dark:bg-gray-950 dark:data-[selected=true]:border-darkPrimary dark:data-[selected=true]:bg-darkPrimaryContainer/20 dark:data-[selected=true]:ring-darkPrimary"
+ >
+ <input
+ id={choiceId}
+ type="radio"
+ name={groupName}
+ value={String(choice.value)}
+ checked={selected === choice.value}
+ onClick={() => onChange(choice.value)}
+ class="sr-only"
+ />
+ <span class="block text-sm font-semibold text-gray-900 dark:text-gray-100">
+ {choice.label}
+ </span>
+ <span class="mt-1 block text-sm text-gray-600 dark:text-gray-300">
+ {choice.description}
+ </span>
+ </label>
+ );
+ })}
+ </div>
+ </fieldset>
+ </section>
+ );
+}
+
type FormType = {
justification: string;
accountName: string;
- investigate: boolean;
measure: string;
};
@@ -75,23 +194,19 @@ const formDesign = (
type: "single-column",
fields: [
{
- id: "justification",
- type: "textArea",
- required: true,
- label: i18n.str`Justification`,
- },
- {
- id: "investigate",
- type: "toggle",
- label: i18n.str`Keep investigation?`,
- },
- {
id: "accountName",
type: "text",
label: i18n.str`Account holder`,
required: true,
- help: i18n.str`Full name of the account holder`,
+ help: i18n.str`Full name used in the payto URI when creating this previously unknown account.`,
hidden: !unknownAccount,
},
+ {
+ id: "justification",
+ type: "textArea",
+ required: true,
+ label: i18n.str`Decision rationale`,
+ help: i18n.str`Record the facts and reasoning needed to understand this decision in a later audit or review.`,
+ },
],
});
diff --git a/packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx b/packages/taler-exchange-aml-webui/src/pages/decision/Measures.tsx
@@ -40,6 +40,7 @@ import { MeasureDefinition, NewMeasure } from "../../components/NewMeasure.js";
import { useCurrentDecisionRequest } from "../../hooks/decision-request.js";
import { useServerMeasures } from "../../hooks/server-info.js";
import { computeMeasureInformation } from "../../utils/computeAvailableMesaures.js";
+import { isBuiltInSkipCheck } from "../../utils/measure-check.js";
/**
* Ask for more information, define new paths to proceed
@@ -148,6 +149,19 @@ export function Measures(): VNode {
return (
<Fragment>
+ <div class="mb-6">
+ <h3 class="text-base font-semibold text-gray-950 dark:text-gray-50">
+ <i18n.Translate>Customer actions after submission</i18n.Translate>
+ </h3>
+ <p class="mt-1 text-sm text-gray-600 dark:text-gray-300">
+ <i18n.Translate>
+ Immediate measures start as soon as this decision is accepted. A
+ measure may show information, collect customer data, or run an AML
+ program. Leave the selection empty when no immediate customer action
+ is required.
+ </i18n.Translate>
+ </p>
+ </div>
{!allMeasures.length ? undefined : (
<ActiveMeasureForm
editMeasure={(template) => {
@@ -272,7 +286,7 @@ function ActiveMeasureForm({
const measure = measures.find((candidate) => candidate.name === name);
return (
(measure?.type === "normal" || measure?.type === "verify-template") &&
- measure.measure.check_name === "SKIP"
+ isBuiltInSkipCheck(measure.measure.check_name)
);
});
@@ -313,10 +327,10 @@ function ActiveMeasureForm({
program: ver.measure.prog_name,
});
}}
- class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700 disabled:bg-gray-600"
+ class="mt-3 min-h-11 rounded-md bg-primary px-4 py-2 text-sm font-semibold text-onPrimary hover:bg-primary/90 dark:bg-darkPrimary dark:text-darkOnPrimary"
>
<i18n.Translate>
- Configure verification measure: "{ver.name}"{" "}
+ Configure verification measure “{ver.name}”
</i18n.Translate>
</button>
);
@@ -341,23 +355,29 @@ function ShowAllMeasures({
Object.keys(request?.custom_measures ?? {}).length > 0;
return (
- <div>
+ <div class="space-y-5">
<button
+ type="button"
onClick={() => {
addNewMeasure({});
}}
- class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700 disabled:bg-gray-600"
+ class="min-h-10 rounded-md bg-primary px-4 py-2 text-sm font-semibold text-onPrimary hover:bg-primary/90 dark:bg-darkPrimary dark:text-darkOnPrimary"
>
<i18n.Translate>Add custom measure</i18n.Translate>
</button>
{!haveCustomMeasures ? undefined : (
- <div class="divide-y divide-gray-200 overflow-x-scroll rounded-lg bg-white shadow-sm">
- <div class="p-2">
- <h1>
+ <section class="rounded-lg border border-gray-200 bg-white p-4 dark:border-gray-700 dark:bg-gray-950">
+ <div>
+ <h4 class="text-base font-semibold text-gray-950 dark:text-gray-50">
<i18n.Translate>Custom measures</i18n.Translate>
- </h1>
+ </h4>
+ <p class="mt-1 text-sm text-gray-600 dark:text-gray-300">
+ <i18n.Translate>
+ Measures defined only for this proposed decision.
+ </i18n.Translate>
+ </p>
</div>
- <div class="p-2">
+ <div class="mt-3">
<CurrentMeasureTable
measures={computeMeasureInformation(summary, {
measureMap: request.custom_measures,
@@ -376,17 +396,23 @@ function ShowAllMeasures({
program: m.type !== "info" ? m.programName : undefined,
});
}}
+ actionLabel={i18n.str`Edit`}
/>
</div>
- </div>
+ </section>
)}
- <div class="divide-y divide-gray-200 overflow-x-scroll rounded-lg bg-white shadow-sm">
- <div class="p-2">
- <h1>
- <i18n.Translate>Server measures</i18n.Translate>
- </h1>
- </div>
- <div class="p-2">
+ <details class="rounded-lg border border-gray-200 bg-gray-50 p-4 dark:border-gray-700 dark:bg-gray-900/60">
+ <summary class="min-h-11 cursor-pointer py-2">
+ <span class="font-semibold text-gray-950 dark:text-gray-50">
+ <i18n.Translate>Available exchange measures</i18n.Translate>
+ </span>
+ <span class="ml-2 text-sm text-gray-600 dark:text-gray-300">
+ <i18n.Translate>
+ Reusable templates configured by the exchange operator
+ </i18n.Translate>
+ </span>
+ </summary>
+ <div class="mt-3 border-t border-gray-200 pt-3 dark:border-gray-700">
<CurrentMeasureTable
measures={computeMeasureInformation(summary)}
onSelect={(m) => {
@@ -403,9 +429,10 @@ function ShowAllMeasures({
program: m.type !== "info" ? m.programName : undefined,
});
}}
+ actionLabel={i18n.str`Use as template`}
/>
</div>
- </div>
+ </details>
</div>
);
}
@@ -482,14 +509,14 @@ function formDesign(
}
}),
id: "measures",
- label: i18n.str`New measures`,
- help: i18n.str`Measures that are available/executed directly after the decision is confirmed.`,
+ label: i18n.str`Immediate measures`,
+ help: i18n.str`Selected measures begin immediately after the decision is accepted by the exchange.`,
},
{
type: "toggle",
id: "all",
- label: i18n.str`Require all measures`,
- help: i18n.str`Run all selected measures together instead of accepting any one of them.`,
+ label: i18n.str`Require every selected measure`,
+ help: i18n.str`When enabled, all selected measures must be completed. Otherwise, completing any one of them is sufficient.`,
},
],
};
diff --git a/packages/taler-exchange-aml-webui/src/pages/decision/Properties.test.ts b/packages/taler-exchange-aml-webui/src/pages/decision/Properties.test.ts
@@ -0,0 +1,31 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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 assert from "node:assert/strict";
+import test from "node:test";
+import { AmlSpaDialect, i18n, setupI18n } from "@gnu-taler/taler-util";
+import { propertiesByDialect } from "./Properties.js";
+
+setupI18n("en", {});
+
+test("TOPS account properties expose their canonical names", () => {
+ const properties = propertiesByDialect(i18n, AmlSpaDialect.TOPS);
+ assert.ok(properties.length > 0);
+ for (const property of properties) {
+ assert.ok("id" in property);
+ assert.equal(property.technicalName, property.id);
+ }
+});
diff --git a/packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx b/packages/taler-exchange-aml-webui/src/pages/decision/Properties.tsx
@@ -16,7 +16,6 @@
import {
AccountProperties,
AmlSpaDialect,
- LegitimizationRuleSet,
PropertiesDerivation_TOPS,
PropertiesDerivationFunctionByPropertyName,
TalerAmlProperties,
@@ -41,8 +40,7 @@ import {
DecisionRequest,
useCurrentDecisionRequest,
} from "../../hooks/decision-request.js";
-import { usePreferences } from "../../hooks/preferences.js";
-import { DEFAULT_LIMITS_WHEN_NEW_ACCOUNT } from "./Rules.js";
+import { useAmlSpaDialect } from "../../hooks/preferences.js";
/**
* Update account properties
@@ -52,31 +50,27 @@ import { DEFAULT_LIMITS_WHEN_NEW_ACCOUNT } from "./Rules.js";
export function Properties(): VNode {
const [request] = useCurrentDecisionRequest();
const { config } = useExchangeApiContext();
- const [pref] = usePreferences();
-
- const dialect =
- (pref.testingDialect ? undefined : config.config.aml_spa_dialect) ??
- AmlSpaDialect.TESTING;
+ const dialect = useAmlSpaDialect(config.config.aml_spa_dialect);
const calculatedProps = calculatePropertiesBasedOnState(
- request.original?.limits ?? DEFAULT_LIMITS_WHEN_NEW_ACCOUNT,
request.original?.properties ?? {},
request,
dialect,
);
- const merged = Object.entries(calculatedProps).reduce(
- (prev, [key, value]) => {
- if (prev[key] === undefined && value !== undefined) {
- prev[key] = value;
- }
- return prev;
- },
- { ...(request.properties ?? {}) },
+ const overrides = new Set(request.property_overrides ?? []);
+ const merged = Object.fromEntries(
+ Object.entries(calculatedProps).filter(
+ (entry): entry is [string, string | boolean | number | null] =>
+ entry[1] !== undefined,
+ ),
);
+ for (const [key, value] of Object.entries(request.properties ?? {})) {
+ if (overrides.has(key) || merged[key] === undefined) merged[key] = value;
+ }
return (
<div>
- <ReloadForm merged={merged} />
+ <ReloadForm calculated={calculatedProps} merged={merged} />
</div>
);
}
@@ -90,17 +84,16 @@ function officerMustCheckInvestigationState(
}
function ReloadForm({
+ calculated,
merged,
}: {
- merged: Record<string, string | boolean>;
+ calculated: Record<string, string | boolean | number | null | undefined>;
+ merged: Record<string, string | boolean | number | null>;
}): VNode {
const { i18n } = useTranslationContext();
const [request, updateRequest] = useCurrentDecisionRequest();
- const [pref] = usePreferences();
const { config } = useExchangeApiContext();
- const dialect =
- (pref.testingDialect ? undefined : config.config.aml_spa_dialect) ??
- AmlSpaDialect.TESTING;
+ const dialect = useAmlSpaDialect(config.config.aml_spa_dialect);
const design = propertiesForm(
i18n,
propertiesByDialect(i18n, dialect, {
@@ -136,8 +129,17 @@ function ReloadForm({
});
onComponentUnload(() => {
+ const defined = (form.status.result.defined ?? {}) as Record<
+ string,
+ string | boolean | number | null
+ >;
updateRequest("unload properties", {
- properties: (form.status.result.defined ?? {}) as Record<string, boolean>,
+ properties: defined,
+ property_overrides: Object.keys(defined).filter(
+ (key) =>
+ calculated[key] !== undefined &&
+ !Object.is(defined[key], calculated[key]),
+ ),
custom_properties: customRows.reduce(
(prev, cur) => {
const name = cur?.name?.trim();
@@ -154,17 +156,35 @@ function ReloadForm({
});
return (
- <div>
+ <div class="space-y-5">
+ <div>
+ <h3 class="text-base font-semibold text-gray-950 dark:text-gray-50">
+ <i18n.Translate>Review derived account properties</i18n.Translate>
+ </h3>
+ <p class="mt-1 text-sm text-gray-600 dark:text-gray-300">
+ <i18n.Translate>
+ Values may be derived from the selected AML/KYC form. Confirm them
+ against the case record and change only values that require an
+ officer override.
+ </i18n.Translate>
+ </p>
+ </div>
<button
+ type="button"
onClick={() => {
form.update({
custom: customProps,
- defined: merged,
+ defined: Object.fromEntries(
+ Object.entries(calculated).filter(
+ (entry): entry is [string, string | boolean | number | null] =>
+ entry[1] !== undefined,
+ ),
+ ),
});
}}
- class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm disabled:bg-gray-500 bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
+ class="min-h-10 rounded-md border border-outline px-4 py-2 text-sm font-semibold hover:bg-surfaceContainer focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary"
>
- <i18n.Translate>Reset to default</i18n.Translate>
+ <i18n.Translate>Reset to derived values</i18n.Translate>
</button>
{!errors ? undefined : <ErrorsSummary errors={errors.defined} />}
@@ -182,7 +202,7 @@ function ReloadForm({
}
type PropertiesForm = {
- defined: { [name: string]: string | boolean };
+ defined: { [name: string]: string | boolean | number | null };
custom: { name: string; value: string }[];
};
@@ -194,6 +214,7 @@ const propertiesForm = (
sections: [
{
title: i18n.str`Properties`,
+ description: i18n.str`Built-in property names are preserved when the decision is submitted.`,
fields: props.map((f) =>
"id" in f ? { ...f, id: "defined." + f.id } : f,
),
@@ -227,7 +248,7 @@ const propertiesForm = (
],
});
-function propertiesByDialect(
+export function propertiesByDialect(
i18n: InternationalizationAPI,
dialect: AmlSpaDialect,
options: {
@@ -235,7 +256,7 @@ function propertiesByDialect(
} = {},
): UIFormElementConfig[] {
if (dialect === AmlSpaDialect.TOPS) {
- return [
+ const properties: UIFormElementConfig[] = [
{
id: TalerAmlProperties.FILE_NOTE,
label: i18n.str`Current note on the GwG file`,
@@ -325,11 +346,13 @@ function propertiesByDialect(
id: TalerAmlProperties.SANCTION_LIST_RATING,
label: i18n.str`Score for how good the sanction list match was`,
type: "integer",
+ help: i18n.str`Integer score from 0 (no match) to 1,000,000,000 (best match).`,
},
{
id: TalerAmlProperties.SANCTION_LIST_CONFIDENCE,
label: i18n.str`Score for how much supporting data we had for the sanction list match`,
type: "integer",
+ help: i18n.str`Integer score from 0 (no supporting data) to 1,000,000,000 (highest confidence).`,
},
{
id: TalerAmlProperties.SANCTION_LIST_SUPPRESS,
@@ -338,22 +361,27 @@ function propertiesByDialect(
threeState: true,
},
];
+ return properties.map((property) =>
+ "id" in property ? { ...property, technicalName: property.id } : property,
+ );
}
return [];
}
-function calculatePropertiesBasedOnState(
- currentLimits: LegitimizationRuleSet, // FIXME: Not necessary.
+export function calculatePropertiesBasedOnState(
state: AccountProperties,
request: DecisionRequest,
dialect: AmlSpaDialect,
-): Record<UIHandlerId, string | boolean | undefined> {
+): Record<UIHandlerId, string | boolean | number | null | undefined> {
const newNewAttributes = (
request.attributes ? request.attributes.data : {}
) as Record<string, unknown>;
- type Result = Record<UIHandlerId, string | boolean | undefined>;
- const initial: Result = {};
+ type Result = Record<
+ UIHandlerId,
+ string | boolean | number | null | undefined
+ >;
+ const initial: Result = { ...state };
const formId = request.attributes?.formId;
@@ -369,11 +397,12 @@ function calculatePropertiesBasedOnState(
info: PropertiesDerivationFunctionByPropertyName<T>,
): Result {
return list.reduce((result, prop) => {
- result[prop] = info[prop].deriveProperty(
+ const derived = info[prop].deriveProperty(
FORM_ID,
newNewAttributes,
state,
);
+ if (derived !== undefined) result[prop] = derived;
return result;
}, iv);
}
@@ -387,11 +416,7 @@ function calculatePropertiesBasedOnState(
);
}
case AmlSpaDialect.TESTING: {
- return mergeProperties(
- initial,
- TOPS_AccountProperties,
- PropertiesDerivation_TOPS,
- );
+ return initial;
}
}
}
diff --git a/packages/taler-exchange-aml-webui/src/pages/decision/Rules.test.tsx b/packages/taler-exchange-aml-webui/src/pages/decision/Rules.test.tsx
@@ -0,0 +1,150 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import assert from "node:assert/strict";
+import test from "node:test";
+import { AbsoluteTime, i18n, setupI18n } from "@gnu-taler/taler-util";
+import { FormUI, useForm } from "@gnu-taler/web-util/browser";
+import { h, render } from "preact";
+import { ExpirationShortcuts } from "../../components/ExpirationShortcuts.js";
+import { ExpirationFormType, expirationFormDesignTemplate } from "./Rules.js";
+
+setupI18n("en", {});
+
+async function installDom() {
+ // Keep the Node-only DOM implementation out of the browser-oriented test
+ // bundle. It is loaded by Node when the compiled test runs.
+ const happyDomPackage = "happy-dom";
+ const { Window } = await import(happyDomPackage);
+ const window = new Window({ url: "https://aml.example/" });
+ for (const [key, value] of Object.entries({
+ window,
+ document: window.document,
+ navigator: window.navigator,
+ Node: window.Node,
+ Element: window.Element,
+ Event: window.Event,
+ MouseEvent: window.MouseEvent,
+ HTMLElement: window.HTMLElement,
+ HTMLButtonElement: window.HTMLButtonElement,
+ HTMLInputElement: window.HTMLInputElement,
+ MutationObserver: window.MutationObserver,
+ })) {
+ Object.defineProperty(globalThis, key, {
+ configurable: true,
+ writable: true,
+ value,
+ });
+ }
+ return window;
+}
+
+async function eventually(assertion: () => void): Promise<void> {
+ let lastError: unknown;
+ for (let attempt = 0; attempt < 50; attempt++) {
+ try {
+ assertion();
+ return;
+ } catch (error) {
+ lastError = error;
+ await new Promise((resolve) => setTimeout(resolve, 0));
+ }
+ }
+ throw lastError;
+}
+
+test("expiration shortcuts update the expiration form", async () => {
+ const window = await installDom();
+ const referenceNow = AbsoluteTime.fromMilliseconds(Date.UTC(2030, 0, 15, 12));
+ let expiration = AbsoluteTime.never();
+
+ function Harness() {
+ // The real screen rebuilds its design on every render. Keeping referenceNow
+ // stable prevents useForm from treating a shortcut click as a form reset.
+ const design = expirationFormDesignTemplate(i18n, [], [], referenceNow);
+ const form = useForm<ExpirationFormType>(design, {
+ expiration: AbsoluteTime.never(),
+ expirationOutcome: "defaults",
+ });
+ expiration = form.status.result.expiration as AbsoluteTime;
+ return (
+ <div>
+ <ExpirationShortcuts
+ referenceNow={referenceNow}
+ onChange={(value) =>
+ form.model.getHandlerForAttributeKey("expiration").onChange(value)
+ }
+ />
+ <FormUI design={design} model={form.model} />
+ </div>
+ );
+ }
+
+ const container = window.document.createElement("div");
+ window.document.body.append(container);
+ render(<Harness />, container as unknown as Element);
+ const buttons = Array.from(
+ container.querySelectorAll("button"),
+ ) as HTMLButtonElement[];
+ const weekButton = buttons.find(
+ (button) => button.textContent === "In a week",
+ );
+ const neverButton = buttons.find((button) => button.textContent === "Never");
+ assert.ok(weekButton);
+ assert.ok(neverButton);
+
+ weekButton.click();
+ await eventually(() =>
+ assert.equal(
+ AbsoluteTime.cmp(
+ expiration,
+ AbsoluteTime.fromMilliseconds(Date.UTC(2030, 0, 22, 12)),
+ ),
+ 0,
+ ),
+ );
+
+ neverButton.click();
+ await eventually(() => assert.equal(AbsoluteTime.isNever(expiration), true));
+
+ render(null, container as unknown as Element);
+ container.remove();
+ await window.happyDOM.abort();
+});
+
+test("successor measure choices retain descriptions and reject stale names", () => {
+ const referenceNow = AbsoluteTime.fromMilliseconds(Date.UTC(2030, 0, 15));
+ const choices = [
+ {
+ value: "configured",
+ label: "configured",
+ description: "Customer form · Collect proof of address",
+ },
+ {
+ value: "removed",
+ label: "removed",
+ description: "This measure is no longer available.",
+ },
+ ];
+ const design = expirationFormDesignTemplate(
+ i18n,
+ choices,
+ ["configured"],
+ referenceNow,
+ );
+ assert.equal(design.type, "single-column");
+ if (design.type !== "single-column") return;
+ const successor = design.fields.find(
+ (field) => "id" in field && field.id === "measure",
+ );
+ assert.ok(successor && successor.type === "selectOne");
+ assert.deepEqual(successor.choices, choices);
+ assert.equal(successor.validator?.("configured", {}), undefined);
+ assert.match(String(successor.validator?.("removed", {})), /no longer/);
+});
diff --git a/packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx b/packages/taler-exchange-aml-webui/src/pages/decision/Rules.tsx
@@ -24,13 +24,10 @@ import {
ExchangeVersionResponse,
HttpStatusCode,
KycRule,
- LegitimizationRuleSet,
LimitOperationType,
Paytos,
- PaytoType,
Result,
TalerError,
- TranslatedString,
} from "@gnu-taler/taler-util";
import {
Attention,
@@ -45,113 +42,56 @@ import {
useForm,
useTranslationContext,
} from "@gnu-taler/web-util/browser";
-import { Fragment, h, VNode } from "preact";
-import { useState } from "preact/hooks";
-import { RulesInfo } from "../../components/RulesInfo.js";
-import { ShowDecisionLimitInfo } from "../../components/ShowDecisionLimitInfo.js";
-import { ShowDefaultRules } from "../../components/ShowDefaultRules.js";
+import { ComponentChildren, Fragment, h, VNode } from "preact";
+import { useRef, useState } from "preact/hooks";
+import { isWalletPaytoType } from "../../components/AccountBadges.js";
+import { MeasureCard } from "../../components/MeasureDetails.js";
+import {
+ categoryForMeasureDefinition,
+ descriptionForMeasureDefinition,
+} from "../../components/MeasureSelection.js";
+import {
+ labelForOperationType,
+ RulesInfo,
+} from "../../components/RulesInfo.js";
+import { ExpirationShortcuts } from "../../components/ExpirationShortcuts.js";
import { useCurrentDecisionRequest } from "../../hooks/decision-request.js";
-import { usePreferences } from "../../hooks/preferences.js";
+import { useAmlSpaDialect } from "../../hooks/preferences.js";
import { useServerMeasures } from "../../hooks/server-info.js";
+import {
+ defaultRulesForAccount,
+ effectiveRuleLimits,
+} from "../../utils/rule-defaults.js";
+import {
+ applicabilityWarnings,
+ BANK_RULES,
+ deadlineIsValid,
+ INSTANT_RULES,
+ isVerbotenMeasure,
+ removeRuleAt,
+ rulesAreValid,
+ saveRuleAt,
+ WALLET_RULES,
+} from "../../utils/rule-validation.js";
-const DEFAULT_MEASURE_IF_NONE = ["VERBOTEN"];
-export const DEFAULT_LIMITS_WHEN_NEW_ACCOUNT: LegitimizationRuleSet = {
- custom_measures: {},
- expiration_time: AbsoluteTime.toProtocolTimestamp(AbsoluteTime.never()),
- rules: [],
-};
-
-const SHARED_RULES = [
- LimitOperationType.refund,
- LimitOperationType.transaction,
-];
-const ONLY_WALLET_RULES = [
- LimitOperationType.balance,
- LimitOperationType.merge,
-];
-const ONLY_BANK_RULES = [
- LimitOperationType.deposit,
- LimitOperationType.aggregate,
- LimitOperationType.withdraw,
- LimitOperationType.close,
-];
-export const WALLET_RULES = [...ONLY_WALLET_RULES, ...SHARED_RULES];
-export const BANK_RULES = [...ONLY_BANK_RULES, ...SHARED_RULES];
-
-export type RuleInconsistency =
- | "missing-wallet-rules"
- | "missing-bank-rules"
- | "shold-not-have-wallet-rules"
- | "shold-not-have-bank-rules";
-
-function findRuleInconsistency(
- isWallet: boolean,
- rules: KycRule[],
-): undefined | RuleInconsistency {
- const OPERATION_TYPE_PRESENT: Record<LimitOperationType, boolean> = {
- [LimitOperationType.balance]: false,
- [LimitOperationType.transaction]: false,
- [LimitOperationType.withdraw]: false,
- [LimitOperationType.deposit]: false,
- [LimitOperationType.aggregate]: false,
- [LimitOperationType.close]: false,
- [LimitOperationType.refund]: false,
- [LimitOperationType.merge]: false,
- };
-
- rules.forEach((r) => {
- OPERATION_TYPE_PRESENT[r.operation_type] = true;
- });
-
- if (isWallet) {
- const hasBankRule = ONLY_BANK_RULES.some(
- (otx) => OPERATION_TYPE_PRESENT[otx],
- );
- if (hasBankRule) {
- return "shold-not-have-bank-rules";
- }
- const hasAllWalletRules = WALLET_RULES.every(
- (otx) => OPERATION_TYPE_PRESENT[otx],
- );
- if (!hasAllWalletRules) {
- return "missing-wallet-rules";
- }
- } else {
- const hasWalletrule = ONLY_WALLET_RULES.some(
- (otx) => OPERATION_TYPE_PRESENT[otx],
- );
- if (hasWalletrule) {
- return "shold-not-have-wallet-rules";
- }
- const hasAllBankRules = BANK_RULES.every(
- (otx) => OPERATION_TYPE_PRESENT[otx],
- );
- if (!hasAllBankRules) {
- return "missing-bank-rules";
- }
- }
- return undefined;
-}
+export { BANK_RULES, WALLET_RULES } from "../../utils/rule-validation.js";
/**
* Defined new limits for the account
* @param param0
* @returns
*/
-export function Rules({ newPayto }: { newPayto?: string }): VNode {
+export function Rules({ fullPayto }: { fullPayto: string }): VNode {
const { i18n } = useTranslationContext();
const { config } = useExchangeApiContext();
const [request] = useCurrentDecisionRequest();
let newPaytoParsed: Paytos.URI | undefined;
const isNewAccountAWallet =
- newPayto === undefined
+ (newPaytoParsed = Result.orUndefined(Paytos.fromString(fullPayto))) ===
+ undefined
? undefined
- : (newPaytoParsed = Result.orUndefined(Paytos.fromString(newPayto))) ===
- undefined
- ? undefined
- : newPaytoParsed.targetType === PaytoType.TalerReserve ||
- newPaytoParsed.targetType === PaytoType.TalerReserveHttp;
+ : isWalletPaytoType(newPaytoParsed.targetType);
// info may be undefined if this is a new account
// for which we use the payto:// parameter
@@ -197,67 +137,40 @@ export function Rules({ newPayto }: { newPayto?: string }): VNode {
/>
);
}
- const rootMeasures = measures.body.roots;
- const defaultRules = measures.body.default_rules.filter((r) => {
- return isWallet
- ? WALLET_RULES.includes(r.operation_type)
- : BANK_RULES.includes(r.operation_type);
- });
+ const defaultRules = defaultRulesForAccount(measures.body, isWallet ?? false);
+ const currentlyApplied = effectiveRuleLimits(
+ request.original?.limits,
+ measures.body,
+ isWallet ?? false,
+ );
return (
- <div>
- <UpdateRulesForm
- rootMeasures={rootMeasures}
- defaultRules={defaultRules}
- config={config.config}
- isWallet={isWallet ?? false}
- limits={request.original?.limits ?? DEFAULT_LIMITS_WHEN_NEW_ACCOUNT}
- />
-
- <div>
- <h2 class="mt-4 mb-2">
- <i18n.Translate>Current active rules</i18n.Translate>
- </h2>
- {request.original === undefined ? (
- <Fragment>
- <p>
- <i18n.Translate>
- There are no rules for this account yet.
- </i18n.Translate>
- </p>
- <ShowDefaultRules rules={defaultRules} />
- </Fragment>
- ) : (
- <ShowDecisionLimitInfo
- fixed
- since={AbsoluteTime.fromProtocolTimestamp(
- request.original.decision_time,
- )}
- until={AbsoluteTime.fromProtocolTimestamp(
- request.original.limits.expiration_time,
- )}
- rules={request.original.limits.rules}
- startOpen
- measure={request.original.limits.successor_measure ?? ""}
- />
- )}
- </div>
- </div>
+ <UpdateRulesForm
+ measureSummary={measures.body}
+ defaultRules={defaultRules}
+ config={config.config}
+ isWallet={isWallet ?? false}
+ limits={currentlyApplied}
+ />
);
}
-function AddNewRuleForm({
- onAdd,
+function RuleEditor({
+ onSave,
onClose,
config,
measureList,
isWallet,
+ initial,
+ editing,
}: {
- onAdd: (nr: RuleFormType) => void;
+ onSave: (nr: RuleFormType) => void;
config: ExchangeVersionResponse;
measureList: string[];
onClose: () => void;
isWallet: boolean;
+ initial?: Partial<RuleFormType>;
+ editing: boolean;
}): VNode {
const { i18n } = useTranslationContext();
const ruleFormDesign = ruleFormDesignTemplate(
@@ -267,355 +180,536 @@ function AddNewRuleForm({
isWallet,
);
- const ruleForm = useForm<RuleFormType>(ruleFormDesign, {});
+ const ruleForm = useForm<RuleFormType>(ruleFormDesign, {
+ display_priority: 0,
+ ...initial,
+ });
return (
- <Fragment>
- <h2 class="mt-4 mb-2">
- <i18n.Translate>New rule form</i18n.Translate>
- </h2>
+ <div class="my-4 rounded-lg border border-gray-300 bg-gray-50 p-4">
+ <h3 class="mb-3 text-base font-semibold">
+ {editing ? (
+ <i18n.Translate>Edit proposed rule</i18n.Translate>
+ ) : (
+ <i18n.Translate>Add proposed rule</i18n.Translate>
+ )}
+ </h3>
<FormUI design={ruleFormDesign} model={ruleForm.model} />
-
- <button
- disabled={ruleForm.status.status === "fail"}
- onClick={() => {
- onAdd(ruleForm.status.result as RuleFormType);
- onClose();
- }}
- class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700 disabled:bg-gray-600"
- >
- <i18n.Translate>Add</i18n.Translate>
- </button>
- <button
- onClick={() => {
- onClose();
- }}
- class="relative disabled:bg-gray-100 disabled:text-gray-500 ml-3 inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus-visible:outline-offset-0"
- >
- <i18n.Translate>Cancel</i18n.Translate>
- </button>
- </Fragment>
+ <div class="mt-4 flex justify-end gap-3">
+ <button
+ type="button"
+ onClick={onClose}
+ class="rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50"
+ >
+ <i18n.Translate>Cancel</i18n.Translate>
+ </button>
+ <button
+ type="button"
+ disabled={ruleForm.status.status === "fail"}
+ onClick={() => onSave(ruleForm.status.result as RuleFormType)}
+ class="rounded-md bg-indigo-700 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-600 disabled:cursor-not-allowed disabled:bg-gray-500"
+ >
+ {editing ? (
+ <i18n.Translate>Save rule</i18n.Translate>
+ ) : (
+ <i18n.Translate>Add rule</i18n.Translate>
+ )}
+ </button>
+ </div>
+ </div>
);
}
+type RuleEditorState = { index?: number; initial?: Partial<RuleFormType> };
+type Replacement =
+ | "current"
+ | "defaults"
+ | "freeze"
+ | "basic"
+ | "premium"
+ | "ecommerce"
+ | "pos";
+
function UpdateRulesForm({
config,
limits,
- rootMeasures,
+ measureSummary,
defaultRules,
isWallet,
}: {
config: ExchangeVersionResponse;
- limits: LegitimizationRuleSet;
+ limits: ReturnType<typeof effectiveRuleLimits>;
isWallet: boolean | undefined;
- rootMeasures: AvailableMeasureSummary["roots"] | undefined;
+ measureSummary: AvailableMeasureSummary;
defaultRules: KycRule[];
}): VNode {
- const { i18n } = useTranslationContext();
- const [pref] = usePreferences();
- const dialect =
- (pref.testingDialect ? undefined : config.aml_spa_dialect) ??
- AmlSpaDialect.TESTING;
+ const { i18n, lang } = useTranslationContext();
+ const dialect = useAmlSpaDialect(config.aml_spa_dialect);
const [request, updateRequest] = useCurrentDecisionRequest();
- const [showAddRuleForm, setShowAddRuleForm] = useState(false);
- const measureList = !rootMeasures ? [] : Object.keys(rootMeasures);
- const customMeasures = Object.keys(request.custom_measures ?? {});
- const allMeasure = [...measureList, ...customMeasures];
- const expirationFormDesign = expirationFormDesignTemplate(i18n, allMeasure);
+ const [editor, setEditor] = useState<RuleEditorState>();
+ const [pendingRemove, setPendingRemove] = useState<number>();
+ const [pendingReplacement, setPendingReplacement] = useState<Replacement>();
+ const addButtonRef = useRef<HTMLButtonElement>(null);
+ const configuredMeasures = {
+ ...measureSummary.roots,
+ ...(request.custom_measures ?? {}),
+ };
+ const allMeasure = Object.keys(configuredMeasures);
const [currentRules, setRules] = useState<KycRule[]>(
- !request.rules ? limits.rules : request.rules,
+ request.rules ?? limits.rules,
);
- let defaultSuccessorMeasure =
+ const [referenceNow] = useState(() => AbsoluteTime.now());
+ const proposedSuccessorMeasure =
request.onExpire_measure ?? limits.successor_measure;
-
- if (
- defaultSuccessorMeasure &&
- !allMeasure.includes(defaultSuccessorMeasure)
- ) {
- console.warn(
- `configuration problem: default successor measure ${defaultSuccessorMeasure} not in known measures`,
- );
- defaultSuccessorMeasure = undefined;
- }
+ const successorMeasureNames =
+ proposedSuccessorMeasure && !allMeasure.includes(proposedSuccessorMeasure)
+ ? [...allMeasure, proposedSuccessorMeasure]
+ : allMeasure;
+ const successorChoices = successorMeasureNames.map((name) => {
+ const measure = configuredMeasures[name];
+ return {
+ value: name,
+ label: name,
+ description: measure
+ ? descriptionForMeasureDefinition(measure, measureSummary, lang, i18n)
+ : i18n.str`This measure is no longer available.`,
+ };
+ });
+ const expirationFormDesign = expirationFormDesignTemplate(
+ i18n,
+ successorChoices,
+ allMeasure,
+ referenceNow,
+ );
const expirationForm = useForm<ExpirationFormType>(expirationFormDesign, {
expiration:
request.deadline ??
AbsoluteTime.fromProtocolTimestamp(limits.expiration_time),
- measure: defaultSuccessorMeasure,
+ expirationOutcome: proposedSuccessorMeasure ? "measure" : "defaults",
+ measure: proposedSuccessorMeasure,
});
+ const selectedSuccessorName = expirationForm.status.result.measure;
+ const selectedSuccessor = selectedSuccessorName
+ ? configuredMeasures[selectedSuccessorName]
+ : undefined;
+ const showSuccessor =
+ expirationForm.status.result.expirationOutcome === "measure" &&
+ !!expirationForm.status.result.expiration &&
+ !AbsoluteTime.isNever(
+ expirationForm.status.result.expiration as AbsoluteTime,
+ );
onComponentUnload(() => {
const deadline =
expirationForm.status.status === "fail"
? undefined
: expirationForm.status.result.expiration;
+ const result = expirationForm.status.result;
const doesntExpire = !deadline || AbsoluteTime.isNever(deadline);
updateRequest("unload rules", {
rules: currentRules,
deadline,
onExpire_measure:
- expirationForm.status.status === "fail" || doesntExpire
+ expirationForm.status.status === "fail" ||
+ doesntExpire ||
+ result.expirationOutcome !== "measure"
? ""
- : expirationForm.status.result.measure,
+ : result.measure,
+ rules_reviewed: true,
});
});
- function addNewRule(nr: RuleFormType) {
- const result = !currentRules ? [] : [...currentRules];
- const clean = (nr.measures ?? []).filter((m) => !!m);
- const measures = !clean.length ? DEFAULT_MEASURE_IF_NONE : clean;
- result.push({
- timeframe: !nr.timeframe
- ? Duration.toTalerProtocolDuration(Duration.getForever())
- : Duration.toTalerProtocolDuration(nr.timeframe),
- threshold: Amounts.stringify(nr.threshold),
- operation_type: nr.operation_type,
- display_priority: 1,
- exposed: nr.exposed,
- is_and_combinator: nr.all,
- measures,
- });
- setRules(result);
+ function closeEditor(): void {
+ setEditor(undefined);
+ setTimeout(() => addButtonRef.current?.focus(), 0);
}
- const ruleInconsistency =
- isWallet === undefined
- ? undefined
- : findRuleInconsistency(isWallet, currentRules);
-
- const ButtonRulesBasicPlan = () => (
- <button
- onClick={() => {
- setRules(BASIC_PLAN(config.currency, isWallet));
- }}
- class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700 disabled:bg-gray-600"
- >
- <i18n.Translate>Basic plan</i18n.Translate>
- </button>
- );
+ function saveRule(nr: RuleFormType): void {
+ const nextRule = ruleFromForm(
+ nr,
+ editor?.index === undefined ? undefined : currentRules[editor.index],
+ );
+ setRules(saveRuleAt(currentRules, nextRule, editor?.index));
+ closeEditor();
+ }
- const ButtonRulesPremiumPlan = () => (
- <button
- onClick={() => {
- setRules(PREMIUM_PLAN(config.currency, isWallet));
- }}
- class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700 disabled:bg-gray-600"
- >
- <i18n.Translate>Premium</i18n.Translate>
- </button>
- );
+ const warnings = applicabilityWarnings(isWallet ?? false, currentRules);
+ const operationLabels = (operations: readonly LimitOperationType[]) =>
+ operations
+ .map((operation) => labelForOperationType(operation, i18n))
+ .join(", ");
- const ButtonRulesEcommerce = () => (
- <button
- onClick={() => {
- setRules(E_COMMERCE(config.currency, isWallet));
- }}
- class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700 disabled:bg-gray-600"
- >
- <i18n.Translate>E-commerce</i18n.Translate>
- </button>
- );
+ function replacementRules(replacement: Replacement): KycRule[] {
+ switch (replacement) {
+ case "current":
+ return limits.rules;
+ case "defaults":
+ return defaultRules;
+ case "freeze":
+ return FREEZE_PLAN(config.currency, isWallet);
+ case "basic":
+ return BASIC_PLAN(config.currency, isWallet);
+ case "premium":
+ return PREMIUM_PLAN(config.currency, isWallet);
+ case "ecommerce":
+ return E_COMMERCE(config.currency, isWallet);
+ case "pos":
+ return POINT_OF_SALE(config.currency, isWallet);
+ default:
+ return assertUnreachable(replacement);
+ }
+ }
- const ButtonRulesPoS = () => (
- <button
- onClick={() => {
- setRules(POINT_OF_SALE(config.currency, isWallet));
- }}
- class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700 disabled:bg-gray-600"
- >
- <i18n.Translate>Point of Sale</i18n.Translate>
- </button>
- );
+ const previewRules = pendingReplacement
+ ? replacementRules(pendingReplacement)
+ : undefined;
return (
- <div>
- {!ruleInconsistency ? undefined : (
- <Attention
- title={i18n.str`Check rules`}
- type={(function (state: RuleInconsistency) {
- switch (state) {
- case "shold-not-have-bank-rules":
- case "shold-not-have-wallet-rules": {
- return "warning";
- }
- case "missing-wallet-rules":
- case "missing-bank-rules":
- return "info";
- default: {
- assertUnreachable(state);
- }
- }
- })(ruleInconsistency)}
+ <section class="mt-4">
+ <div class="flex items-center justify-between gap-4">
+ <div>
+ <h2 class="text-lg font-semibold">
+ <i18n.Translate>Proposed rules</i18n.Translate>
+ </h2>
+ <p class="text-sm text-gray-600">
+ <i18n.Translate>
+ This complete rule set replaces the currently applied rules and
+ exchange defaults until it expires. When multiple rules apply, the
+ rule with the highest priority takes precedence. Table order does
+ not affect priority.
+ </i18n.Translate>
+ </p>
+ </div>
+ <button
+ ref={addButtonRef}
+ type="button"
+ disabled={editor !== undefined}
+ onClick={() => setEditor({})}
+ class="shrink-0 rounded-md bg-indigo-700 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-600 disabled:bg-gray-500"
>
- {(function (state: RuleInconsistency) {
- switch (state) {
- case "shold-not-have-bank-rules": {
- return (
- <i18n.Translate>
- The account is a wallet and there are bank account
- operation's limits which may trigger actions that are not
- required: {ONLY_BANK_RULES.join(",")}
- </i18n.Translate>
- );
- }
- case "shold-not-have-wallet-rules": {
- return (
- <i18n.Translate>
- The account isn't a wallet and there are wallet operation's
- limits which may trigger actions that are not required:{" "}
- {ONLY_WALLET_RULES.join(",")}
- </i18n.Translate>
- );
- }
- case "missing-wallet-rules": {
- return (
- <i18n.Translate>
- The account is a wallet and there are wallet operation's
- limits which are not limited: {WALLET_RULES.join(",")}
- </i18n.Translate>
- );
- }
- case "missing-bank-rules": {
- return (
- <i18n.Translate>
- The AML account is a bank account, but not all
- account-related operations are limited (
- {BANK_RULES.join(",")}).
- </i18n.Translate>
- );
- }
- default: {
- assertUnreachable(state);
- }
- }
- })(ruleInconsistency)}
- </Attention>
- )}
+ <i18n.Translate>Add rule</i18n.Translate>
+ </button>
+ </div>
- {!showAddRuleForm ? undefined : (
- <AddNewRuleForm
+ {!editor ? undefined : (
+ <RuleEditor
measureList={allMeasure}
config={config}
isWallet={isWallet ?? false}
- onAdd={addNewRule}
- onClose={() => {
- setShowAddRuleForm(false);
- }}
+ initial={editor.initial}
+ editing={editor.index !== undefined}
+ onSave={saveRule}
+ onClose={closeEditor}
/>
)}
- <h2 class="mt-4 mb-2">
- <i18n.Translate>New rules</i18n.Translate>
- </h2>
+ {warnings.unexpected.length ? (
+ <Attention
+ title={i18n.str`Rules for another account type`}
+ type="warning"
+ >
+ <i18n.Translate>
+ These operations do not apply to this account type:{" "}
+ {operationLabels(warnings.unexpected)}.
+ </i18n.Translate>
+ </Attention>
+ ) : undefined}
+ {warnings.missing.length ? (
+ <Attention title={i18n.str`Operations without limits`} type="info">
+ <i18n.Translate>
+ No proposed rule limits these operations:{" "}
+ {operationLabels(warnings.missing)}.
+ </i18n.Translate>
+ </Attention>
+ ) : undefined}
+ {!rulesAreValid(currentRules) ? (
+ <Attention title={i18n.str`Invalid proposed rules`} type="danger">
+ <i18n.Translate>
+ Edit the highlighted rule set before continuing. Hard blocks cannot
+ be combined with measures, and Balance and Refund rules must use an
+ instant timeframe.
+ </i18n.Translate>
+ </Attention>
+ ) : undefined}
<RulesInfo
rules={currentRules}
- onRemove={(r, idx) => {
- const nr = [...currentRules];
- nr.splice(idx, 1);
- setRules(nr);
- }}
- onNew={() => {
- setShowAddRuleForm(true);
+ editable
+ onEdit={(rule, idx) =>
+ setEditor({ index: idx, initial: formFromRule(rule) })
+ }
+ onRemove={(_rule, idx) => {
+ setPendingRemove(idx);
}}
/>
- <button
- onClick={() => {
- setRules(limits.rules);
- }}
- class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700 disabled:bg-gray-600"
- >
- <i18n.Translate>Reset rules to current state</i18n.Translate>
- </button>
- <button
- onClick={() => {
- setRules(defaultRules);
- }}
- class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700 disabled:bg-gray-600"
- >
- <i18n.Translate>Set rules to default</i18n.Translate>
- </button>
- <button
- onClick={() => {
- setRules(FREEZE_PLAN(config.currency, isWallet));
- }}
- class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700 disabled:bg-gray-600"
- >
- <i18n.Translate>Freeze account</i18n.Translate>
- </button>
- {dialect == AmlSpaDialect.TESTING ? (
- <>
- <ButtonRulesBasicPlan />
- <ButtonRulesPremiumPlan />
- <ButtonRulesEcommerce />
- <ButtonRulesPoS />
- </>
- ) : null}
- <h2 class="mt-4 mb-2">
- <i18n.Translate>Behavior on rule expiration</i18n.Translate>
- </h2>
- <FormUI design={expirationFormDesign} model={expirationForm.model} />
- <button
- onClick={() => {
- expirationForm.model
- .getHandlerForAttributeKey("measure")
- .onChange(defaultSuccessorMeasure);
- }}
- class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700 disabled:bg-gray-600"
- >
- <i18n.Translate>Reset measure</i18n.Translate>
- </button>
- <button
- onClick={() => {
- const c =
- expirationForm.model.getHandlerForAttributeKey("expiration");
- c.onChange(
- AbsoluteTime.fromProtocolTimestamp(limits.expiration_time),
- );
- }}
- class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700 disabled:bg-gray-600"
- >
- <i18n.Translate>Reset expiration</i18n.Translate>
- </button>
- </div>
+ {pendingRemove === undefined ? undefined : (
+ <Attention title={i18n.str`Remove proposed rule?`} type="warning">
+ {currentRules.length === 1 ? (
+ <i18n.Translate>
+ This is the final rule. Removing it leaves every applicable
+ operation unlimited.
+ </i18n.Translate>
+ ) : (
+ <i18n.Translate>
+ The rule will be removed from the proposed set.
+ </i18n.Translate>
+ )}
+ <div class="mt-3 flex gap-3">
+ <button
+ type="button"
+ onClick={() => setPendingRemove(undefined)}
+ class="rounded-md bg-white px-3 py-2 text-sm ring-1 ring-gray-300"
+ >
+ <i18n.Translate>Keep rule</i18n.Translate>
+ </button>
+ <button
+ type="button"
+ onClick={() => {
+ setRules(removeRuleAt(currentRules, pendingRemove));
+ setPendingRemove(undefined);
+ }}
+ class="rounded-md bg-red-700 px-3 py-2 text-sm text-white"
+ >
+ <i18n.Translate>Remove rule</i18n.Translate>
+ </button>
+ </div>
+ </Attention>
+ )}
+
+ <div class="mt-5 rounded-lg border border-gray-200 p-4">
+ <h3 class="font-semibold">
+ <i18n.Translate>Replace proposed rules</i18n.Translate>
+ </h3>
+ <p class="mb-3 text-sm text-gray-600">
+ <i18n.Translate>
+ Preview a complete replacement before applying it.
+ </i18n.Translate>
+ </p>
+ <div class="flex flex-wrap gap-2">
+ <ReplacementButton onClick={() => setPendingReplacement("current")}>
+ <i18n.Translate>Currently applied</i18n.Translate>
+ </ReplacementButton>
+ <ReplacementButton onClick={() => setPendingReplacement("defaults")}>
+ <i18n.Translate>Exchange defaults</i18n.Translate>
+ </ReplacementButton>
+ {dialect === AmlSpaDialect.TOPS ? (
+ <Fragment>
+ <ReplacementButton
+ onClick={() => setPendingReplacement("ecommerce")}
+ >
+ <i18n.Translate>E-commerce</i18n.Translate>
+ </ReplacementButton>
+ <ReplacementButton onClick={() => setPendingReplacement("pos")}>
+ <i18n.Translate>Point of Sale</i18n.Translate>
+ </ReplacementButton>
+ </Fragment>
+ ) : undefined}
+ {dialect === AmlSpaDialect.TESTING ? (
+ <Fragment>
+ <ReplacementButton onClick={() => setPendingReplacement("basic")}>
+ <i18n.Translate>Basic plan</i18n.Translate>
+ </ReplacementButton>
+ <ReplacementButton
+ onClick={() => setPendingReplacement("premium")}
+ >
+ <i18n.Translate>Premium</i18n.Translate>
+ </ReplacementButton>
+ </Fragment>
+ ) : undefined}
+ <button
+ type="button"
+ onClick={() => setPendingReplacement("freeze")}
+ class="rounded-md bg-white px-3 py-2 text-sm font-semibold text-red-700 ring-1 ring-inset ring-red-300 hover:bg-red-50"
+ >
+ <i18n.Translate>Freeze account</i18n.Translate>
+ </button>
+ </div>
+ </div>
+
+ {!previewRules || !pendingReplacement ? undefined : (
+ <div class="mt-4 rounded-lg border border-indigo-200 bg-indigo-50 p-4">
+ <h3 class="font-semibold">
+ <i18n.Translate>Replacement preview</i18n.Translate>
+ </h3>
+ {pendingReplacement === "freeze" ? (
+ <Attention title={i18n.str`Confirm account freeze`} type="danger">
+ <i18n.Translate>
+ Every applicable operation will receive a zero hard limit.
+ </i18n.Translate>
+ </Attention>
+ ) : undefined}
+ <RulesInfo rules={previewRules} />
+ <div class="mt-3 flex justify-end gap-3">
+ <button
+ type="button"
+ onClick={() => setPendingReplacement(undefined)}
+ class="rounded-md bg-white px-3 py-2 text-sm ring-1 ring-gray-300"
+ >
+ <i18n.Translate>Cancel</i18n.Translate>
+ </button>
+ <button
+ type="button"
+ onClick={() => {
+ setRules(previewRules);
+ setPendingReplacement(undefined);
+ }}
+ class={
+ pendingReplacement === "freeze"
+ ? "rounded-md bg-red-700 px-3 py-2 text-sm text-white"
+ : "rounded-md bg-indigo-700 px-3 py-2 text-sm text-white"
+ }
+ >
+ <i18n.Translate>Apply replacement</i18n.Translate>
+ </button>
+ </div>
+ </div>
+ )}
+
+ <div class="mt-8">
+ <h2 class="mb-2 text-lg font-semibold">
+ <i18n.Translate>Rule expiration</i18n.Translate>
+ </h2>
+ <p class="mb-3 text-sm text-gray-600">
+ <i18n.Translate>
+ Choose how long the proposed rules apply and what happens
+ afterwards.
+ </i18n.Translate>
+ </p>
+ <ExpirationShortcuts
+ referenceNow={referenceNow}
+ onChange={(expiration) =>
+ expirationForm.model
+ .getHandlerForAttributeKey("expiration")
+ .onChange(expiration)
+ }
+ />
+ <FormUI design={expirationFormDesign} model={expirationForm.model} />
+ {showSuccessor && selectedSuccessorName ? (
+ selectedSuccessor ? (
+ <section class="mt-5">
+ <h3 class="text-sm font-semibold text-gray-950 dark:text-gray-50">
+ <i18n.Translate>Selected successor measure</i18n.Translate>
+ </h3>
+ <div class="mt-3 max-w-2xl">
+ <MeasureCard
+ name={selectedSuccessorName}
+ measure={selectedSuccessor}
+ summary={measureSummary}
+ language={lang}
+ category={categoryForMeasureDefinition(selectedSuccessor)}
+ />
+ </div>
+ </section>
+ ) : (
+ <Attention
+ type="danger"
+ title={i18n.str`Successor measure unavailable`}
+ >
+ <i18n.Translate>
+ The selected successor measure is no longer configured. Choose
+ another measure before continuing.
+ </i18n.Translate>
+ </Attention>
+ )
+ ) : undefined}
+ {expirationForm.status.result.expiration &&
+ AbsoluteTime.isNever(
+ expirationForm.status.result.expiration as AbsoluteTime,
+ ) ? (
+ <p class="mt-2 text-sm text-gray-600">
+ <i18n.Translate>
+ The proposed rules never expire, so no successor action will run.
+ </i18n.Translate>
+ </p>
+ ) : undefined}
+ <button
+ type="button"
+ onClick={() =>
+ expirationForm.update({
+ expiration: AbsoluteTime.fromProtocolTimestamp(
+ limits.expiration_time,
+ ),
+ expirationOutcome: limits.successor_measure
+ ? "measure"
+ : "defaults",
+ measure: limits.successor_measure,
+ })
+ }
+ class="mt-3 rounded-md bg-white px-3 py-2 text-sm font-semibold ring-1 ring-gray-300 hover:bg-gray-50"
+ >
+ <i18n.Translate>Restore currently applied expiration</i18n.Translate>
+ </button>
+ </div>
+ </section>
);
}
type RuleFormType = {
operation_type: LimitOperationType;
+ display_priority: number;
threshold: AmountJson;
- timeframe: Duration;
+ timeframe?: Duration;
exposed: boolean;
+ outcome: "block" | "measures";
measures: string[];
all: boolean;
};
-type ExpirationFormType = {
+export type ExpirationFormType = {
expiration: AbsoluteTime;
+ expirationOutcome: "defaults" | "measure";
measure: string | undefined;
};
-function labelForOperationType(
- op: LimitOperationType,
- i18n: InternationalizationAPI,
-): TranslatedString {
- switch (op) {
- case LimitOperationType.withdraw:
- return i18n.ctx("operation type")`Withdraw`;
- case LimitOperationType.deposit:
- return i18n.ctx("operation type")`Deposit`;
- case LimitOperationType.merge:
- return i18n.ctx("operation type")`Merge`;
- case LimitOperationType.aggregate:
- return i18n.ctx("operation type")`Aggregate`;
- case LimitOperationType.balance:
- return i18n.ctx("operation type")`Balance`;
- case LimitOperationType.refund:
- return i18n.ctx("operation type")`Refund`;
- case LimitOperationType.close:
- return i18n.ctx("operation type")`Close`;
- case LimitOperationType.transaction:
- return i18n.ctx("operation type")`Transaction`;
- }
+function formFromRule(rule: KycRule): RuleFormType {
+ const blocked =
+ rule.measures.length === 1 && isVerbotenMeasure(rule.measures[0]!);
+ return {
+ operation_type: rule.operation_type,
+ display_priority: rule.display_priority,
+ threshold: Amounts.parseOrThrow(rule.threshold),
+ timeframe: INSTANT_RULES.includes(rule.operation_type)
+ ? undefined
+ : Duration.fromTalerProtocolDuration(rule.timeframe),
+ exposed: rule.exposed ?? false,
+ outcome: blocked ? "block" : "measures",
+ measures: blocked ? [] : rule.measures,
+ all: rule.is_and_combinator ?? false,
+ };
+}
+
+function ruleFromForm(form: RuleFormType, original?: KycRule): KycRule {
+ return {
+ ...original,
+ operation_type: form.operation_type,
+ display_priority: form.display_priority,
+ threshold: Amounts.stringify(form.threshold),
+ timeframe: Duration.toTalerProtocolDuration(
+ INSTANT_RULES.includes(form.operation_type)
+ ? Duration.fromSpec({})
+ : (form.timeframe ?? Duration.getForever()),
+ ),
+ measures: form.outcome === "block" ? ["VERBOTEN"] : form.measures,
+ exposed: form.exposed,
+ is_and_combinator: form.outcome === "measures" ? form.all : false,
+ };
+}
+
+function ReplacementButton({
+ onClick,
+ children,
+}: {
+ onClick: () => void;
+ children: ComponentChildren;
+}): VNode {
+ return (
+ <button
+ type="button"
+ onClick={onClick}
+ class="rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50"
+ >
+ {children}
+ </button>
+ );
}
const ruleFormDesignTemplate = (
@@ -639,6 +733,13 @@ const ruleFormDesignTemplate = (
}),
},
{
+ id: "display_priority",
+ type: "integer",
+ required: true,
+ label: i18n.str`Priority`,
+ help: i18n.str`Higher values take precedence when multiple rules apply. Priority is independent of the rule's position in the table.`,
+ },
+ {
id: "threshold",
type: "amount",
required: true,
@@ -649,9 +750,16 @@ const ruleFormDesignTemplate = (
id: "timeframe",
type: "durationText",
required: true,
+ hide: (_value, form) => INSTANT_RULES.includes(form.operation_type),
placeholder: "1Y 2M 3D 4h 5m 6s",
label: i18n.str`Timeframe`,
- help: `Use YMDhms next to a number as a unit for Year, Month, Day, hour, minute and seconds.`,
+ help: i18n.str`Use Y, M, D, h, m or s after each number. Forever accumulates over the account's full history.`,
+ },
+ {
+ type: "caption",
+ label: i18n.str`Instant timeframe`,
+ help: i18n.str`Balance and Refund limits apply to one balance or transaction, so their timeframe is fixed to zero.`,
+ hide: (_value, form) => !INSTANT_RULES.includes(form.operation_type),
},
{
id: "exposed",
@@ -660,7 +768,18 @@ const ruleFormDesignTemplate = (
help: i18n.str`Is this limit communicated to the customer?`,
},
{
+ id: "outcome",
+ type: "choiceHorizontal",
+ required: true,
+ label: i18n.str`When the threshold is crossed`,
+ choices: [
+ { value: "block", label: i18n.str`Block operation` },
+ { value: "measures", label: i18n.str`Require measures` },
+ ],
+ },
+ {
type: "selectMultiple",
+ required: true,
unique: true,
choices: measureNames.map((name) => {
return {
@@ -669,80 +788,72 @@ const ruleFormDesignTemplate = (
};
}),
id: "measures",
- label: i18n.str`Escalation measure`,
+ label: i18n.str`Required measures`,
help: i18n.str`Measures that the customer will need to satisfy to apply for a new threshold.`,
+ hide: (_value, form) => form.outcome !== "measures",
},
{
id: "all",
type: "toggle",
label: i18n.str`All measures`,
help: i18n.str`Hint the customer that all measures should be completed`,
+ hide: (_value, form) => form.outcome !== "measures",
},
],
});
-const expirationFormDesignTemplate = (
+export const expirationFormDesignTemplate = (
i18n: InternationalizationAPI,
- measureNames: string[],
+ measureChoices: Array<{
+ value: string;
+ label: string;
+ description?: string;
+ }>,
+ availableMeasureNames: string[],
+ now: AbsoluteTime,
): FormDesign => ({
type: "single-column",
fields: [
{
- type: "choiceHorizontal",
- label: i18n.str`Expiration`,
- help: i18n.str`Predefined shortcuts`,
- id: "expiration",
- choices: [
- {
- label: i18n.str`In a week`,
- // @ts-expect-error we have to format as string 'dd/MM/yyyy' and convert back
- value: AbsoluteTime.addDuration(
- AbsoluteTime.now(),
- Duration.fromSpec({ days: 7 }),
- ),
- },
- {
- label: i18n.str`In a month`,
- // @ts-expect-error we have to format as string 'dd/MM/yyyy' and convert back
- value: AbsoluteTime.addDuration(
- AbsoluteTime.now(),
- Duration.fromSpec({ months: 1 }),
- ),
- },
- {
- label: i18n.str`In a year`,
- // @ts-expect-error we have to format as string 'dd/MM/yyyy' and convert back
- value: AbsoluteTime.addDuration(
- AbsoluteTime.now(),
- Duration.fromSpec({ years: 1 }),
- ),
- },
- {
- label: i18n.str`Never`,
- // @ts-expect-error we have to format as string 'dd/MM/yyyy' and convert back
- value: AbsoluteTime.never(),
- },
- ],
- },
- {
id: "expiration",
type: "absoluteTimeText",
placeholder: "dd/MM/yyyy",
pattern: "dd/MM/yyyy",
label: i18n.str`Expiration date`,
help: i18n.str`Until when are the new rules active.`,
+ required: true,
+ validator: (value) =>
+ deadlineIsValid(value as unknown as AbsoluteTime, now)
+ ? undefined
+ : i18n.str`Choose a future expiration date or Never.`,
+ },
+ {
+ id: "expirationOutcome",
+ type: "choiceHorizontal",
+ required: true,
+ label: i18n.str`After expiration`,
+ choices: [
+ { value: "defaults", label: i18n.str`Return to exchange defaults` },
+ { value: "measure", label: i18n.str`Trigger a successor measure` },
+ ],
+ hide: (_value, form) =>
+ !!form.expiration && AbsoluteTime.isNever(form.expiration),
},
{
type: "selectOne",
- choices: measureNames.map((name) => {
- return {
- value: name,
- label: name,
- };
- }),
+ choices: measureChoices,
id: "measure",
label: i18n.str`Successor measure`,
+ placeholder: i18n.str`Search available measures`,
help: i18n.str`Measure taken automatically upon expiration of the current decision.`,
+ required: true,
+ hide: (_value, form) =>
+ (!!form.expiration && AbsoluteTime.isNever(form.expiration)) ||
+ form.expirationOutcome !== "measure",
+ validator: (value) =>
+ availableMeasureNames.includes(value)
+ ? undefined
+ : i18n.str`This successor measure is no longer available.`,
},
],
});
@@ -750,7 +861,7 @@ const expirationFormDesignTemplate = (
const BASIC_PLAN: TemplateRulesFunction = (currency, isWallet) =>
[
{
- display_priority: 1,
+ display_priority: 0,
measures: ["VERBOTEN"],
operation_type: LimitOperationType.balance,
threshold: Amounts.stringify({
@@ -758,10 +869,10 @@ const BASIC_PLAN: TemplateRulesFunction = (currency, isWallet) =>
fraction: 0,
value: 10000,
}),
- timeframe: Duration.toTalerProtocolDuration(Duration.getForever()),
+ timeframe: Duration.toTalerProtocolDuration(Duration.fromSpec({})),
},
{
- display_priority: 1,
+ display_priority: 0,
measures: ["VERBOTEN"],
operation_type: LimitOperationType.transaction,
threshold: Amounts.stringify({
@@ -772,7 +883,7 @@ const BASIC_PLAN: TemplateRulesFunction = (currency, isWallet) =>
timeframe: Duration.toTalerProtocolDuration(Duration.getForever()),
},
{
- display_priority: 1,
+ display_priority: 0,
measures: ["VERBOTEN"],
operation_type: LimitOperationType.withdraw,
threshold: Amounts.stringify({
@@ -785,7 +896,7 @@ const BASIC_PLAN: TemplateRulesFunction = (currency, isWallet) =>
),
},
{
- display_priority: 1,
+ display_priority: 0,
measures: ["VERBOTEN"],
operation_type: LimitOperationType.merge,
threshold: Amounts.stringify({
@@ -798,7 +909,7 @@ const BASIC_PLAN: TemplateRulesFunction = (currency, isWallet) =>
),
},
{
- display_priority: 1,
+ display_priority: 0,
measures: ["preserve-investigate"],
operation_type: LimitOperationType.deposit,
threshold: Amounts.stringify({
@@ -811,7 +922,7 @@ const BASIC_PLAN: TemplateRulesFunction = (currency, isWallet) =>
),
},
{
- display_priority: 1,
+ display_priority: 0,
measures: ["preserve-investigate"],
operation_type: LimitOperationType.deposit,
threshold: Amounts.stringify({
@@ -824,7 +935,7 @@ const BASIC_PLAN: TemplateRulesFunction = (currency, isWallet) =>
),
},
{
- display_priority: 1,
+ display_priority: 0,
measures: ["preserve-investigate"],
operation_type: LimitOperationType.aggregate,
threshold: Amounts.stringify({
@@ -837,7 +948,7 @@ const BASIC_PLAN: TemplateRulesFunction = (currency, isWallet) =>
),
},
{
- display_priority: 1,
+ display_priority: 0,
measures: ["preserve-investigate"],
operation_type: LimitOperationType.aggregate,
threshold: Amounts.stringify({
@@ -863,7 +974,7 @@ type TemplateRulesFunction = (
const PREMIUM_PLAN: TemplateRulesFunction = (currency, isWallet) =>
[
{
- display_priority: 1,
+ display_priority: 0,
measures: ["VERBOTEN"],
operation_type: LimitOperationType.balance,
threshold: Amounts.stringify({
@@ -871,10 +982,10 @@ const PREMIUM_PLAN: TemplateRulesFunction = (currency, isWallet) =>
fraction: 0,
value: 10 * 1000,
}),
- timeframe: Duration.toTalerProtocolDuration(Duration.getForever()),
+ timeframe: Duration.toTalerProtocolDuration(Duration.fromSpec({})),
},
{
- display_priority: 1,
+ display_priority: 0,
measures: ["VERBOTEN"],
operation_type: LimitOperationType.transaction,
threshold: Amounts.stringify({
@@ -885,7 +996,7 @@ const PREMIUM_PLAN: TemplateRulesFunction = (currency, isWallet) =>
timeframe: Duration.toTalerProtocolDuration(Duration.getForever()),
},
{
- display_priority: 1,
+ display_priority: 0,
measures: ["VERBOTEN"],
operation_type: LimitOperationType.withdraw,
threshold: Amounts.stringify({
@@ -898,7 +1009,7 @@ const PREMIUM_PLAN: TemplateRulesFunction = (currency, isWallet) =>
),
},
{
- display_priority: 1,
+ display_priority: 0,
measures: ["VERBOTEN"],
operation_type: LimitOperationType.merge,
threshold: Amounts.stringify({
@@ -911,7 +1022,7 @@ const PREMIUM_PLAN: TemplateRulesFunction = (currency, isWallet) =>
),
},
{
- display_priority: 1,
+ display_priority: 0,
measures: ["preserve-investigate"],
operation_type: LimitOperationType.deposit,
threshold: Amounts.stringify({
@@ -924,7 +1035,7 @@ const PREMIUM_PLAN: TemplateRulesFunction = (currency, isWallet) =>
),
},
{
- display_priority: 1,
+ display_priority: 0,
measures: ["preserve-investigate"],
operation_type: LimitOperationType.deposit,
threshold: Amounts.stringify({
@@ -937,7 +1048,7 @@ const PREMIUM_PLAN: TemplateRulesFunction = (currency, isWallet) =>
),
},
{
- display_priority: 1,
+ display_priority: 0,
measures: ["preserve-investigate"],
operation_type: LimitOperationType.aggregate,
threshold: Amounts.stringify({
@@ -950,7 +1061,7 @@ const PREMIUM_PLAN: TemplateRulesFunction = (currency, isWallet) =>
),
},
{
- display_priority: 1,
+ display_priority: 0,
measures: ["preserve-investigate"],
operation_type: LimitOperationType.aggregate,
threshold: Amounts.stringify({
@@ -978,17 +1089,21 @@ const FREEZE_PLAN: TemplateRulesFunction = (
? WALLET_RULES
: BANK_RULES
).map((operation_type) => ({
- display_priority: 1,
+ display_priority: 0,
measures: ["VERBOTEN"],
operation_type,
threshold: Amounts.stringify(Amounts.zeroOfCurrency(currency)),
- timeframe: Duration.toTalerProtocolDuration(Duration.getForever()),
+ timeframe: Duration.toTalerProtocolDuration(
+ INSTANT_RULES.includes(operation_type)
+ ? Duration.fromSpec({})
+ : Duration.getForever(),
+ ),
}));
const POINT_OF_SALE: TemplateRulesFunction = (currency, isWallet) =>
[
{
- display_priority: 1,
+ display_priority: 0,
measures: ["VERBOTEN"],
operation_type: LimitOperationType.withdraw,
threshold: Amounts.stringify({
@@ -1001,7 +1116,7 @@ const POINT_OF_SALE: TemplateRulesFunction = (currency, isWallet) =>
),
},
{
- display_priority: 1,
+ display_priority: 0,
measures: ["VERBOTEN"],
operation_type: LimitOperationType.merge,
threshold: Amounts.stringify({
@@ -1014,7 +1129,7 @@ const POINT_OF_SALE: TemplateRulesFunction = (currency, isWallet) =>
),
},
{
- display_priority: 1,
+ display_priority: 0,
measures: ["preserve-investigate"],
operation_type: LimitOperationType.deposit,
threshold: Amounts.stringify({
@@ -1027,7 +1142,7 @@ const POINT_OF_SALE: TemplateRulesFunction = (currency, isWallet) =>
),
},
{
- display_priority: 1,
+ display_priority: 0,
measures: ["preserve-investigate"],
operation_type: LimitOperationType.aggregate,
threshold: Amounts.stringify({
@@ -1048,7 +1163,7 @@ const POINT_OF_SALE: TemplateRulesFunction = (currency, isWallet) =>
const E_COMMERCE: TemplateRulesFunction = (currency, isWallet) =>
[
{
- display_priority: 1,
+ display_priority: 0,
measures: ["VERBOTEN"],
operation_type: LimitOperationType.withdraw,
threshold: Amounts.stringify({
@@ -1061,7 +1176,7 @@ const E_COMMERCE: TemplateRulesFunction = (currency, isWallet) =>
),
},
{
- display_priority: 1,
+ display_priority: 0,
measures: ["VERBOTEN"],
operation_type: LimitOperationType.merge,
threshold: Amounts.stringify({
@@ -1074,7 +1189,7 @@ const E_COMMERCE: TemplateRulesFunction = (currency, isWallet) =>
),
},
{
- display_priority: 1,
+ display_priority: 0,
measures: ["preserve-investigate"],
operation_type: LimitOperationType.deposit,
threshold: Amounts.stringify({
@@ -1087,7 +1202,7 @@ const E_COMMERCE: TemplateRulesFunction = (currency, isWallet) =>
),
},
{
- display_priority: 1,
+ display_priority: 0,
measures: ["preserve-investigate"],
operation_type: LimitOperationType.aggregate,
threshold: Amounts.stringify({
diff --git a/packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx b/packages/taler-exchange-aml-webui/src/pages/decision/Summary.tsx
@@ -14,7 +14,6 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import {
- AbsoluteTime,
AmlDecisionRequest,
assertUnreachable,
HttpStatusCode,
@@ -31,6 +30,7 @@ import {
ErrorLoading,
FailLoading,
Loading,
+ Time,
useExchangeApiContext,
useNotificationContext,
useNotifiedOperation,
@@ -38,8 +38,9 @@ import {
} from "@gnu-taler/web-util/browser";
import { Fragment, h, VNode } from "preact";
import { useState } from "preact/hooks";
+import { ConfirmationModal } from "../../components/ConfirmationModal.js";
import { CurrentMeasureTable } from "../../components/MeasuresTable.js";
-import { ShowDecisionLimitInfo } from "../../components/ShowDecisionLimitInfo.js";
+import { RulesInfo } from "../../components/RulesInfo.js";
import { useCurrentDecisionRequest } from "../../hooks/decision-request.js";
import { OfficerReady } from "../../hooks/officer.js";
import { useServerMeasures } from "../../hooks/server-info.js";
@@ -48,6 +49,7 @@ import {
UiMeasureInformation,
} from "../../utils/computeAvailableMesaures.js";
import { buildAmlDecisionRequest } from "../../utils/decision-validation.js";
+import { deadlineIsValid, rulesAreValid } from "../../utils/rule-validation.js";
import {
isAttributesCompleted,
isEventsCompleted,
@@ -68,11 +70,13 @@ const TALER_SCREEN_ID = 102;
export function Summary({
account,
onMove,
- newPayto,
+ fullPayto,
+ newAccount,
officer,
}: {
account?: string;
- newPayto?: string;
+ fullPayto: string;
+ newAccount: boolean;
officer: OfficerReady;
onMove: (n: WizardSteps | undefined) => void;
}): VNode {
@@ -87,7 +91,18 @@ export function Summary({
measures && !(measures instanceof TalerError) && measures.type === "ok"
? measures.body
: undefined;
- const allMeasures = computeMeasureInformation(measureSummary);
+ const configuredMeasures = computeMeasureInformation(measureSummary);
+ const customMeasures = computeMeasureInformation(measureSummary, {
+ measureMap: decision.custom_measures,
+ });
+ const allMeasures: UiMeasureInformation = {
+ forms: [...configuredMeasures.forms, ...customMeasures.forms],
+ procedures: [
+ ...configuredMeasures.procedures,
+ ...customMeasures.procedures,
+ ],
+ info: [...configuredMeasures.info, ...customMeasures.info],
+ };
const d = decision.new_measures === undefined ? [] : decision.new_measures;
const activeMeasureInfo: UiMeasureInformation = {
@@ -99,25 +114,32 @@ export function Summary({
const { lib } = useExchangeApiContext();
- const isNewAccount = !!newPayto;
const INVALID_ACCOUNT = !account;
- const INVALID_RULES = !isRulesCompleted(decision); //!decision.deadline || !decision.rules;
+ const INVALID_RULES = !isRulesCompleted(decision);
+ const RULES_NOT_REVIEWED = decision.rules_reviewed !== true;
+ const HAS_VALID_RULE_DRAFT =
+ decision.rules !== undefined &&
+ rulesAreValid(decision.rules) &&
+ deadlineIsValid(decision.deadline);
const INVALID_MEASURES = !isMeasuresCompleted(decision); //.new_measures === undefined;
const INVALID_PROPERTIES = !isPropertiesCompleted(decision); //.properties === undefined;
const INVALID_EVENTS = !isEventsCompleted(decision); //false; //decision.inhibit_events === undefined;
- const INVALID_JUSTIFICATION = isNewAccount
+ const INVALID_JUSTIFICATION = newAccount
? !isJustificationCompletedForNewACcount(decision)
: !isJustificationCompleted(decision);
const INVALID_ATTRIBUTES = !isAttributesCompleted(decision);
- const MROS_REPORT_COMPLETED = !decision.triggering_events
- ? false
- : decision.triggering_events.includes(
- TOPS_AmlEventsName.MROS_REPORTED_SUSPICION_SIMPLE,
- ) ||
- decision.triggering_events.includes(
- TOPS_AmlEventsName.MROS_REPORTED_SUSPICION_SUBSTANTIATED,
- );
+ const recordedEvents = [
+ ...(decision.triggering_events ?? []),
+ ...(decision.custom_events ?? []),
+ ];
+ const MROS_REPORT_COMPLETED =
+ recordedEvents.includes(
+ TOPS_AmlEventsName.MROS_REPORTED_SUSPICION_SIMPLE,
+ ) ||
+ recordedEvents.includes(
+ TOPS_AmlEventsName.MROS_REPORTED_SUSPICION_SUBSTANTIATED,
+ );
const INCOMPLETE_STEPS =
INVALID_ACCOUNT ||
@@ -135,13 +157,15 @@ export function Summary({
const built = buildAmlDecisionRequest({
account,
- fullPayto: newPayto,
+ fullPayto,
decision,
measures: measureSummary,
});
const request = INCOMPLETE_STEPS ? undefined : built.request;
const [submitConfirmation, setSubmitConfirmation] = useState<boolean>(false);
+ const [discardConfirmation, setDiscardConfirmation] =
+ useState<boolean>(false);
const requiresConfirmation = MROS_REPORT_COMPLETED;
const submit = useNotifiedOperation<
@@ -176,7 +200,7 @@ export function Summary({
case HttpStatusCode.NotFound:
return i18n.str`Session not found. Contact the administrator.`;
case HttpStatusCode.Conflict:
- return i18n.str`The session is disabled or a more recent decision was already submitted.`;
+ return i18n.str`The exchange rejected the decision because the officer session is disabled or the account has a newer decision. Reload the account before trying again.`;
default:
assertUnreachable(fail.case);
}
@@ -231,8 +255,8 @@ export function Summary({
<div class="px-4 py-5 sm:p-6">
<Attention type="warning" title={i18n.str`Confirmation required`}>
<i18n.Translate>
- This decision declares that the MROS report has concluded.
- Please make sure that this is the case
+ This decision records that an MROS report was filed. Confirm
+ that the report has actually been submitted before continuing.
</i18n.Translate>
</Attention>
@@ -243,12 +267,12 @@ export function Summary({
}}
class="mt-4 disabled:opacity-50 disabled:cursor-default rounded-md px-3 py-2 text-sm font-semibold shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 "
>
- <i18n.Translate>I want to check first!</i18n.Translate>
+ <i18n.Translate>Go back and review</i18n.Translate>
</button>
<AsyncButton
submit
onClick={!request ? undefined : () => submit.run(request)}
- class="mt-4 disabled:opacity-50 disabled:cursor-default rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
+ class="mt-4 disabled:cursor-not-allowed disabled:bg-gray-200 disabled:text-gray-700 disabled:hover:bg-gray-200 rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
>
<i18n.Translate>Confirm decision</i18n.Translate>
</AsyncButton>
@@ -269,6 +293,16 @@ export function Summary({
</i18n.Translate>
</Attention>
) : undefined}
+ {built.errors.includes("invalid-custom-measure") ? (
+ <Attention type="danger" title={i18n.str`Invalid custom measure`}>
+ <i18n.Translate>
+ A custom measure references an unavailable check or program, lacks
+ required context, or cannot provide the selected program inputs.
+ Review the immediate measures before submitting.
+ </i18n.Translate>
+ <ReviewStepButton onClick={() => onMove("measures")} />
+ </Attention>
+ ) : undefined}
{built.errors.includes("multiple-skip-measures") ? (
<Attention type="danger" title={i18n.str`Too many SKIP measures`}>
<i18n.Translate>
@@ -276,64 +310,96 @@ export function Summary({
</i18n.Translate>
</Attention>
) : undefined}
- {INVALID_RULES ? (
- <Fragment>
- {!decision.deadline && (
- <Attention
- type="danger"
- title={i18n.str`Missing deadline`}
- onClose={() => onMove("justification")}
- >
- <i18n.Translate>
- Deadline should specify when this rules ends and what is the
- next measures to apply after expiration.
- </i18n.Translate>
- </Attention>
- )}
- {!decision.rules && (
- <Attention
- type="danger"
- title={i18n.str`Missing rules`}
- onClose={() => onMove("rules")}
- >
- <i18n.Translate>
- Can't make a decision without rules.
- </i18n.Translate>
- </Attention>
- )}
- </Fragment>
- ) : (
+ {RULES_NOT_REVIEWED ? (
+ <Attention
+ type="danger"
+ title={i18n.str`Transaction rules not reviewed`}
+ >
+ <i18n.Translate>
+ Review the proposed rules and their expiration before submitting
+ this decision.
+ </i18n.Translate>
+ <ReviewStepButton onClick={() => onMove("rules")} />
+ </Attention>
+ ) : undefined}
+ {decision.deadline === undefined ? (
+ <Attention type="danger" title={i18n.str`Missing deadline`}>
+ <i18n.Translate>
+ Set when the proposed rules expire and what should happen afterward.
+ </i18n.Translate>
+ <ReviewStepButton onClick={() => onMove("rules")} />
+ </Attention>
+ ) : undefined}
+ {built.errors.includes("expired-deadline") ? (
+ <Attention type="danger" title={i18n.str`Invalid rule expiration`}>
+ <i18n.Translate>
+ Rule expiration must be in the future or set to Never.
+ </i18n.Translate>
+ <ReviewStepButton onClick={() => onMove("rules")} />
+ </Attention>
+ ) : undefined}
+ {decision.rules === undefined ? (
+ <Attention type="danger" title={i18n.str`Missing rules`}>
+ <i18n.Translate>
+ A decision must contain the complete rule set that will apply to the
+ account.
+ </i18n.Translate>
+ <ReviewStepButton onClick={() => onMove("rules")} />
+ </Attention>
+ ) : undefined}
+ {built.errors.includes("invalid-rules") ? (
+ <Attention type="danger" title={i18n.str`Invalid proposed rules`}>
+ <i18n.Translate>
+ Review the proposed rules. Hard blocks must be explicit, and Balance
+ and Refund rules must use an instant timeframe.
+ </i18n.Translate>
+ <ReviewStepButton onClick={() => onMove("rules")} />
+ </Attention>
+ ) : undefined}
+ {HAS_VALID_RULE_DRAFT ? (
<div>
<h2 class="mt-4 mb-2">
- <i18n.Translate>New rules</i18n.Translate>
+ <i18n.Translate>Proposed rules</i18n.Translate>
</h2>
- <ShowDecisionLimitInfo
- fixed
- since={AbsoluteTime.now()}
- until={decision.deadline!}
- rules={decision.rules!}
- startOpen
- measure={decision.onExpire_measure ?? ""}
- />
+ <div class="space-y-4 rounded-lg border border-gray-300 p-4 dark:border-gray-700">
+ <dl class="grid gap-4 text-sm sm:grid-cols-2">
+ <div>
+ <dt class="font-semibold text-gray-600 dark:text-gray-300">
+ <i18n.Translate>Expires</i18n.Translate>
+ </dt>
+ <dd class="mt-1">
+ <Time timestamp={decision.deadline!} format="PPp" />
+ </dd>
+ </div>
+ <div>
+ <dt class="font-semibold text-gray-600 dark:text-gray-300">
+ <i18n.Translate>Successor measure</i18n.Translate>
+ </dt>
+ <dd class="mt-1">
+ {decision.onExpire_measure || i18n.str`Exchange defaults`}
+ </dd>
+ </div>
+ </dl>
+ <RulesInfo rules={decision.rules!} />
+ </div>
</div>
- )}
+ ) : undefined}
{INVALID_MEASURES ? (
<Attention
type="danger"
- title={i18n.str`Missing active measure`}
- onClose={() => onMove("measures")}
+ title={i18n.str`Immediate measures not reviewed`}
>
<i18n.Translate>
- You should specify in the measure section.
+ Review whether the customer must complete any immediate measures.
</i18n.Translate>
+ <ReviewStepButton onClick={() => onMove("measures")} />
</Attention>
) : decision.new_measures!.length === 0 ? (
- <Attention
- type="info"
- title={i18n.str`No customer action required.`}
- onClose={() => onMove("measures")}
- >
- <i18n.Translate>No active measure has been selected.</i18n.Translate>
+ <Attention type="info" title={i18n.str`No immediate customer action`}>
+ <i18n.Translate>
+ No measure will start when this decision is submitted.
+ </i18n.Translate>
+ <ReviewStepButton onClick={() => onMove("measures")} />
</Attention>
) : (
<CurrentMeasureTable measures={activeMeasureInfo} />
@@ -341,12 +407,12 @@ export function Summary({
{INVALID_PROPERTIES ? (
<Attention
type="danger"
- title={i18n.str`Missing properties`}
- onClose={() => onMove("properties")}
+ title={i18n.str`Account properties not reviewed`}
>
<i18n.Translate>
- You should specify in the properties section.
+ Review the account properties before submitting the decision.
</i18n.Translate>
+ <ReviewStepButton onClick={() => onMove("properties")} />
</Attention>
) : (
<div />
@@ -354,59 +420,169 @@ export function Summary({
{INVALID_EVENTS ? (
<Attention
type="danger"
- title={i18n.str`Missing events`}
- onClose={() => onMove("events")}
+ title={i18n.str`Reporting events not reviewed`}
>
<i18n.Translate>
- You should specify in the events section.
+ Review which statistical events will be recorded with the decision.
</i18n.Translate>
+ <ReviewStepButton onClick={() => onMove("events")} />
</Attention>
) : (
<div />
)}
{INVALID_JUSTIFICATION ? (
- <Attention
- type="danger"
- title={i18n.str`Missing justification`}
- onClose={() => onMove("justification")}
- >
+ <Attention type="danger" title={i18n.str`Case disposition incomplete`}>
<i18n.Translate>
You must complete the justification section.
</i18n.Translate>
+ <ReviewStepButton onClick={() => onMove("justification")} />
</Attention>
) : (
<div />
)}
{INVALID_ATTRIBUTES ? (
- <Attention
- type="danger"
- title={i18n.str`Invalid attributes`}
- onClose={() => onMove("attributes")}
- >
+ <Attention type="danger" title={i18n.str`Invalid attributes`}>
<i18n.Translate>
- You should check form errors or submit a decision without
- attributes.
+ Correct the selected form or continue without attaching new customer
+ information.
</i18n.Translate>
+ <ReviewStepButton onClick={() => onMove("attributes")} />
</Attention>
) : (
<div />
)}
+ <section class="mt-6 grid gap-4 rounded-lg border border-outlineVariant p-4 dark:border-gray-700">
+ <h2 class="text-lg font-semibold">
+ <i18n.Translate>Decision details</i18n.Translate>
+ </h2>
+ <div>
+ <h3 class="font-semibold">
+ <i18n.Translate>Justification</i18n.Translate>
+ </h3>
+ <p class="whitespace-pre-wrap text-sm text-gray-700 dark:text-gray-300">
+ {decision.justification || i18n.str`Not provided`}
+ </p>
+ <p class="mt-1 text-sm">
+ {decision.keep_investigating ? (
+ <i18n.Translate>
+ The account remains under investigation.
+ </i18n.Translate>
+ ) : (
+ <i18n.Translate>
+ The account will not remain under investigation.
+ </i18n.Translate>
+ )}
+ </p>
+ </div>
+ <div>
+ <h3 class="font-semibold">
+ <i18n.Translate>Properties</i18n.Translate>
+ </h3>
+ <dl class="mt-1 grid gap-x-4 text-sm sm:grid-cols-2">
+ {Object.entries({
+ ...(decision.properties ?? {}),
+ ...(decision.custom_properties ?? {}),
+ }).map(([name, value]) => (
+ <div
+ key={name}
+ class="flex justify-between gap-4 border-b border-gray-200 py-1 dark:border-gray-700"
+ >
+ <dt class="font-mono">{name}</dt>
+ <dd>{String(value)}</dd>
+ </div>
+ ))}
+ </dl>
+ {Object.keys({
+ ...(decision.properties ?? {}),
+ ...(decision.custom_properties ?? {}),
+ }).length === 0 ? (
+ <p class="mt-1 text-sm text-gray-600 dark:text-gray-300">
+ <i18n.Translate>No account properties</i18n.Translate>
+ </p>
+ ) : undefined}
+ </div>
+ <div>
+ <h3 class="font-semibold">
+ <i18n.Translate>Events</i18n.Translate>
+ </h3>
+ <p class="text-sm">
+ {recordedEvents.join(", ") || i18n.str`No events`}
+ </p>
+ </div>
+ <div>
+ <h3 class="font-semibold">
+ <i18n.Translate>Submitted attributes</i18n.Translate>
+ </h3>
+ {decision.attributes ? (
+ <p class="text-sm">
+ {decision.attributes.formId} v{decision.attributes.formVersion}
+ {decision.attributes.expiration ? (
+ <>
+ {" · "}
+ <i18n.Translate>expiration set</i18n.Translate>
+ </>
+ ) : undefined}
+ </p>
+ ) : (
+ <p class="text-sm">
+ <i18n.Translate>No new attributes</i18n.Translate>
+ </p>
+ )}
+ </div>
+ {Object.keys(decision.custom_measures ?? {}).length ? (
+ <div>
+ <h3 class="font-semibold">
+ <i18n.Translate>Custom measures</i18n.Translate>
+ </h3>
+ <p class="text-sm">
+ {Object.keys(decision.custom_measures ?? {}).join(", ")}
+ </p>
+ </div>
+ ) : undefined}
+ </section>
+
<div class="mt-2 flex justify-between">
<button
- onClick={clearUp}
- class="mt-4 disabled:opacity-50 disabled:cursor-default rounded-md px-3 py-2 text-sm font-semibold shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 "
+ type="button"
+ onClick={() => setDiscardConfirmation(true)}
+ class="mt-4 rounded-md border border-error px-3 py-2 text-sm font-semibold text-error hover:bg-errorContainer focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-error dark:border-red-300 dark:text-red-300 dark:hover:bg-red-950/50"
>
- <i18n.Translate>Clear</i18n.Translate>
+ <i18n.Translate>Discard decision</i18n.Translate>
</button>
<AsyncButton
submit
onClick={!request ? undefined : () => submit.run(request)}
- class="mt-4 disabled:opacity-50 disabled:cursor-default rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
+ class="mt-4 rounded-md bg-primary px-4 py-2 text-sm font-semibold text-onPrimary hover:bg-primary/90 disabled:cursor-not-allowed disabled:bg-gray-200 disabled:text-gray-700 disabled:hover:bg-gray-200 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary dark:bg-darkPrimary dark:text-darkOnPrimary"
>
- <i18n.Translate>Send decision</i18n.Translate>
+ <i18n.Translate>Submit AML decision</i18n.Translate>
</AsyncButton>
</div>
+ <ConfirmationModal
+ open={discardConfirmation}
+ title={i18n.str`Discard this decision?`}
+ confirmLabel={i18n.str`Discard decision`}
+ onClose={() => setDiscardConfirmation(false)}
+ onConfirm={clearUp}
+ >
+ <i18n.Translate>
+ All entries made in this decision wizard will be lost. No change will
+ be submitted to the exchange.
+ </i18n.Translate>
+ </ConfirmationModal>
</Fragment>
);
}
+
+function ReviewStepButton({ onClick }: { onClick: () => void }): VNode {
+ const { i18n } = useTranslationContext();
+ return (
+ <button
+ type="button"
+ onClick={onClick}
+ class="mt-3 block min-h-10 rounded-md border border-outline px-3 py-2 text-sm font-semibold hover:bg-surfaceContainer focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary"
+ >
+ <i18n.Translate>Review this step</i18n.Translate>
+ </button>
+ );
+}
diff --git a/packages/taler-exchange-aml-webui/src/pages/index.stories.ts b/packages/taler-exchange-aml-webui/src/pages/index.stories.ts
@@ -13,4 +13,16 @@
You should have received a copy of the GNU General Public License along with
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-// export * as a1 from "./ShowConsolidated.stories.js";
+export * as dashboard from "./Dashboard.stories.js";
+export * as accounts from "./AccountList.stories.js";
+export * as findAccount from "./Search.stories.js";
+export * as amlConfiguration from "./Info.stories.js";
+export * as accountCase from "./AccountDetails.stories.js";
+export * as accountDecisionHistory from "./AccountDecisionHistory.stories.js";
+export * as collectedInformation from "./ShowCollectedInfo.stories.js";
+export * as developer from "./Developer.stories.js";
+export * as access from "./OfficerAccess.stories.js";
+export * as decisionHistory from "../components/DecisionHistory.stories.js";
+export * as paytoTargetDetails from "../components/PaytoTargetDetails.stories.js";
+export * as decisionWizard from "./DecisionWizard.stories.js";
+export * as transfers from "./Transfers.stories.js";
diff --git a/packages/taler-exchange-aml-webui/src/scss/main.scss b/packages/taler-exchange-aml-webui/src/scss/main.scss
@@ -1,3 +1,43 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
+
+@media (prefers-color-scheme: dark) {
+ .aml-app .bg-white,
+ .aml-app .bg-gray-50,
+ .aml-app .bg-gray-100 {
+ background-color: #11131a;
+ }
+
+ .aml-app .bg-gray-200,
+ .aml-app .bg-gray-300 {
+ background-color: #1d2939;
+ }
+
+ .aml-app .text-black,
+ .aml-app .text-gray-900,
+ .aml-app .text-gray-800,
+ .aml-app .text-gray-700 {
+ color: #e2e2eb;
+ }
+
+ .aml-app .text-gray-600,
+ .aml-app .text-gray-500 {
+ color: #c4c6d0;
+ }
+
+ .aml-app .border-gray-200,
+ .aml-app .border-gray-300,
+ .aml-app .divide-gray-200,
+ .aml-app .divide-gray-300 {
+ border-color: #767880;
+ }
+
+ .aml-app input,
+ .aml-app select,
+ .aml-app textarea {
+ background-color: #11131a;
+ color: #e2e2eb;
+ border-color: #767880;
+ }
+}
diff --git a/packages/taler-exchange-aml-webui/src/stories.tsx b/packages/taler-exchange-aml-webui/src/stories.tsx
@@ -25,11 +25,25 @@ import * as pages from "./pages/index.stories.js";
import {
ExchangeApiProviderTesting,
ExchangeContextType,
+ NotificationProvider,
renderStories,
} from "@gnu-taler/web-util/browser";
-import { TalerExchangeApi } from "@gnu-taler/taler-util";
+import {
+ AbsoluteTime,
+ AmlSpaDialect,
+ TalerExchangeApi,
+ TalerExchangeHttpClient,
+ opFixedSuccess,
+} from "@gnu-taler/taler-util";
+import { dummyHttpResponse } from "@gnu-taler/taler-util/http";
import { ComponentChildren, FunctionComponent, VNode, h } from "preact";
+import { SWRConfig } from "swr";
+import { Router } from "wouter-preact";
+import { memoryLocation } from "wouter-preact/memory-location";
+import { OfficerProviderTesting, OfficerState } from "./hooks/officer.js";
+import { OfficerInfoProvider } from "./context/officer-info.js";
+import { UiFormsProvider } from "./context/ui-forms.js";
import "./scss/main.scss";
function main(): void {
@@ -42,8 +56,45 @@ function main(): void {
);
}
-function getWrapperForGroup(): FunctionComponent {
- return function All({ children }: { children?: ComponentChildren }): VNode {
+export interface StoryContextProps {
+ officer?: OfficerState;
+ officerInfo?: {
+ officer_name: string;
+ read_only: boolean;
+ };
+ exchange?: Partial<TalerExchangeHttpClient>;
+ exchangeVersion?: string;
+ amlDialect?: AmlSpaDialect;
+}
+
+const defaultOfficer: OfficerState = {
+ state: "ready",
+ session: {
+ id: "4TQZQ0M6CB0JZXJ3Z1B4H7X3EVAQXX45SB9QT0NXZYKAHQXZ3EYG" as any,
+ __signingKey: new Uint8Array(32) as any,
+ },
+ expiration: AbsoluteTime.fromMilliseconds(Date.now() + 60 * 60 * 1000),
+ lock: () => opFixedSuccess(dummyHttpResponse, undefined),
+ forget: () => opFixedSuccess(dummyHttpResponse, undefined),
+};
+
+const { hook: storyLocationHook } = memoryLocation({
+ path: "/",
+ static: true,
+});
+
+function getWrapperForGroup(): FunctionComponent<StoryContextProps> {
+ return function All({
+ children,
+ exchange,
+ exchangeVersion = "40:0:6",
+ amlDialect = AmlSpaDialect.TOPS,
+ officer = defaultOfficer,
+ officerInfo = {
+ officer_name: "Storybook AML officer",
+ read_only: false,
+ },
+ }: StoryContextProps & { children?: ComponentChildren }): VNode {
const config: TalerExchangeApi.ExchangeVersionResponse = {
currency: "ARS",
currency_specification: {
@@ -55,26 +106,51 @@ function getWrapperForGroup(): FunctionComponent {
},
name: "taler-exchange",
supported_kyc_requirements: [],
- version: "asd",
+ version: exchangeVersion,
+ aml_spa_dialect: amlDialect,
};
// @ts-expect-error don't care about the content of keys
const keys: TalerExchangeApi.ExchangeKeysResponse = {};
+ const exchangeApi = {
+ baseUrl: new URL("http://exchange.example/"),
+ ...exchange,
+ } as TalerExchangeHttpClient;
const value: ExchangeContextType = {
cancelRequest: () => null,
config: { config, keys },
url: new URL("/", "http://localhost"),
hints: [],
lib: {
- exchange: undefined!, // FIXME: mock
+ exchange: exchangeApi,
},
unthrottledApi: {
- exchange: undefined!, // FIXME: mock
+ exchange: exchangeApi,
},
onActivity: () => null!,
};
return (
<ExchangeApiProviderTesting value={value}>
- {children}
+ <NotificationProvider>
+ <SWRConfig
+ value={{
+ provider: () => new Map(),
+ dedupingInterval: 0,
+ shouldRetryOnError: false,
+ }}
+ >
+ <Router hook={storyLocationHook}>
+ <OfficerProviderTesting value={officer}>
+ <OfficerInfoProvider value={officerInfo}>
+ <UiFormsProvider>
+ <div class="aml-app min-h-screen bg-background p-4 text-onBackground dark:bg-darkBackground dark:text-darkOnBackground sm:p-8">
+ {children}
+ </div>
+ </UiFormsProvider>
+ </OfficerInfoProvider>
+ </OfficerProviderTesting>
+ </Router>
+ </SWRConfig>
+ </NotificationProvider>
</ExchangeApiProviderTesting>
);
};
diff --git a/packages/taler-exchange-aml-webui/src/utils/computeAvailableMesaures.test.ts b/packages/taler-exchange-aml-webui/src/utils/computeAvailableMesaures.test.ts
@@ -0,0 +1,32 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+import { AvailableMeasureSummary } from "@gnu-taler/taler-util";
+import assert from "node:assert/strict";
+import test from "node:test";
+import { computeMeasureInformation } from "./computeAvailableMesaures.js";
+
+test("lowercase skip measures remain available as procedures", () => {
+ const summary: AvailableMeasureSummary = {
+ roots: {
+ automatic: { check_name: "skip", prog_name: "review" },
+ },
+ checks: {},
+ programs: {
+ review: { description: "Review account", context: [], inputs: [] },
+ },
+ default_rules: [],
+ };
+ const measures = computeMeasureInformation(summary);
+ assert.deepEqual(
+ measures.procedures.map(({ name, programName }) => ({ name, programName })),
+ [{ name: "automatic", programName: "review" }],
+ );
+ assert.deepEqual(measures.forms, []);
+ assert.deepEqual(measures.info, []);
+});
diff --git a/packages/taler-exchange-aml-webui/src/utils/computeAvailableMesaures.ts b/packages/taler-exchange-aml-webui/src/utils/computeAvailableMesaures.ts
@@ -19,6 +19,7 @@ import type {
KycCheckInformation,
MeasureInformation,
} from "@gnu-taler/taler-util";
+import { isBuiltInSkipCheck } from "./measure-check.js";
export type MeasureInfo = ProcedureMeasure | FormMeasure | InfoMeasure;
@@ -114,24 +115,28 @@ function buildMeasureInformation(
name: string | undefined,
measure: MeasureInformation,
): MeasureInfo | undefined {
- if (measure.check_name !== "SKIP") {
+ if (!isBuiltInSkipCheck(measure.check_name)) {
+ const check = serverMeasures.checks[measure.check_name];
+ if (!check) return undefined;
if (!measure.prog_name) {
const r: MeasureInfo = {
type: "info",
name: name ?? "",
context: measure.context,
checkName: measure.check_name,
- check: serverMeasures.checks[measure.check_name],
+ check,
// custom: true,
};
return r;
} else {
+ const program = serverMeasures.programs[measure.prog_name];
+ if (!program) return undefined;
const r: MeasureInfo = {
type: "form",
name: name ?? "",
context: measure.context,
programName: measure.prog_name,
- program: serverMeasures.programs[measure.prog_name],
+ program,
checkName: measure.check_name,
check: serverMeasures.checks[measure.check_name],
// custom: false,
@@ -143,12 +148,14 @@ function buildMeasureInformation(
console.error(`ERROR: program name can't be empty for measure "${name}"`);
return undefined;
}
+ const program = serverMeasures.programs[measure.prog_name];
+ if (!program) return undefined;
const r: MeasureInfo = {
type: "procedure",
name: name ?? "",
context: measure.context,
programName: measure.prog_name,
- program: serverMeasures.programs[measure.prog_name],
+ program,
// custom: false,
};
return r;
diff --git a/packages/taler-exchange-aml-webui/src/utils/decision-dialect.test.ts b/packages/taler-exchange-aml-webui/src/utils/decision-dialect.test.ts
@@ -0,0 +1,85 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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 assert from "node:assert";
+import { test } from "node:test";
+import {
+ AbsoluteTime,
+ AmlSpaDialect,
+ TalerAmlProperties,
+ TalerFormAttributes,
+ TOPS_AmlEventsName,
+} from "@gnu-taler/taler-util";
+import { DecisionRequest } from "../hooks/decision-request.js";
+import { calculateEventsBasedOnState } from "../pages/decision/Events.js";
+import { calculatePropertiesBasedOnState } from "../pages/decision/Properties.js";
+
+function accountOpeningDecision(): DecisionRequest {
+ return {
+ attributes: {
+ formId: "vqf_902_1_officer",
+ formVersion: 1,
+ formSalt: "SALT",
+ expiration: AbsoluteTime.never(),
+ data: {
+ [TalerFormAttributes.FORM_ID]: "vqf_902_1_officer",
+ },
+ },
+ properties: {
+ [TalerAmlProperties.ACCOUNT_OPEN]: true,
+ },
+ };
+}
+
+test("TOPS derives account state and reporting events", () => {
+ const decision = accountOpeningDecision();
+ const properties = calculatePropertiesBasedOnState(
+ {
+ OPERATOR_PROPERTY: 7,
+ [TalerAmlProperties.FILE_NOTE]: "Keep this note",
+ },
+ decision,
+ AmlSpaDialect.TOPS,
+ );
+ assert.strictEqual(properties[TalerAmlProperties.ACCOUNT_OPEN], true);
+ assert.strictEqual(
+ properties[TalerAmlProperties.FILE_NOTE],
+ "Keep this note",
+ );
+ assert.strictEqual(properties.OPERATOR_PROPERTY, 7);
+
+ const events = calculateEventsBasedOnState(
+ undefined,
+ decision,
+ AmlSpaDialect.TOPS,
+ );
+ assert.ok(events.triggered.includes(TOPS_AmlEventsName.INCR_ACCOUNT_OPEN));
+});
+
+test("testing dialect does not apply TOPS derivation", () => {
+ const decision = accountOpeningDecision();
+ const properties = calculatePropertiesBasedOnState(
+ { OPERATOR_PROPERTY: 7 },
+ decision,
+ AmlSpaDialect.TESTING,
+ );
+ assert.deepStrictEqual(properties, { OPERATOR_PROPERTY: 7 });
+
+ assert.deepStrictEqual(
+ calculateEventsBasedOnState(undefined, decision, AmlSpaDialect.TESTING),
+ { triggered: [], rest: [] },
+ );
+});
diff --git a/packages/taler-exchange-aml-webui/src/utils/decision-validation.test.ts b/packages/taler-exchange-aml-webui/src/utils/decision-validation.test.ts
@@ -11,11 +11,13 @@ import assert from "node:assert";
import { test } from "node:test";
import {
AbsoluteTime,
+ AmountString,
AvailableMeasureSummary,
+ Duration,
+ LimitOperationType,
TalerFormAttributes,
} from "@gnu-taler/taler-util";
import { DecisionRequest } from "../hooks/decision-request.js";
-import { decisionTargetsMatch } from "../hooks/decision-request.js";
import {
attributesAreComplete,
buildAmlDecisionRequest,
@@ -24,7 +26,7 @@ import {
const measureSummary: AvailableMeasureSummary = {
roots: {
review: { check_name: "review" },
- skipOne: { check_name: "SKIP" },
+ skipOne: { check_name: "skip" },
skipTwo: { check_name: "SKIP" },
},
programs: {},
@@ -36,7 +38,7 @@ function completeDecision(): DecisionRequest {
return {
rules: [],
deadline: AbsoluteTime.never(),
- properties: { builtin: true },
+ properties: { builtin: true, score: 42 },
custom_properties: { custom: "value" },
triggering_events: ["KNOWN"],
custom_events: ["CUSTOM", "KNOWN"],
@@ -57,6 +59,7 @@ test("decision builder preserves custom state and AND measures", () => {
assert.deepStrictEqual(result.errors, []);
assert.deepStrictEqual(result.request?.properties, {
builtin: true,
+ score: 42,
custom: "value",
});
assert.deepStrictEqual(result.request?.events, ["KNOWN", "CUSTOM"]);
@@ -66,7 +69,10 @@ test("decision builder preserves custom state and AND measures", () => {
test("attribute uploads require salt and a future expiration", () => {
const decision = completeDecision();
decision.attributes = {
- data: { answer: 42 },
+ data: {
+ answer: 42,
+ [TalerFormAttributes.FORM_CONTEXT]: { requested: "passport" },
+ },
formId: "example",
formVersion: 3,
formSalt: "HIGH_ENTROPY_SALT",
@@ -85,6 +91,17 @@ test("attribute uploads require salt and a future expiration", () => {
],
"HIGH_ENTROPY_SALT",
);
+ assert.deepStrictEqual(
+ (result.request?.attributes as Record<string, unknown> | undefined)?.[
+ TalerFormAttributes.FORM_CONTEXT
+ ],
+ { requested: "passport" },
+ );
+ decision.attributes.expiration = undefined;
+ assert.strictEqual(attributesAreComplete(decision), false);
+ decision.attributes.expiration = AbsoluteTime.fromMilliseconds(0);
+ assert.strictEqual(attributesAreComplete(decision), false);
+ decision.attributes.expiration = AbsoluteTime.never();
delete decision.attributes.formSalt;
assert.strictEqual(attributesAreComplete(decision), false);
});
@@ -103,6 +120,65 @@ test("decision builder rejects stale and incompatible measure references", () =>
assert.strictEqual(result.request, undefined);
});
+test("decision builder rejects invalid rules and expired deadlines", () => {
+ const decision = completeDecision();
+ decision.deadline = AbsoluteTime.fromMilliseconds(1_000);
+ decision.rules = [
+ {
+ operation_type: LimitOperationType.balance,
+ measures: [],
+ display_priority: 100,
+ threshold: "KUDOS:10" as AmountString,
+ timeframe: Duration.toTalerProtocolDuration(
+ Duration.fromSpec({ days: 1 }),
+ ),
+ },
+ ];
+ const result = buildAmlDecisionRequest({
+ account: "ACCOUNT",
+ fullPayto: undefined,
+ decision,
+ measures: measureSummary,
+ now: AbsoluteTime.fromMilliseconds(2_000),
+ });
+ assert.ok(result.errors.includes("invalid-rules"));
+ assert.ok(result.errors.includes("expired-deadline"));
+});
+
+test("decision builder preserves proposed rule priorities", () => {
+ const decision = completeDecision();
+ decision.rules = [
+ {
+ operation_type: LimitOperationType.withdraw,
+ measures: ["review"],
+ display_priority: 99,
+ threshold: "KUDOS:10" as AmountString,
+ timeframe: Duration.toTalerProtocolDuration(
+ Duration.fromSpec({ days: 1 }),
+ ),
+ },
+ {
+ operation_type: LimitOperationType.deposit,
+ measures: ["VERBOTEN"],
+ display_priority: 99,
+ threshold: "KUDOS:20" as AmountString,
+ timeframe: Duration.toTalerProtocolDuration(
+ Duration.fromSpec({ days: 1 }),
+ ),
+ },
+ ];
+ const result = buildAmlDecisionRequest({
+ account: "ACCOUNT",
+ fullPayto: undefined,
+ decision,
+ measures: measureSummary,
+ });
+ assert.deepEqual(
+ result.request?.new_rules.rules.map((entry) => entry.display_priority),
+ [99, 99],
+ );
+});
+
test("custom properties cannot replace built-in properties", () => {
const decision = completeDecision();
decision.custom_properties = { builtin: "replacement" };
@@ -115,22 +191,22 @@ test("custom properties cannot replace built-in properties", () => {
assert.ok(result.errors.includes("invalid-properties"));
});
-test("decision draft targets cannot cross officers or accounts", () => {
- const target = { officerId: "OFFICER", account: "ACCOUNT" };
- assert.strictEqual(decisionTargetsMatch(target, target), true);
- assert.strictEqual(
- decisionTargetsMatch(target, { ...target, account: "OTHER" }),
- false,
- );
- assert.strictEqual(
- decisionTargetsMatch(target, { ...target, officerId: "OTHER" }),
- false,
- );
- assert.strictEqual(
- decisionTargetsMatch(
- { ...target, fullPayto: "payto://iban/one" },
- { ...target, fullPayto: "payto://iban/two" },
- ),
- false,
- );
+test("custom measures must satisfy check and program requirements", () => {
+ const decision = completeDecision();
+ decision.custom_measures = {
+ invalid: {
+ check_name: "missing-check",
+ prog_name: "missing-program",
+ context: {},
+ },
+ };
+ decision.new_measures = ["invalid"];
+ const result = buildAmlDecisionRequest({
+ account: "ACCOUNT",
+ fullPayto: undefined,
+ decision,
+ measures: measureSummary,
+ });
+ assert.ok(result.errors.includes("invalid-custom-measure"));
+ assert.strictEqual(result.request, undefined);
});
diff --git a/packages/taler-exchange-aml-webui/src/utils/decision-validation.ts b/packages/taler-exchange-aml-webui/src/utils/decision-validation.ts
@@ -15,11 +15,19 @@ import {
TalerFormAttributes,
} from "@gnu-taler/taler-util";
import { DecisionRequest } from "../hooks/decision-request.js";
+import { isBuiltInSkipCheck } from "./measure-check.js";
+import {
+ deadlineIsValid,
+ isVerbotenMeasure,
+ rulesAreValid,
+} from "./rule-validation.js";
export type DecisionValidationError =
| "missing-account"
| "missing-rules"
| "missing-deadline"
+ | "invalid-rules"
+ | "expired-deadline"
| "missing-properties"
| "invalid-properties"
| "missing-events"
@@ -28,6 +36,7 @@ export type DecisionValidationError =
| "missing-account-name"
| "invalid-attributes"
| "missing-measure-metadata"
+ | "invalid-custom-measure"
| "unknown-measure"
| "multiple-skip-measures"
| "invalid-payto";
@@ -73,9 +82,18 @@ export function buildAmlDecisionRequest({
if (!account) errors.push("missing-account");
if (!decision.rules) errors.push("missing-rules");
if (!decision.deadline) errors.push("missing-deadline");
+ if (decision.rules && !rulesAreValid(decision.rules)) {
+ errors.push("invalid-rules");
+ }
+ if (decision.deadline && !deadlineIsValid(decision.deadline, now)) {
+ errors.push("expired-deadline");
+ }
if (!decision.properties) errors.push("missing-properties");
if (decision.properties_errors) errors.push("invalid-properties");
- if (decision.triggering_events === undefined || decision.custom_events === undefined) {
+ if (
+ decision.triggering_events === undefined ||
+ decision.custom_events === undefined
+ ) {
errors.push("missing-events");
}
if (decision.new_measures === undefined) errors.push("missing-measures");
@@ -102,6 +120,32 @@ export function buildAmlDecisionRequest({
...Object.entries(measures?.roots ?? {}),
...Object.entries(decision.custom_measures ?? {}),
]);
+ for (const measure of Object.values(decision.custom_measures ?? {})) {
+ const check = isBuiltInSkipCheck(measure.check_name)
+ ? undefined
+ : measures?.checks[measure.check_name];
+ const program = measure.prog_name
+ ? measures?.programs[measure.prog_name]
+ : undefined;
+ const contextKeys = new Set(Object.keys(measure.context ?? {}));
+ const missingCheckContext =
+ !isBuiltInSkipCheck(measure.check_name) &&
+ (!check || check.requires.some((name) => !contextKeys.has(name)));
+ const missingProgramContext =
+ !!measure.prog_name &&
+ (!program || program.context.some((name) => !contextKeys.has(name)));
+ const incompatibleProgramInputs =
+ !!program?.inputs.length &&
+ (!check || program.inputs.some((name) => !check.outputs.includes(name)));
+ if (
+ missingCheckContext ||
+ missingProgramContext ||
+ incompatibleProgramInputs ||
+ (isBuiltInSkipCheck(measure.check_name) && !program)
+ ) {
+ errors.push("invalid-custom-measure");
+ }
+ }
const immediateMeasures = normalizedNames(decision.new_measures ?? []);
const referencedMeasures = [
...immediateMeasures,
@@ -109,12 +153,12 @@ export function buildAmlDecisionRequest({
decision.onExpire_measure,
];
for (const name of normalizedNames(referencedMeasures)) {
- if (name !== "VERBOTEN" && !knownMeasures.has(name)) {
+ if (!isVerbotenMeasure(name) && !knownMeasures.has(name)) {
errors.push("unknown-measure");
}
}
- const skipCount = immediateMeasures.filter(
- (name) => knownMeasures.get(name)?.check_name === "SKIP",
+ const skipCount = immediateMeasures.filter((name) =>
+ isBuiltInSkipCheck(knownMeasures.get(name)?.check_name),
).length;
if (skipCount > 1) errors.push("multiple-skip-measures");
diff --git a/packages/taler-exchange-aml-webui/src/utils/dialect-info.test.ts b/packages/taler-exchange-aml-webui/src/utils/dialect-info.test.ts
@@ -0,0 +1,49 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import {
+ AmlSpaDialect,
+ i18n,
+ setupI18n,
+ TOPS_AccountProperties,
+ TOPS_AmlEventsName,
+} from "@gnu-taler/taler-util";
+import assert from "node:assert/strict";
+import test from "node:test";
+import { getDialectInfo } from "./dialect-info.js";
+
+setupI18n("en", {});
+
+test("TOPS metadata covers every canonical property and event", () => {
+ const dialect = getDialectInfo(AmlSpaDialect.TOPS, i18n);
+
+ assert.deepEqual(
+ dialect.properties.map((property) => property.id),
+ [...TOPS_AccountProperties],
+ );
+ assert.deepEqual(
+ dialect.events.map((event) => event.id),
+ Object.values(TOPS_AmlEventsName),
+ );
+ for (const property of dialect.properties) {
+ assert.ok(property.name);
+ assert.ok(property.description);
+ assert.ok(property.valueType);
+ }
+ for (const event of dialect.events) {
+ assert.ok(event.name);
+ assert.ok(event.description);
+ }
+});
+
+test("testing dialect explicitly has no canonical catalog", () => {
+ const dialect = getDialectInfo(AmlSpaDialect.TESTING, i18n);
+ assert.deepEqual(dialect.properties, []);
+ assert.deepEqual(dialect.events, []);
+});
diff --git a/packages/taler-exchange-aml-webui/src/utils/dialect-info.ts b/packages/taler-exchange-aml-webui/src/utils/dialect-info.ts
@@ -0,0 +1,256 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import {
+ AmlSpaDialect,
+ InternationalizationAPI,
+ TalerAmlProperties,
+ TOPS_AmlEventsName,
+ TranslatedString,
+} from "@gnu-taler/taler-util";
+
+export interface DialectPropertyInfo {
+ id: string;
+ name: TranslatedString;
+ description: TranslatedString;
+ valueType: TranslatedString;
+}
+
+export interface DialectEventInfo {
+ id: string;
+ name: TranslatedString;
+ description: TranslatedString;
+}
+
+export interface DialectInfo {
+ name: TranslatedString;
+ description: TranslatedString;
+ properties: DialectPropertyInfo[];
+ events: DialectEventInfo[];
+}
+
+export function getDialectInfo(
+ dialect: AmlSpaDialect,
+ i18n: InternationalizationAPI,
+): DialectInfo {
+ if (dialect === AmlSpaDialect.TESTING) {
+ return {
+ name: i18n.str`Testing`,
+ description: i18n.str`Fallback dialect for development and testing.`,
+ properties: [],
+ events: [],
+ };
+ }
+
+ return {
+ name: i18n.str`TOPS`,
+ description: i18n.str`Taler Operations deployment for Swiss AML processes.`,
+ properties: [
+ property(
+ TalerAmlProperties.FILE_NOTE,
+ i18n.str`File note`,
+ i18n.str`Current note on the GwG file.`,
+ i18n.str`Text`,
+ ),
+ property(
+ TalerAmlProperties.CUSTOMER_LABEL,
+ i18n.str`Customer label`,
+ i18n.str`Customer name or internal alias.`,
+ i18n.str`Text`,
+ ),
+ property(
+ TalerAmlProperties.ACCOUNT_OPEN,
+ i18n.str`Account open`,
+ i18n.str`Whether the account is active for deposits and payments.`,
+ i18n.str`Boolean`,
+ ),
+ property(
+ TalerAmlProperties.PEP_DOMESTIC,
+ i18n.str`Domestic PEP`,
+ i18n.str`Whether the customer is a domestic politically exposed person.`,
+ i18n.str`Boolean`,
+ ),
+ property(
+ TalerAmlProperties.PEP_FOREIGN,
+ i18n.str`Foreign PEP`,
+ i18n.str`Whether the customer is a foreign politically exposed person.`,
+ i18n.str`Boolean`,
+ ),
+ property(
+ TalerAmlProperties.PEP_INTERNATIONAL_ORGANIZATION,
+ i18n.str`International-organization PEP`,
+ i18n.str`Whether the customer is a politically exposed person associated with an international organization.`,
+ i18n.str`Boolean`,
+ ),
+ property(
+ TalerAmlProperties.HIGH_RISK_CUSTOMER,
+ i18n.str`High-risk customer`,
+ i18n.str`Whether the customer is classified as high risk.`,
+ i18n.str`Boolean`,
+ ),
+ property(
+ TalerAmlProperties.HIGH_RISK_COUNTRY,
+ i18n.str`High-risk country`,
+ i18n.str`Whether the customer is associated with a high-risk country.`,
+ i18n.str`Boolean`,
+ ),
+ property(
+ TalerAmlProperties.ACCOUNT_IDLE,
+ i18n.str`Account idle`,
+ i18n.str`Whether the account has been marked as idle.`,
+ i18n.str`Boolean`,
+ ),
+ property(
+ TalerAmlProperties.INVESTIGATION_TRIGGER,
+ i18n.str`Investigation trigger`,
+ i18n.str`Informal reason why the AML investigation was triggered.`,
+ i18n.str`Text`,
+ ),
+ property(
+ TalerAmlProperties.INVESTIGATION_STATE,
+ i18n.str`Investigation state`,
+ i18n.str`Special-clarification and MROS reporting state for the account.`,
+ i18n.str`Enumeration`,
+ ),
+ property(
+ TalerAmlProperties.SANCTION_LIST_BEST_MATCH,
+ i18n.str`Sanction-list best match`,
+ i18n.str`Sanction-list entry that best matched the account, regardless of match quality.`,
+ i18n.str`Text`,
+ ),
+ property(
+ TalerAmlProperties.SANCTION_LIST_RATING,
+ i18n.str`Sanction-list rating`,
+ i18n.str`Score from 0 (no match) to 1,000,000,000 (best match).`,
+ i18n.str`Integer`,
+ ),
+ property(
+ TalerAmlProperties.SANCTION_LIST_CONFIDENCE,
+ i18n.str`Sanction-list confidence`,
+ i18n.str`Score from 0 (no supporting data) to 1,000,000,000 (highest confidence).`,
+ i18n.str`Integer`,
+ ),
+ property(
+ TalerAmlProperties.SANCTION_LIST_SUPPRESS,
+ i18n.str`Suppress sanction-list match`,
+ i18n.str`Whether this account's sanction-list hit is treated as a false positive.`,
+ i18n.str`Boolean`,
+ ),
+ ],
+ events: [
+ event(
+ TOPS_AmlEventsName.INCR_ACCOUNT_OPEN,
+ i18n.str`Account opened`,
+ i18n.str`Recorded when an account changes to open.`,
+ ),
+ event(
+ TOPS_AmlEventsName.DECR_ACCOUNT_OPEN,
+ i18n.str`Account closed`,
+ i18n.str`Recorded when an account changes from open to closed.`,
+ ),
+ event(
+ TOPS_AmlEventsName.INCR_HIGH_RISK_CUSTOMER,
+ i18n.str`High-risk customer classification added`,
+ i18n.str`Recorded when an open account becomes classified as a high-risk customer.`,
+ ),
+ event(
+ TOPS_AmlEventsName.DECR_HIGH_RISK_CUSTOMER,
+ i18n.str`High-risk customer classification removed`,
+ i18n.str`Recorded when the high-risk customer classification is removed.`,
+ ),
+ event(
+ TOPS_AmlEventsName.INCR_HIGH_RISK_COUNTRY,
+ i18n.str`High-risk country classification added`,
+ i18n.str`Recorded when an open account becomes associated with a high-risk country.`,
+ ),
+ event(
+ TOPS_AmlEventsName.DECR_HIGH_RISK_COUNTRY,
+ i18n.str`High-risk country classification removed`,
+ i18n.str`Recorded when the high-risk country classification is removed.`,
+ ),
+ event(
+ TOPS_AmlEventsName.INCR_PEP,
+ i18n.str`PEP classification added`,
+ i18n.str`Recorded when an open account becomes associated with any PEP category.`,
+ ),
+ event(
+ TOPS_AmlEventsName.DECR_PEP,
+ i18n.str`PEP classification removed`,
+ i18n.str`Recorded when the account is no longer associated with any PEP category.`,
+ ),
+ event(
+ TOPS_AmlEventsName.INCR_PEP_FOREIGN,
+ i18n.str`Foreign PEP classification added`,
+ i18n.str`Recorded when an open account becomes associated with a foreign PEP.`,
+ ),
+ event(
+ TOPS_AmlEventsName.DECR_PEP_FOREIGN,
+ i18n.str`Foreign PEP classification removed`,
+ i18n.str`Recorded when the foreign PEP classification is removed.`,
+ ),
+ event(
+ TOPS_AmlEventsName.INCR_PEP_DOMESTIC,
+ i18n.str`Domestic PEP classification added`,
+ i18n.str`Recorded when an open account becomes associated with a domestic PEP.`,
+ ),
+ event(
+ TOPS_AmlEventsName.DECR_PEP_DOMESTIC,
+ i18n.str`Domestic PEP classification removed`,
+ i18n.str`Recorded when the domestic PEP classification is removed.`,
+ ),
+ event(
+ TOPS_AmlEventsName.INCR_PEP_INTERNATIONAL_ORGANIZATION,
+ i18n.str`International-organization PEP classification added`,
+ i18n.str`Recorded when an open account becomes associated with an international-organization PEP.`,
+ ),
+ event(
+ TOPS_AmlEventsName.DECR_PEP_INTERNATIONAL_ORGANIZATION,
+ i18n.str`International-organization PEP classification removed`,
+ i18n.str`Recorded when the international-organization PEP classification is removed.`,
+ ),
+ event(
+ TOPS_AmlEventsName.MROS_REPORTED_SUSPICION_SIMPLE,
+ i18n.str`Simple suspicion reported to MROS`,
+ i18n.str`Recorded when a report is filed under Article 305ter paragraph 2 StGB.`,
+ ),
+ event(
+ TOPS_AmlEventsName.MROS_REPORTED_SUSPICION_SUBSTANTIATED,
+ i18n.str`Substantiated suspicion reported to MROS`,
+ i18n.str`Recorded when a report is filed under Article 9 GwG.`,
+ ),
+ event(
+ TOPS_AmlEventsName.INCR_INVESTIGATION_CONCLUDED,
+ i18n.str`Investigation concluded`,
+ i18n.str`Recorded when a pending special clarification is concluded.`,
+ ),
+ event(
+ TOPS_AmlEventsName.DECR_INVESTIGATION_CONCLUDED,
+ i18n.str`Investigation conclusion reversed`,
+ i18n.str`Recorded when a previously concluded investigation returns to a non-concluded state.`,
+ ),
+ ],
+ };
+}
+
+function property(
+ id: string,
+ name: TranslatedString,
+ description: TranslatedString,
+ valueType: TranslatedString,
+): DialectPropertyInfo {
+ return { id, name, description, valueType };
+}
+
+function event(
+ id: string,
+ name: TranslatedString,
+ description: TranslatedString,
+): DialectEventInfo {
+ return { id, name, description };
+}
diff --git a/packages/taler-exchange-aml-webui/src/utils/dialect.test.ts b/packages/taler-exchange-aml-webui/src/utils/dialect.test.ts
@@ -0,0 +1,45 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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 { AmlSpaDialect } from "@gnu-taler/taler-util";
+import assert from "node:assert";
+import { test } from "node:test";
+import { resolveAmlSpaDialect } from "./dialect.js";
+
+test("uses the exchange AML SPA dialect without an override", () => {
+ assert.strictEqual(
+ resolveAmlSpaDialect(AmlSpaDialect.TOPS, undefined),
+ AmlSpaDialect.TOPS,
+ );
+});
+
+test("uses an explicit AML SPA dialect override", () => {
+ assert.strictEqual(
+ resolveAmlSpaDialect(AmlSpaDialect.TOPS, AmlSpaDialect.TESTING),
+ AmlSpaDialect.TESTING,
+ );
+ assert.strictEqual(
+ resolveAmlSpaDialect(AmlSpaDialect.TESTING, AmlSpaDialect.TOPS),
+ AmlSpaDialect.TOPS,
+ );
+});
+
+test("defaults to the testing dialect when the exchange omits it", () => {
+ assert.strictEqual(
+ resolveAmlSpaDialect(undefined, undefined),
+ AmlSpaDialect.TESTING,
+ );
+});
diff --git a/packages/taler-exchange-aml-webui/src/utils/dialect.ts b/packages/taler-exchange-aml-webui/src/utils/dialect.ts
@@ -0,0 +1,24 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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 { AmlSpaDialect } from "@gnu-taler/taler-util";
+
+export function resolveAmlSpaDialect(
+ configuredDialect: AmlSpaDialect | undefined,
+ override: AmlSpaDialect | undefined,
+): AmlSpaDialect {
+ return override ?? configuredDialect ?? AmlSpaDialect.TESTING;
+}
diff --git a/packages/taler-exchange-aml-webui/src/utils/measure-check.test.ts b/packages/taler-exchange-aml-webui/src/utils/measure-check.test.ts
@@ -0,0 +1,20 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+import assert from "node:assert/strict";
+import test from "node:test";
+import { BUILT_IN_SKIP_CHECK, isBuiltInSkipCheck } from "./measure-check.js";
+
+test("the built-in skip check is case-insensitive and canonically lowercase", () => {
+ assert.equal(BUILT_IN_SKIP_CHECK, "skip");
+ assert.equal(isBuiltInSkipCheck("skip"), true);
+ assert.equal(isBuiltInSkipCheck("SKIP"), true);
+ assert.equal(isBuiltInSkipCheck("Skip"), true);
+ assert.equal(isBuiltInSkipCheck("skip-form"), false);
+ assert.equal(isBuiltInSkipCheck(undefined), false);
+});
diff --git a/packages/taler-exchange-aml-webui/src/utils/measure-check.ts b/packages/taler-exchange-aml-webui/src/utils/measure-check.ts
@@ -0,0 +1,14 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+export const BUILT_IN_SKIP_CHECK = "skip";
+
+export function isBuiltInSkipCheck(name: string | undefined): boolean {
+ return name?.toLowerCase() === BUILT_IN_SKIP_CHECK;
+}
diff --git a/packages/taler-exchange-aml-webui/src/utils/rule-defaults.test.ts b/packages/taler-exchange-aml-webui/src/utils/rule-defaults.test.ts
@@ -0,0 +1,76 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import {
+ AbsoluteTime,
+ AmountString,
+ AvailableMeasureSummary,
+ KycRule,
+ LegitimizationRuleSet,
+ LimitOperationType,
+} from "@gnu-taler/taler-util";
+import assert from "node:assert/strict";
+import test from "node:test";
+import { effectiveRuleLimits, initialRuleDraft } from "./rule-defaults.js";
+
+function rule(operation_type: LimitOperationType): KycRule {
+ return {
+ operation_type,
+ threshold: "EUR:10" as AmountString,
+ timeframe: { d_us: 0 },
+ measures: ["review"],
+ display_priority: 0,
+ exposed: true,
+ is_and_combinator: false,
+ };
+}
+
+const bankRule = rule(LimitOperationType.deposit);
+const walletRule = rule(LimitOperationType.balance);
+const sharedRule = rule(LimitOperationType.transaction);
+const measures: AvailableMeasureSummary = {
+ roots: {},
+ programs: {},
+ checks: {},
+ default_rules: [bankRule, walletRule, sharedRule],
+};
+
+test("an active decision is preserved even when it has no rules", () => {
+ const current: LegitimizationRuleSet = {
+ rules: [],
+ expiration_time: { t_s: 2_000_000_000 },
+ successor_measure: "manual-review",
+ custom_measures: { custom: { check_name: "skip" } },
+ };
+
+ assert.equal(effectiveRuleLimits(current, measures, false), current);
+ assert.deepEqual(initialRuleDraft(current), {
+ rules: [],
+ deadline: AbsoluteTime.fromProtocolTimestamp(current.expiration_time),
+ onExpire_measure: "manual-review",
+ custom_measures: current.custom_measures,
+ rules_reviewed: false,
+ });
+});
+
+test("new bank and wallet accounts receive only applicable defaults", () => {
+ const bank = effectiveRuleLimits(undefined, measures, false);
+ const wallet = effectiveRuleLimits(undefined, measures, true);
+
+ assert.deepEqual(bank.rules, [bankRule, sharedRule]);
+ assert.deepEqual(wallet.rules, [walletRule, sharedRule]);
+ assert.equal(
+ AbsoluteTime.isNever(
+ AbsoluteTime.fromProtocolTimestamp(bank.expiration_time),
+ ),
+ true,
+ );
+ assert.equal(bank.successor_measure, undefined);
+ assert.deepEqual(bank.custom_measures, {});
+});
diff --git a/packages/taler-exchange-aml-webui/src/utils/rule-defaults.ts b/packages/taler-exchange-aml-webui/src/utils/rule-defaults.ts
@@ -0,0 +1,60 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import {
+ AbsoluteTime,
+ AvailableMeasureSummary,
+ KycRule,
+ LegitimizationRuleSet,
+ MeasureInformation,
+} from "@gnu-taler/taler-util";
+import { BANK_RULES, WALLET_RULES } from "./rule-validation.js";
+
+export interface InitialRuleDraft {
+ rules: KycRule[];
+ deadline: AbsoluteTime;
+ onExpire_measure?: string;
+ custom_measures: Record<string, MeasureInformation>;
+ rules_reviewed: false;
+}
+
+export function defaultRulesForAccount(
+ measureSummary: AvailableMeasureSummary,
+ isWallet: boolean,
+): KycRule[] {
+ const applicableOperations = isWallet ? WALLET_RULES : BANK_RULES;
+ return measureSummary.default_rules.filter((rule) =>
+ applicableOperations.includes(rule.operation_type),
+ );
+}
+
+export function effectiveRuleLimits(
+ currentLimits: LegitimizationRuleSet | undefined,
+ measureSummary: AvailableMeasureSummary,
+ isWallet: boolean,
+): LegitimizationRuleSet {
+ if (currentLimits !== undefined) return currentLimits;
+ return {
+ custom_measures: {},
+ expiration_time: AbsoluteTime.toProtocolTimestamp(AbsoluteTime.never()),
+ rules: defaultRulesForAccount(measureSummary, isWallet),
+ };
+}
+
+export function initialRuleDraft(
+ limits: LegitimizationRuleSet,
+): InitialRuleDraft {
+ return {
+ rules: limits.rules,
+ deadline: AbsoluteTime.fromProtocolTimestamp(limits.expiration_time),
+ onExpire_measure: limits.successor_measure,
+ custom_measures: limits.custom_measures,
+ rules_reviewed: false,
+ };
+}
diff --git a/packages/taler-exchange-aml-webui/src/utils/rule-validation.test.ts b/packages/taler-exchange-aml-webui/src/utils/rule-validation.test.ts
@@ -0,0 +1,112 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import assert from "node:assert/strict";
+import test from "node:test";
+import {
+ AbsoluteTime,
+ AmountString,
+ Duration,
+ KycRule,
+ LimitOperationType,
+} from "@gnu-taler/taler-util";
+import {
+ applicabilityWarnings,
+ deadlineIsValid,
+ removeRuleAt,
+ saveRuleAt,
+ validateRule,
+} from "./rule-validation.js";
+
+function rule(
+ operation_type: LimitOperationType,
+ measures: string[] = ["review"],
+ display_priority = 0,
+): KycRule {
+ return {
+ operation_type,
+ measures,
+ display_priority,
+ threshold: "KUDOS:10" as AmountString,
+ timeframe: Duration.toTalerProtocolDuration(Duration.fromSpec({ days: 1 })),
+ };
+}
+
+test("hard blocks must be explicit and exclusive", () => {
+ assert.deepEqual(validateRule(rule(LimitOperationType.withdraw, [])), [
+ "empty-measures",
+ ]);
+ assert.deepEqual(
+ validateRule(rule(LimitOperationType.withdraw, ["VERBOTEN", "review"])),
+ ["mixed-verboten"],
+ );
+ assert.deepEqual(
+ validateRule(rule(LimitOperationType.withdraw, ["VERBOTEN"])),
+ [],
+ );
+});
+
+test("balance and refund use an instant timeframe", () => {
+ assert.deepEqual(validateRule(rule(LimitOperationType.balance)), [
+ "invalid-instant-timeframe",
+ ]);
+ const instant = rule(LimitOperationType.refund);
+ instant.timeframe = Duration.toTalerProtocolDuration(Duration.fromSpec({}));
+ assert.deepEqual(validateRule(instant), []);
+});
+
+test("applicability warnings name only missing and unexpected operations", () => {
+ const warnings = applicabilityWarnings(true, [
+ rule(LimitOperationType.balance),
+ rule(LimitOperationType.deposit),
+ ]);
+ assert.deepEqual(warnings.unexpected, [LimitOperationType.deposit]);
+ assert.deepEqual(warnings.missing, [
+ LimitOperationType.merge,
+ LimitOperationType.refund,
+ LimitOperationType.transaction,
+ ]);
+});
+
+test("adding, editing, and removing rules preserves explicit priorities", () => {
+ const withdraw = rule(LimitOperationType.withdraw, ["review"], 7);
+ const deposit = rule(LimitOperationType.deposit, ["review"], 0);
+ const aggregate = rule(LimitOperationType.aggregate, ["review"], -2);
+ const added = saveRuleAt([withdraw], deposit);
+ assert.deepEqual(
+ added.map((entry) => [entry.operation_type, entry.display_priority]),
+ [
+ [LimitOperationType.withdraw, 7],
+ [LimitOperationType.deposit, 0],
+ ],
+ );
+ const edited = saveRuleAt(added, aggregate, 0);
+ assert.deepEqual(
+ edited.map((entry) => entry.operation_type),
+ [LimitOperationType.aggregate, LimitOperationType.deposit],
+ );
+ assert.deepEqual(
+ removeRuleAt(edited, 1).map((entry) => [
+ entry.operation_type,
+ entry.display_priority,
+ ]),
+ [[LimitOperationType.aggregate, -2]],
+ );
+});
+
+test("deadlines must be in the future or never", () => {
+ const now = AbsoluteTime.fromMilliseconds(1_000);
+ assert.equal(deadlineIsValid(undefined, now), false);
+ assert.equal(deadlineIsValid(AbsoluteTime.fromMilliseconds(999), now), false);
+ assert.equal(
+ deadlineIsValid(AbsoluteTime.fromMilliseconds(1_001), now),
+ true,
+ );
+ assert.equal(deadlineIsValid(AbsoluteTime.never(), now), true);
+});
diff --git a/packages/taler-exchange-aml-webui/src/utils/rule-validation.ts b/packages/taler-exchange-aml-webui/src/utils/rule-validation.ts
@@ -0,0 +1,124 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import {
+ AbsoluteTime,
+ KycRule,
+ LimitOperationType,
+} from "@gnu-taler/taler-util";
+
+export const SHARED_RULES = [
+ LimitOperationType.refund,
+ LimitOperationType.transaction,
+] as const;
+
+export const ONLY_WALLET_RULES = [
+ LimitOperationType.balance,
+ LimitOperationType.merge,
+] as const;
+
+export const ONLY_BANK_RULES = [
+ LimitOperationType.deposit,
+ LimitOperationType.aggregate,
+ LimitOperationType.withdraw,
+ LimitOperationType.close,
+] as const;
+
+export const WALLET_RULES: LimitOperationType[] = [
+ ...ONLY_WALLET_RULES,
+ ...SHARED_RULES,
+];
+
+export const BANK_RULES: LimitOperationType[] = [
+ ...ONLY_BANK_RULES,
+ ...SHARED_RULES,
+];
+
+export const INSTANT_RULES: LimitOperationType[] = [
+ LimitOperationType.balance,
+ LimitOperationType.refund,
+];
+
+export type RuleValidationError =
+ | "empty-measures"
+ | "mixed-verboten"
+ | "invalid-instant-timeframe";
+
+export interface RuleApplicabilityWarnings {
+ missing: LimitOperationType[];
+ unexpected: LimitOperationType[];
+}
+
+export function isVerbotenMeasure(name: string): boolean {
+ return name.toUpperCase() === "VERBOTEN";
+}
+
+export function validateRule(rule: KycRule): RuleValidationError[] {
+ const errors: RuleValidationError[] = [];
+ const verboten = rule.measures.filter(isVerbotenMeasure);
+ if (rule.measures.length === 0) errors.push("empty-measures");
+ if (verboten.length > 0 && rule.measures.length !== 1) {
+ errors.push("mixed-verboten");
+ }
+ if (
+ INSTANT_RULES.includes(rule.operation_type) &&
+ rule.timeframe.d_us !== 0
+ ) {
+ errors.push("invalid-instant-timeframe");
+ }
+ return errors;
+}
+
+export function rulesAreValid(rules: KycRule[]): boolean {
+ return rules.every((rule) => validateRule(rule).length === 0);
+}
+
+export function deadlineIsValid(
+ deadline: AbsoluteTime | undefined,
+ now = AbsoluteTime.now(),
+): boolean {
+ return (
+ deadline !== undefined &&
+ (AbsoluteTime.isNever(deadline) || AbsoluteTime.cmp(deadline, now) > 0)
+ );
+}
+
+export function applicabilityWarnings(
+ isWallet: boolean,
+ rules: KycRule[],
+): RuleApplicabilityWarnings {
+ const expected = isWallet ? WALLET_RULES : BANK_RULES;
+ const unexpectedCandidates = isWallet ? ONLY_BANK_RULES : ONLY_WALLET_RULES;
+ const present = new Set(rules.map((rule) => rule.operation_type));
+ return {
+ missing: expected.filter((operation) => !present.has(operation)),
+ unexpected: unexpectedCandidates.filter((operation) =>
+ present.has(operation),
+ ),
+ };
+}
+
+export function saveRuleAt(
+ rules: KycRule[],
+ rule: KycRule,
+ index?: number,
+): KycRule[] {
+ if (index === undefined) {
+ return [...rules, rule];
+ }
+ if (index < 0 || index >= rules.length) return rules;
+ const updated = [...rules];
+ updated[index] = rule;
+ return updated;
+}
+
+export function removeRuleAt(rules: KycRule[], index: number): KycRule[] {
+ if (index < 0 || index >= rules.length) return rules;
+ return rules.filter((_rule, idx) => idx !== index);
+}
diff --git a/packages/taler-exchange-aml-webui/tailwind.config.js b/packages/taler-exchange-aml-webui/tailwind.config.js
@@ -1,16 +1,112 @@
-import { default as tw_form } from '@tailwindcss/forms';
+import { default as twForm } from "@tailwindcss/forms";
+
+const colors = {
+ primary: "#0042b3",
+ onPrimary: "#ffffff",
+ primaryContainer: "#d3deff",
+ onPrimaryContainer: "#00134a",
+ darkPrimary: "#b4c5ff",
+ darkOnPrimary: "#002a78",
+ darkPrimaryContainer: "#0042b3",
+ darkOnPrimaryContainer: "#e5ebff",
+ secondary: "#586a88",
+ onSecondary: "#ffffff",
+ secondaryContainer: "#d9e3f9",
+ onSecondaryContainer: "#111c2b",
+ darkSecondary: "#a4c9ff",
+ darkOnSecondary: "#00315d",
+ darkSecondaryContainer: "#72a3e5",
+ darkOnSecondaryContainer: "#003869",
+ tertiary: "#338af0",
+ onTertiary: "#ffffff",
+ tertiaryContainer: "#d1e4ff",
+ onTertiaryContainer: "#001c39",
+ darkTertiary: "#8dd1e5",
+ darkOnTertiary: "#003641",
+ darkTertiaryContainer: "#166577",
+ darkOnTertiaryContainer: "#9ce0f5",
+ error: "#b3261e",
+ onError: "#ffffff",
+ errorContainer: "#f9dedc",
+ onErrorContainer: "#410e0b",
+ darkError: "#ffb4aa",
+ darkOnError: "#690003",
+ darkErrorContainer: "#b3261e",
+ darkOnErrorContainer: "#ffcbc4",
+ success: "#337a40",
+ onSuccess: "#ffffff",
+ successContainer: "#2e8534",
+ onSuccessContainer: "#f7fff1",
+ darkSuccess: "#337a40",
+ darkOnSuccess: "#ffffff",
+ darkSuccessContainer: "#1d3522",
+ darkOnSuccessContainer: "#eaf6ec",
+ warning: "#f99c06",
+ onWarning: "#000000",
+ warningContainer: "#fdedd3",
+ onWarningContainer: "#6b4706",
+ darkWarning: "#f99c06",
+ darkOnWarning: "#000000",
+ darkWarningContainer: "#664200",
+ darkOnWarningContainer: "#fdedd3",
+ background: "#fdfdff",
+ onBackground: "#1a1c1f",
+ darkBackground: "#11131a",
+ darkOnBackground: "#e2e2eb",
+ outline: "#767880",
+ outlineVariant: "#c4c6d0",
+};
/** @type {import('tailwindcss').Config} */
export default {
+ darkMode: "media",
content: {
relative: true,
files: [
"./src/**/*.{html,tsx}",
- "./node_modules/@gnu-taler/web-util/src/**/*.{html,tsx}"
+ "./node_modules/@gnu-taler/web-util/src/**/*.{html,tsx}",
],
},
theme: {
- extend: {},
+ extend: {
+ colors: {
+ ...colors,
+ // Keep legacy utility classes on the accepted Taler palette while
+ // components are incrementally moved to semantic role names.
+ indigo: {
+ 50: colors.primaryContainer,
+ 100: colors.primaryContainer,
+ 200: colors.tertiaryContainer,
+ 300: colors.tertiary,
+ 400: colors.tertiary,
+ 500: colors.tertiary,
+ 600: colors.primary,
+ 700: colors.primary,
+ 800: colors.onPrimaryContainer,
+ 900: colors.onPrimaryContainer,
+ 950: colors.onPrimaryContainer,
+ },
+ red: {
+ 50: colors.errorContainer,
+ 500: colors.error,
+ 600: colors.error,
+ 700: colors.error,
+ 950: colors.onErrorContainer,
+ },
+ green: {
+ 50: colors.successContainer,
+ 500: colors.success,
+ 600: colors.success,
+ 700: colors.success,
+ },
+ amber: {
+ 50: colors.warningContainer,
+ 300: colors.warning,
+ 500: colors.warning,
+ 950: colors.onWarningContainer,
+ },
+ },
+ },
},
- plugins: [tw_form],
+ plugins: [twForm],
};
diff --git a/packages/taler-exchange-kyc-webui/src/pages/Start.tsx b/packages/taler-exchange-kyc-webui/src/pages/Start.tsx
@@ -182,7 +182,7 @@ function LinkGenerator({ req }: { req: KycRequirementInformation }): VNode {
state: LinkGenerationState.WAIT,
});
- const { showError } = useNotificationContext();
+ const { clearErrors, showError } = useNotificationContext();
const { lib } = useExchangeApiContext();
const start = useNotifiedOperation<
Awaited<ReturnType<typeof lib.exchange.startExternalKycProcess>>,
@@ -193,6 +193,7 @@ function LinkGenerator({ req }: { req: KycRequirementInformation }): VNode {
},
{
onSuccess(success) {
+ clearErrors();
setLoading({
state: LinkGenerationState.DONE,
url: success.redirect_url,
diff --git a/packages/taler-harness/src/harness/environments.ts b/packages/taler-harness/src/harness/environments.ts
@@ -1188,6 +1188,7 @@ export async function postAmlDecision(
attributes?: object;
attributes_expiration?: TalerProtocolTimestamp;
events?: string[];
+ keepInvestigating?: boolean;
},
) {
const { exchangeBaseUrl, paytoHash, amlPriv, amlPub } = req;
@@ -1196,7 +1197,7 @@ export async function postAmlDecision(
decision_time: TalerProtocolTimestamp.now(),
h_payto: paytoHash,
justification: "Bla",
- keep_investigating: false,
+ keep_investigating: req.keepInvestigating ?? false,
new_rules: req.newRules,
new_measures: req.newMeasures,
properties: req.properties ?? {},
diff --git a/packages/taler-harness/src/harness/harness.ts b/packages/taler-harness/src/harness/harness.ts
@@ -2202,6 +2202,7 @@ export class ExchangeService implements ExchangeServiceInterface {
async enableAmlAccount(
amlStaffPub: string,
legalName: string,
+ permission: "ro" | "rw" = "rw",
): Promise<void> {
await runCommand(
this.globalState,
@@ -2213,7 +2214,7 @@ export class ExchangeService implements ExchangeServiceInterface {
"aml-enable",
amlStaffPub,
legalName,
- "rw",
+ permission,
"upload",
],
);
diff --git a/packages/taler-harness/src/harness/webui-browser.ts b/packages/taler-harness/src/harness/webui-browser.ts
@@ -0,0 +1,64 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import { findBrowserBinary, installNativeUrl } from "../stagefright/stage.js";
+
+async function loadPlaywright(): Promise<typeof import("playwright-core")> {
+ try {
+ return await import("playwright-core");
+ } catch (cause) {
+ throw Error(`unable to load playwright-core (${cause})`);
+ }
+}
+
+export interface WebuiBrowser {
+ browser: any;
+ context: any;
+ page: any;
+ close: () => Promise<void>;
+}
+
+export interface WebuiBrowserOptions {
+ viewport?: { width: number; height: number };
+ colorScheme?: "light" | "dark" | "no-preference";
+}
+
+/** Launch the system Chromium with deterministic WebUI context settings. */
+export async function launchWebuiBrowser(
+ options: WebuiBrowserOptions = {},
+): Promise<WebuiBrowser> {
+ const restoreUrl = installNativeUrl();
+ try {
+ const pw = await loadPlaywright();
+ const browser = await pw.chromium.launch({
+ headless: true,
+ executablePath: findBrowserBinary(),
+ });
+ const context = await browser.newContext({
+ viewport: options.viewport,
+ colorScheme: options.colorScheme,
+ });
+ const page = await context.newPage();
+ return {
+ browser,
+ context,
+ page,
+ close: async () => {
+ try {
+ await browser.close();
+ } finally {
+ restoreUrl();
+ }
+ },
+ };
+ } catch (cause) {
+ restoreUrl();
+ throw cause;
+ }
+}
diff --git a/packages/taler-harness/src/harness/webui-server.ts b/packages/taler-harness/src/harness/webui-server.ts
@@ -244,3 +244,19 @@ export async function startStaticServerMerchantWebui(
},
});
}
+
+/** Serve the Exchange AML WebUI against a real exchange HTTP endpoint. */
+export async function startStaticServerExchangeAmlWebui(
+ exchangeBaseUrl: string,
+): Promise<WebuiServer> {
+ return startStaticWebuiServer({
+ packageName: "taler-exchange-aml-webui",
+ packageFilter: "@gnu-taler/taler-exchange-aml-webui",
+ proxyBaseUrl: exchangeBaseUrl,
+ dynamicFiles: {
+ "/settings.json": (serverBaseUrl: string) => ({
+ backendBaseURL: serverBaseUrl,
+ }),
+ },
+ });
+}
diff --git a/packages/taler-harness/src/integrationtests/test-exchange-aml-webui.ts b/packages/taler-harness/src/integrationtests/test-exchange-aml-webui.ts
@@ -0,0 +1,1045 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import path from "node:path";
+import {
+ Configuration,
+ Paytos,
+ TalerAmlProperties,
+ TalerFormAttributes,
+ TalerProtocolTimestamp,
+ encodeCrock,
+} from "@gnu-taler/taler-util";
+import type { Locator } from "playwright-core";
+import {
+ configureCommonKyc,
+ createKycTestkudosEnvironmentFull,
+ postAmlDecision,
+} from "../harness/environments.js";
+import {
+ GlobalTestState,
+ getTestHarnessPaytoForLabel,
+} from "../harness/harness.js";
+import { launchWebuiBrowser } from "../harness/webui-browser.js";
+import { startStaticServerExchangeAmlWebui } from "../harness/webui-server.js";
+
+function adjustExchangeConfig(config: Configuration): void {
+ configureCommonKyc(config);
+ config.setString("exchange", "AML_SPA_DIALECT", "tops");
+}
+
+async function waitForEnabled(locator: Locator): Promise<void> {
+ await locator.evaluate((element: any) => {
+ if (!element.disabled) return;
+ return new Promise<void>((resolve) => {
+ const observer = new (globalThis as any).MutationObserver(() => {
+ if (element.disabled) return;
+ observer.disconnect();
+ resolve();
+ });
+ observer.observe(element, {
+ attributes: true,
+ attributeFilter: ["disabled"],
+ });
+ });
+ });
+}
+
+/** Browser smoke coverage against a real exchange and AML configuration. */
+export async function runExchangeAmlWebuiTest(t: GlobalTestState) {
+ const { exchange, amlKeypair } = await createKycTestkudosEnvironmentFull(t, {
+ adjustExchangeConfig,
+ });
+ const emptyRules = {
+ custom_measures: {},
+ expiration_time: TalerProtocolTimestamp.never(),
+ rules: [],
+ };
+ async function addAccount(
+ label: string,
+ options: {
+ events?: string[];
+ highRisk?: boolean;
+ note?: string;
+ investigate?: boolean;
+ attributes?: object;
+ } = {},
+ ): Promise<string> {
+ const payto = getTestHarnessPaytoForLabel(label);
+ const paytoHash = encodeCrock(Paytos.hashNormalized(payto));
+ await postAmlDecision(t, {
+ exchangeBaseUrl: exchange.baseUrl,
+ amlPriv: amlKeypair.priv,
+ amlPub: amlKeypair.pub,
+ paytoHash,
+ paytoUri: payto,
+ newRules: emptyRules,
+ events: options.events,
+ keepInvestigating: options.investigate,
+ properties: {
+ ...(options.highRisk
+ ? { [TalerAmlProperties.HIGH_RISK_CUSTOMER]: true }
+ : {}),
+ ...(options.note
+ ? { [TalerAmlProperties.FILE_NOTE]: options.note }
+ : {}),
+ },
+ attributes: options.attributes,
+ attributes_expiration: options.attributes
+ ? TalerProtocolTimestamp.never()
+ : undefined,
+ });
+ return paytoHash;
+ }
+ await addAccount("aml-below-threshold");
+ await addAccount("aml-open-standard", { events: ["ACCOUNT_OPEN"] });
+ const investigatedAccount = await addAccount("aml-open-high-risk", {
+ events: ["ACCOUNT_OPEN"],
+ highRisk: true,
+ investigate: true,
+ note: "Review the source of funds before changing the current measures.",
+ attributes: {
+ [TalerFormAttributes.FORM_ID]: "generic_note",
+ [TalerFormAttributes.FORM_VERSION]: 1,
+ [TalerFormAttributes.NOTE_TEXT]:
+ "Beneficial ownership documents reviewed by AML staff.",
+ },
+ });
+ // AML decisions use second-resolution timestamps and must be strictly newer.
+ await new Promise((resolve) => setTimeout(resolve, 1_100));
+ await postAmlDecision(t, {
+ exchangeBaseUrl: exchange.baseUrl,
+ amlPriv: amlKeypair.priv,
+ amlPub: amlKeypair.pub,
+ paytoHash: investigatedAccount,
+ paytoUri: getTestHarnessPaytoForLabel("aml-open-high-risk"),
+ newRules: emptyRules,
+ keepInvestigating: true,
+ properties: {
+ [TalerAmlProperties.HIGH_RISK_CUSTOMER]: true,
+ [TalerAmlProperties.FILE_NOTE]:
+ "Review the source of funds before changing the current measures.",
+ },
+ });
+ await addAccount("aml-closed", {
+ events: ["ACCOUNT_OPEN", "ACCOUNT_IDLE"],
+ note: "Relationship closed after a period without activity.",
+ });
+ const webui = await startStaticServerExchangeAmlWebui(exchange.baseUrl);
+ const browser = await launchWebuiBrowser({
+ viewport: { width: 1280, height: 900 },
+ colorScheme: "light",
+ });
+ const pageErrors: string[] = [];
+ const browserDiagnostics: string[] = [];
+ const renderDiagnostics: string[] = [];
+ browser.page.on("pageerror", (error: Error) =>
+ pageErrors.push(error.message),
+ );
+ browser.page.on("console", (message: { type(): string; text(): string }) => {
+ if (
+ message.text().includes("process runtime thrown an Error") ||
+ message.text().includes('"stack":')
+ ) {
+ renderDiagnostics.push(`render console: ${message.text()}`);
+ }
+ if (message.type() === "error") {
+ browserDiagnostics.push(`browser console: ${message.text()}`);
+ }
+ });
+ browser.page.on(
+ "requestfailed",
+ (request: { url(): string; failure(): { errorText: string } | null }) => {
+ if (request.failure()?.errorText === "net::ERR_ABORTED") return;
+ browserDiagnostics.push(
+ `request failed: ${request.url()} (${request.failure()?.errorText ?? "unknown error"})`,
+ );
+ },
+ );
+
+ try {
+ const page = browser.page;
+ await page.goto(webui.url);
+ await page
+ .getByRole("heading", { name: "Create session" })
+ .waitFor({ state: "visible", timeout: 15_000 });
+ await page
+ .getByText(new URL("/", webui.url).href, { exact: true })
+ .waitFor({ state: "visible", timeout: 15_000 });
+ const createButton = page.getByRole("button", {
+ name: "Create",
+ exact: true,
+ });
+ const getCreateButtonContrast = () =>
+ createButton.evaluate((element: any) => {
+ const style = (globalThis as any).getComputedStyle(element);
+ const luminance = (color: string): number => {
+ const channels = (color.match(/[\d.]+/g) ?? [])
+ .slice(0, 3)
+ .map(Number)
+ .map((channel) => {
+ const normalized = channel / 255;
+ return normalized <= 0.04045
+ ? normalized / 12.92
+ : ((normalized + 0.055) / 1.055) ** 2.4;
+ });
+ return (
+ channels[0] * 0.2126 + channels[1] * 0.7152 + channels[2] * 0.0722
+ );
+ };
+ const foreground = luminance(style.color);
+ const background = luminance(style.backgroundColor);
+ return {
+ opacity: style.opacity,
+ ratio:
+ (Math.max(foreground, background) + 0.05) /
+ (Math.min(foreground, background) + 0.05),
+ };
+ });
+ const disabledContrast = await getCreateButtonContrast();
+ t.assertTrue(
+ disabledContrast.opacity === "1" && disabledContrast.ratio >= 4.5,
+ "disabled Create button should retain accessible text contrast",
+ );
+ await createButton.hover();
+ const disabledHoverContrast = await getCreateButtonContrast();
+ t.assertTrue(
+ disabledHoverContrast.opacity === "1" &&
+ disabledHoverContrast.ratio >= 4.5,
+ "hover should not reduce the disabled Create button contrast",
+ );
+ await page.getByLabel("Password", { exact: true }).fill("Aml-Webui-123!");
+ await page.getByLabel("Repeat password").fill("Aml-Webui-123!");
+ await waitForEnabled(createButton);
+ await page.getByLabel("Repeat password").press("Enter");
+ await page
+ .getByRole("heading", {
+ name: "Officer key awaiting enrollment",
+ exact: true,
+ })
+ .waitFor({ state: "visible", timeout: 15_000 });
+ t.assertTrue(
+ (await page
+ .getByRole("link", { name: "Development settings", exact: true })
+ .count()) === 0,
+ "enrollment screen should not link to development settings",
+ );
+ await page
+ .getByRole("button", { name: "Discard this key", exact: true })
+ .click();
+ const discardDialog = page.getByRole("dialog", {
+ name: "Confirmation required",
+ exact: true,
+ });
+ await discardDialog.waitFor({ state: "visible" });
+ t.assertTrue(
+ await page.locator('dialog[open][aria-modal="true"]').isVisible(),
+ "discarding an officer key should require a modal confirmation",
+ );
+ await discardDialog
+ .getByRole("button", { name: "Cancel", exact: true })
+ .click();
+ await page
+ .getByRole("dialog", { name: "Confirmation required", exact: true })
+ .waitFor({ state: "detached" });
+ const officerPub = (await page.locator("code").textContent())?.trim();
+ t.assertTrue(!!officerPub, "AML WebUI must expose its officer public key");
+ t.assertTrue(
+ (await page
+ .getByRole("navigation", { name: "AML navigation" })
+ .count()) === 0,
+ "AML WebUI must not expose private navigation before enrollment",
+ );
+ await page
+ .getByRole("button", { name: "Retry access check", exact: true })
+ .click();
+ await page
+ .getByText(/^Last checked at /)
+ .waitFor({ state: "visible", timeout: 15_000 });
+ await exchange.enableAmlAccount(officerPub!, "Browser AML officer", "ro");
+
+ await page
+ .getByRole("button", { name: "Retry access check", exact: true })
+ .click();
+ await page
+ .getByRole("heading", { name: "Dashboard", exact: true })
+ .waitFor({ state: "visible", timeout: 15_000 });
+ await page
+ .getByText(
+ "You can review AML information, but this officer key cannot submit decisions.",
+ { exact: true },
+ )
+ .waitFor({ state: "visible" });
+ await page.screenshot({
+ path: path.join(t.testDir, "exchange-aml-webui-read-only-desktop.png"),
+ fullPage: true,
+ });
+ await page.getByRole("link", { name: "Accounts", exact: true }).click();
+ await page
+ .getByRole("heading", { name: "Accounts", exact: true })
+ .waitFor({ state: "visible", timeout: 15_000 });
+ await page
+ .getByText("System information", { exact: true })
+ .first()
+ .waitFor({ state: "visible" });
+ t.assertDeepEqual(await page.locator("tbody tr").count(), 4);
+ await page
+ .getByText("Page 1", { exact: true })
+ .waitFor({ state: "visible" });
+ await page.getByText("Export filtered accounts", { exact: true }).click();
+ const csvExport = page.getByRole("button", {
+ name: "Download CSV",
+ exact: true,
+ });
+ await csvExport.waitFor({ state: "visible" });
+ await page.getByRole("heading", { name: "Accounts", exact: true }).click();
+ await csvExport.waitFor({ state: "hidden" });
+ await page.screenshot({
+ path: path.join(t.testDir, "exchange-aml-webui-accounts-desktop.png"),
+ fullPage: true,
+ });
+ await page.getByLabel("Risk", { exact: true }).selectOption("yes");
+ await page
+ .getByRole("table")
+ .getByRole("link", { name: "aml-open-high-risk", exact: true })
+ .waitFor({ state: "visible" });
+ t.assertTrue(
+ page.url().includes("high_risk=yes"),
+ "account filters should be stored in the URL",
+ );
+ await page.reload();
+ t.assertTrue(
+ page.url().includes("high_risk=yes"),
+ "account filter URL should survive a reload",
+ );
+ const filterReloadDialog = page.locator('dialog[open][aria-modal="true"]');
+ await filterReloadDialog
+ .getByRole("heading", { name: "Session locked", exact: true })
+ .waitFor({ state: "visible" });
+ await filterReloadDialog
+ .getByLabel("Password", { exact: true })
+ .fill("Aml-Webui-123!");
+ await filterReloadDialog
+ .getByRole("button", { name: "Unlock", exact: true })
+ .click();
+ t.assertDeepEqual(
+ await page.getByLabel("Risk", { exact: true }).inputValue(),
+ "yes",
+ );
+ await page
+ .getByRole("button", { name: "Clear filters", exact: true })
+ .click();
+ await page
+ .getByRole("table")
+ .getByRole("link", { name: "aml-open-high-risk", exact: true })
+ .click();
+ await page
+ .getByRole("heading", { name: "Case summary", exact: true })
+ .waitFor({ state: "visible", timeout: 15_000 });
+ const caseSections = [
+ "Case summary",
+ "Effective policy",
+ "Account assessment",
+ "Collected information",
+ "Active requirements",
+ ];
+ const sectionTops: number[] = [];
+ for (const section of caseSections) {
+ const heading = page.getByRole("heading", { name: section, exact: true });
+ await heading.waitFor({ state: "visible" });
+ sectionTops.push(
+ await heading.evaluate(
+ (element: any) =>
+ element.getBoundingClientRect().top + (globalThis as any).scrollY,
+ ),
+ );
+ }
+ t.assertTrue(
+ sectionTops.every(
+ (top, index) => index === 0 || top > sectionTops[index - 1],
+ ),
+ "account case sections should follow the review workflow",
+ );
+ await page
+ .getByText("Filed by an AML officer", { exact: true })
+ .waitFor({ state: "visible" });
+ await page
+ .getByText("No active requirements", { exact: true })
+ .waitFor({ state: "visible" });
+ t.assertTrue(
+ (await page
+ .getByRole("button", { name: "New decision", exact: true })
+ .getAttribute("aria-disabled")) === "true",
+ "read-only officers should not be able to create a decision from an account case",
+ );
+ const pdfAction = page.getByRole("button", {
+ name: "Download AML file (PDF)",
+ exact: true,
+ });
+ await pdfAction.waitFor({ state: "visible" });
+ const pdfDownloadPromise = page.waitForEvent("download");
+ await pdfAction.click();
+ const pdfDownload = await pdfDownloadPromise;
+ t.assertTrue(
+ pdfDownload.suggestedFilename().endsWith(`_${investigatedAccount}.pdf`),
+ "the AML audit PDF should download directly from the account case",
+ );
+ await page.screenshot({
+ path: path.join(t.testDir, "exchange-aml-webui-account-case-desktop.png"),
+ fullPage: true,
+ });
+ await page.getByText("View details", { exact: true }).click();
+ await page
+ .getByRole("heading", { name: "Generic note", exact: true })
+ .waitFor({ state: "visible" });
+ await page
+ .getByText("Collected AML/KYC information", { exact: true })
+ .waitFor({ state: "visible" });
+ await page.getByText("AML officer", { exact: true }).waitFor({
+ state: "visible",
+ });
+ await page.screenshot({
+ path: path.join(
+ t.testDir,
+ "exchange-aml-webui-collected-information-desktop.png",
+ ),
+ fullPage: true,
+ });
+ await page
+ .getByRole("link", { name: "Back to account", exact: true })
+ .click();
+ await page
+ .getByRole("heading", { name: "Case summary", exact: true })
+ .waitFor({ state: "visible" });
+ await page.getByRole("link", { name: "Transfers", exact: true }).click();
+ await page
+ .getByRole("heading", { name: "Transfer activity", exact: true })
+ .waitFor({ state: "visible" });
+ t.assertTrue(
+ page.url().includes(`/account/${investigatedAccount}/transfers`),
+ "account transfers should use the canonical account-scoped route",
+ );
+ await page
+ .getByRole("link", { name: "Decision history", exact: true })
+ .click();
+ await page
+ .getByRole("heading", { name: "Decision history", exact: true })
+ .waitFor({ state: "visible" });
+ await page
+ .getByRole("heading", { name: "Previous decisions", exact: true })
+ .waitFor({ state: "visible" });
+ t.assertTrue(
+ page.url().includes("/history"),
+ "decision history should have its own account-scoped route",
+ );
+ await page.screenshot({
+ path: path.join(
+ t.testDir,
+ "exchange-aml-webui-decision-history-desktop.png",
+ ),
+ fullPage: true,
+ });
+ await page.getByRole("link", { name: "Overview", exact: true }).click();
+ await page
+ .getByRole("heading", { name: "Case summary", exact: true })
+ .waitFor({ state: "visible" });
+ await page.setViewportSize({ width: 390, height: 844 });
+ await page.emulateMedia({ colorScheme: "dark" });
+ const caseLayout = await page.evaluate(() => ({
+ viewport: (globalThis as any).innerWidth,
+ content: (globalThis as any).document.documentElement.scrollWidth,
+ }));
+ t.assertTrue(
+ caseLayout.content <= caseLayout.viewport,
+ "mobile account case should not overflow horizontally",
+ );
+ await page.screenshot({
+ path: path.join(
+ t.testDir,
+ "exchange-aml-webui-account-case-mobile-dark.png",
+ ),
+ fullPage: true,
+ });
+ await page
+ .getByRole("link", { name: "Decision history", exact: true })
+ .click();
+ await page
+ .getByRole("heading", { name: "Decision history", exact: true })
+ .waitFor({ state: "visible" });
+ const historyLayout = await page.evaluate(() => ({
+ viewport: (globalThis as any).innerWidth,
+ content: (globalThis as any).document.documentElement.scrollWidth,
+ }));
+ t.assertTrue(
+ historyLayout.content <= historyLayout.viewport,
+ "mobile decision history should not overflow horizontally",
+ );
+ await page.screenshot({
+ path: path.join(
+ t.testDir,
+ "exchange-aml-webui-decision-history-mobile-dark.png",
+ ),
+ fullPage: true,
+ });
+ await page.getByRole("link", { name: "Overview", exact: true }).click();
+ await page
+ .getByRole("heading", { name: "Case summary", exact: true })
+ .waitFor({ state: "visible" });
+ await page
+ .getByRole("link", { name: "Back to accounts", exact: true })
+ .click();
+ await page
+ .getByRole("heading", { name: "Accounts", exact: true })
+ .waitFor({ state: "visible" });
+ await page.locator("article").first().waitFor({ state: "visible" });
+ const accountLayout = await page.evaluate(() => ({
+ viewport: (globalThis as any).innerWidth,
+ content: (globalThis as any).document.documentElement.scrollWidth,
+ }));
+ t.assertTrue(
+ accountLayout.content <= accountLayout.viewport,
+ "mobile account cards should not overflow horizontally",
+ );
+ await page.screenshot({
+ path: path.join(t.testDir, "exchange-aml-webui-accounts-mobile-dark.png"),
+ fullPage: true,
+ });
+ await page.setViewportSize({ width: 1280, height: 900 });
+ await page.emulateMedia({ colorScheme: "light" });
+ await page.getByRole("link", { name: "Find account", exact: true }).click();
+ const readOnlyIbanInput = page.getByRole("textbox", {
+ name: "IBAN",
+ exact: true,
+ });
+ await readOnlyIbanInput.fill("DE89370400440532013000");
+ const readOnlySearchButton = page.getByRole("button", {
+ name: "Search",
+ exact: true,
+ });
+ await waitForEnabled(readOnlySearchButton);
+ await readOnlyIbanInput.press("Enter");
+ await page
+ .getByText("Account not found", { exact: true })
+ .waitFor({ state: "visible", timeout: 15_000 });
+ t.assertTrue(
+ await page
+ .getByRole("button", {
+ name: "Start a decision for this account",
+ exact: true,
+ })
+ .isDisabled(),
+ "read-only officers should not be able to start a decision from search",
+ );
+ await page
+ .getByText("Read-only officers cannot create AML decisions.", {
+ exact: true,
+ })
+ .waitFor({ state: "visible" });
+ await page.screenshot({
+ path: path.join(t.testDir, "exchange-aml-webui-search-desktop.png"),
+ fullPage: true,
+ });
+ await page.getByRole("link", { name: "Session", exact: true }).click();
+ await page
+ .getByText("Browser AML officer", { exact: true })
+ .waitFor({ state: "visible" });
+ await page.getByText("Read-only", { exact: true }).waitFor({
+ state: "visible",
+ });
+ await page
+ .getByRole("heading", { name: "Session and access", exact: true })
+ .waitFor({ state: "visible" });
+ await page.getByText("Locks automatically", { exact: true }).waitFor({
+ state: "visible",
+ });
+ await page.screenshot({
+ path: path.join(t.testDir, "exchange-aml-webui-session-desktop.png"),
+ fullPage: true,
+ });
+ await page.getByRole("button", { name: "Remove key", exact: true }).click();
+ const removeKeyDialog = page.getByRole("dialog", {
+ name: "Remove officer key?",
+ exact: true,
+ });
+ await removeKeyDialog.waitFor({ state: "visible" });
+ await removeKeyDialog
+ .getByText(
+ "This does not revoke the officer at the exchange. Ask the exchange operator to revoke its access if the key may be compromised.",
+ { exact: true },
+ )
+ .waitFor({ state: "visible" });
+ await removeKeyDialog
+ .getByRole("button", { name: "Cancel", exact: true })
+ .click();
+ await page.evaluate(() => {
+ (globalThis as any).location.hash = "#/decide/ACCOUNT/PAYTO";
+ });
+ await page
+ .getByText("This officer key cannot create or submit AML decisions.", {
+ exact: true,
+ })
+ .waitFor({ state: "visible" });
+ await new Promise((resolve) => setTimeout(resolve, 1_100));
+ await exchange.enableAmlAccount(officerPub!, "Browser AML officer", "rw");
+ await page.evaluate(() => {
+ (globalThis as any).location.hash = "#/dashboard";
+ });
+ t.assertTrue(
+ (await page
+ .getByRole("navigation", { name: "AML navigation" })
+ .getByRole("link", { name: "Dev", exact: true })
+ .count()) === 0,
+ "development settings should not appear in the AML navigation",
+ );
+
+ pageErrors.length = 0;
+ browserDiagnostics.length = 0;
+ await page.reload();
+ await page
+ .getByRole("heading", { name: "Session locked", exact: true })
+ .waitFor({ state: "visible", timeout: 15_000 });
+ t.assertTrue(
+ await page.locator('dialog[open][aria-modal="true"]').isVisible(),
+ "AML WebUI must present the locked session as a modal dialog",
+ );
+ const navigationWasBlocked = await page
+ .getByRole("link", { name: "Accounts", exact: true })
+ .click({ timeout: 500 })
+ .then(
+ () => false,
+ () => true,
+ );
+ t.assertTrue(
+ navigationWasBlocked,
+ "AML WebUI must block private navigation while the session is locked",
+ );
+ const lockDialog = page.locator('dialog[open][aria-modal="true"]');
+ await lockDialog
+ .getByLabel("Password", { exact: true })
+ .fill("wrong password");
+ await lockDialog
+ .getByRole("button", { name: "Unlock", exact: true })
+ .click();
+ await lockDialog
+ .getByText("Failed to unlock the session.", { exact: true })
+ .waitFor({ state: "visible" });
+ await lockDialog
+ .getByLabel("Password", { exact: true })
+ .fill("Aml-Webui-123!");
+ await lockDialog
+ .getByRole("button", { name: "Unlock", exact: true })
+ .click();
+ await page
+ .getByText("Failed to unlock the session.", { exact: true })
+ .waitFor({ state: "detached" });
+ await page.getByRole("link", { name: "Dashboard", exact: true }).click();
+ await page
+ .getByText("Review case queue", { exact: true })
+ .waitFor({ state: "visible", timeout: 15_000 });
+ t.assertTrue(
+ (await page
+ .getByText(
+ "You can review AML information, but this officer key cannot submit decisions.",
+ { exact: true },
+ )
+ .count()) === 0,
+ "read-write enrollment should remove the read-only notice",
+ );
+ t.assertTrue(
+ (
+ await page.locator('img[alt="GNU Taler"]').getAttribute("src")
+ )?.endsWith(".svg") === true,
+ "AML WebUI must use the canonical SVG logo",
+ );
+ t.assertTrue(
+ (await page.getByRole("button", { name: "Open settings" }).count()) === 0,
+ "AML WebUI must not show the header burger menu",
+ );
+
+ await page.evaluate((account: string) => {
+ (globalThis as any).location.hash = `#/account/${account}`;
+ }, investigatedAccount);
+ await page
+ .getByRole("heading", { name: "Case summary", exact: true })
+ .waitFor({ state: "visible", timeout: 15_000 });
+ await page
+ .getByRole("button", { name: "New decision", exact: true })
+ .click();
+ await page
+ .getByRole("heading", { name: "Decision for bank account", exact: true })
+ .waitFor({ state: "visible", timeout: 15_000 });
+ await page
+ .getByRole("heading", { name: "Customer information", exact: true })
+ .waitFor({ state: "visible" });
+ t.assertTrue(
+ page.url().includes(`/decide/${investigatedAccount}/`),
+ "starting a decision should open the account-scoped wizard",
+ );
+ const customerInformationCard = page.locator(
+ 'section[aria-labelledby="decision-step-heading"]',
+ );
+ const formSelector = page.getByRole("combobox", {
+ name: "AML/KYC form",
+ exact: true,
+ });
+ await formSelector.click();
+ await page
+ .getByRole("listbox")
+ .waitFor({ state: "visible", timeout: 5_000 });
+ t.assertTrue(
+ (await customerInformationCard.evaluate(
+ (element: any) =>
+ (globalThis as any).getComputedStyle(element).overflow,
+ )) === "visible",
+ "wizard step cards should not clip form dropdowns",
+ );
+ await page.screenshot({
+ path: path.join(
+ t.testDir,
+ "exchange-aml-webui-wizard-form-dropdown-desktop.png",
+ ),
+ fullPage: true,
+ });
+ await formSelector.press("Escape");
+ await page.screenshot({
+ path: path.join(t.testDir, "exchange-aml-webui-wizard-desktop.png"),
+ fullPage: true,
+ });
+
+ await page.getByRole("button", { name: /^Account properties:/ }).click();
+ await page
+ .getByRole("heading", {
+ name: "Review derived account properties",
+ exact: true,
+ })
+ .waitFor({ state: "visible" });
+ await page
+ .getByText("Current note on the GwG file", { exact: true })
+ .waitFor({ state: "visible" });
+ await page.getByRole("button", { name: /^Reporting events:/ }).click();
+ await page
+ .getByText(/they do not notify the customer/i)
+ .waitFor({ state: "visible" });
+ await page.getByRole("button", { name: /^Immediate measures:/ }).click();
+ await page
+ .getByRole("heading", {
+ name: "Customer actions after submission",
+ exact: true,
+ })
+ .waitFor({ state: "visible" });
+ await page
+ .getByRole("button", { name: "Add custom measure", exact: true })
+ .click();
+ await page
+ .getByRole("heading", { name: "Create custom measure", exact: true })
+ .waitFor({ state: "visible" });
+ await page
+ .getByText(
+ "Context values must satisfy the selected check and program requirements.",
+ { exact: false },
+ )
+ .waitFor({ state: "visible" });
+ await page.screenshot({
+ path: path.join(
+ t.testDir,
+ "exchange-aml-webui-wizard-custom-measure-desktop.png",
+ ),
+ fullPage: true,
+ });
+ await page.getByRole("button", { name: "Cancel", exact: true }).click();
+ await page.getByRole("button", { name: /^Transaction rules:/ }).click();
+ await page
+ .getByText("TOPS account profiles", { exact: true })
+ .waitFor({ state: "visible" });
+ await page.getByRole("button", { name: "E-commerce", exact: true }).click();
+ await page.screenshot({
+ path: path.join(t.testDir, "exchange-aml-webui-wizard-rules-desktop.png"),
+ fullPage: true,
+ });
+ await page.setViewportSize({ width: 390, height: 844 });
+ await page.emulateMedia({ colorScheme: "dark" });
+ const wizardLayout = await page.evaluate(() => ({
+ viewport: (globalThis as any).innerWidth,
+ content: (globalThis as any).document.documentElement.scrollWidth,
+ }));
+ t.assertTrue(
+ wizardLayout.content <= wizardLayout.viewport,
+ "mobile decision wizard should not overflow horizontally",
+ );
+ await page.screenshot({
+ path: path.join(
+ t.testDir,
+ "exchange-aml-webui-wizard-rules-mobile-dark.png",
+ ),
+ fullPage: true,
+ });
+ await page
+ .getByRole("button", { name: "Back to account", exact: true })
+ .click();
+ await page
+ .getByRole("heading", { name: "Case summary", exact: true })
+ .waitFor({ state: "visible" });
+ await page.setViewportSize({ width: 1280, height: 900 });
+ await page.emulateMedia({ colorScheme: "light" });
+ await page.getByRole("link", { name: "Dashboard", exact: true }).click();
+ await page
+ .getByText("Review case queue", { exact: true })
+ .waitFor({ state: "visible" });
+
+ const desktopShell = await page.evaluate(() => {
+ const document = (globalThis as any).document;
+ const getComputedStyle = (globalThis as any).getComputedStyle;
+ const navigation = document.querySelector(
+ 'nav[aria-label="AML navigation"]',
+ );
+ const sidebar = navigation.parentElement;
+ const footer = document.querySelector("footer");
+ const sidebarRect = sidebar.getBoundingClientRect();
+ const footerRect = footer.getBoundingClientRect();
+ return {
+ sidebarRight: sidebarRect.right,
+ sidebarBottom: sidebarRect.bottom,
+ sidebarRadius: Number.parseFloat(
+ getComputedStyle(sidebar).borderTopRightRadius,
+ ),
+ footerLeft: footerRect.left,
+ footerBottom: footerRect.bottom,
+ footerHeight: footerRect.height,
+ };
+ });
+ t.assertTrue(
+ desktopShell.sidebarRadius === 0,
+ "desktop sidebar should have square outer edges",
+ );
+ t.assertTrue(
+ desktopShell.footerLeft >= desktopShell.sidebarRight - 1 &&
+ Math.abs(desktopShell.footerBottom - desktopShell.sidebarBottom) <= 1,
+ "desktop footer should sit in the content column beside the sidebar",
+ );
+ t.assertTrue(
+ desktopShell.footerHeight <= 50,
+ "desktop footer should remain visually compact",
+ );
+ await page.evaluate(() => {
+ (globalThis as any).scrollTo(0, 0);
+ });
+ await page.screenshot({
+ path: path.join(t.testDir, "exchange-aml-webui-desktop.png"),
+ fullPage: true,
+ });
+ await page.setViewportSize({ width: 390, height: 844 });
+ await page.screenshot({
+ path: path.join(t.testDir, "exchange-aml-webui-mobile.png"),
+ });
+ const mobileNavigationHeight = await page
+ .getByRole("link", { name: "Dashboard", exact: true })
+ .evaluate((element: any) => element.getBoundingClientRect().height);
+ t.assertTrue(
+ mobileNavigationHeight >= 44,
+ "mobile navigation links should retain accessible touch targets",
+ );
+ const mobileNavigation = page
+ .getByRole("navigation", { name: "AML navigation" })
+ .locator("..");
+ const mobileNavigationBox = await mobileNavigation.boundingBox();
+ t.assertTrue(
+ !!mobileNavigationBox,
+ "mobile navigation should have a measurable layout box",
+ );
+ await page.locator("footer").evaluate((element: any) => {
+ element.scrollIntoView({ block: "end" });
+ });
+ await page.evaluate((navigationHeight: number) => {
+ (globalThis as any).scrollBy(0, navigationHeight + 8);
+ }, mobileNavigationBox!.height);
+ const mobileBottom = await page.evaluate(() => {
+ const document = (globalThis as any).document;
+ const navigation = document.querySelector(
+ 'nav[aria-label="AML navigation"]',
+ );
+ const footer = document.querySelector("footer");
+ return {
+ navigationTop: navigation.parentElement.getBoundingClientRect().top,
+ footerTop: footer.getBoundingClientRect().top,
+ footerBottom: footer.getBoundingClientRect().bottom,
+ };
+ });
+ t.assertTrue(
+ mobileBottom.footerTop >= 0 &&
+ mobileBottom.footerBottom <= mobileBottom.navigationTop + 1,
+ "mobile navigation should not cover the footer at the end of the page",
+ );
+ await page.screenshot({
+ path: path.join(t.testDir, "exchange-aml-webui-mobile-footer.png"),
+ });
+ await page.evaluate(() => {
+ (globalThis as any).scrollTo(0, 0);
+ });
+ await page.setViewportSize({ width: 1280, height: 900 });
+
+ await page.getByRole("link", { name: "Transfers", exact: true }).click();
+ await page
+ .getByRole("heading", { name: "Transfer activity", exact: true })
+ .waitFor({ state: "visible" });
+ await page
+ .getByText(/Credit transfers are incoming, debit transfers are outgoing/i)
+ .waitFor({ state: "visible" });
+ await page.screenshot({
+ path: path.join(t.testDir, "exchange-aml-webui-transfers-desktop.png"),
+ fullPage: true,
+ });
+ await page.setViewportSize({ width: 390, height: 844 });
+ const transfersLayout = await page.evaluate(() => ({
+ viewport: (globalThis as any).innerWidth,
+ content: (globalThis as any).document.documentElement.scrollWidth,
+ }));
+ t.assertTrue(
+ transfersLayout.content <= transfersLayout.viewport,
+ "mobile transfer activity should not overflow horizontally",
+ );
+ await page.screenshot({
+ path: path.join(t.testDir, "exchange-aml-webui-transfers-mobile.png"),
+ fullPage: true,
+ });
+ await page.setViewportSize({ width: 1280, height: 900 });
+
+ await page.getByRole("link", { name: "Accounts", exact: true }).click();
+ await page.getByRole("link", { name: "Find account", exact: true }).click();
+ await page
+ .getByRole("heading", { name: "Find account", exact: true })
+ .waitFor({ state: "visible", timeout: 15_000 });
+ const ibanInput = page.getByRole("textbox", {
+ name: "IBAN",
+ exact: true,
+ });
+ await ibanInput.fill("DE89370400440532013000");
+ const searchButton = page.getByRole("button", {
+ name: "Search",
+ exact: true,
+ });
+ await waitForEnabled(searchButton);
+ await ibanInput.press("Enter");
+ await page
+ .getByText("Account not found", { exact: true })
+ .waitFor({ state: "visible", timeout: 15_000 });
+ await page
+ .getByText("Find by normalized payto hash", { exact: true })
+ .click();
+ const hashInput = page.getByRole("textbox", {
+ name: "Normalized payto hash",
+ exact: true,
+ });
+ await hashInput.fill(investigatedAccount.toLowerCase());
+ await hashInput.press("Enter");
+ await page.waitForURL((url: URL) => url.hash.includes(investigatedAccount));
+
+ await page.setViewportSize({ width: 390, height: 844 });
+ await page.emulateMedia({ colorScheme: "dark" });
+ await page.getByRole("link", { name: "Session", exact: true }).click();
+ await page.getByText("Read and write", { exact: true }).waitFor({
+ state: "visible",
+ });
+ await page.getByText("Locks automatically", { exact: true }).waitFor({
+ state: "visible",
+ });
+ await page.screenshot({
+ path: path.join(t.testDir, "exchange-aml-webui-session-mobile-dark.png"),
+ fullPage: true,
+ });
+ const headerLockButton = page
+ .getByRole("banner")
+ .getByRole("button", { name: "Lock session", exact: true });
+ const headerLockBox = await headerLockButton.boundingBox();
+ t.assertTrue(
+ !!headerLockBox &&
+ headerLockBox.width >= 44 &&
+ headerLockBox.height >= 44,
+ "mobile header lock action should have an accessible touch target",
+ );
+ await headerLockButton.click();
+ const headerLockDialog = page.locator('dialog[open][aria-modal="true"]');
+ await headerLockDialog
+ .getByRole("heading", { name: "Session locked", exact: true })
+ .waitFor({ state: "visible" });
+ await headerLockDialog
+ .getByLabel("Password", { exact: true })
+ .fill("Aml-Webui-123!");
+ await headerLockDialog
+ .getByRole("button", { name: "Unlock", exact: true })
+ .click();
+ await page
+ .getByRole("heading", { name: "Session and access", exact: true })
+ .waitFor({ state: "visible", timeout: 15_000 });
+ await page.evaluate(() => {
+ (globalThis as any).location.hash = "#/dev";
+ });
+ await page
+ .getByRole("heading", { name: "Development settings", exact: true })
+ .waitFor({ state: "visible" });
+ const effectiveBaseUrl = (
+ await page.locator("form code").textContent()
+ )?.trim();
+ t.assertTrue(!!effectiveBaseUrl, "Dev screen must show the effective URL");
+ await page
+ .getByLabel("Exchange base URL", { exact: true })
+ .fill("http://127.0.0.1:1/");
+ await page.getByRole("button", { name: "Apply and reload" }).click();
+ await page
+ .getByRole("heading", { name: "Development settings", exact: true })
+ .waitFor({ state: "visible", timeout: 15_000 });
+ t.assertTrue(
+ (await page.evaluate(() =>
+ (globalThis as any).localStorage.getItem("aml-base-url"),
+ )) === "http://127.0.0.1:1/",
+ "Dev screen must render with an unavailable exchange override",
+ );
+ await page
+ .getByLabel("Exchange base URL", { exact: true })
+ .fill(effectiveBaseUrl!);
+ await page.getByRole("button", { name: "Apply and reload" }).click();
+ await page
+ .getByRole("heading", { name: "Development settings", exact: true })
+ .waitFor({ state: "visible", timeout: 15_000 });
+ const headerLogo = page
+ .getByRole("banner")
+ .getByRole("link", { name: "GNU Taler", exact: true });
+ t.assertTrue(
+ (await headerLogo.getAttribute("href")) === "#/dashboard",
+ "header logo should link to the AML dashboard",
+ );
+ await headerLogo.click();
+ await page
+ .getByRole("heading", { name: "Session locked", exact: true })
+ .waitFor({ state: "visible", timeout: 15_000 });
+ t.assertTrue(
+ pageErrors.length === 0 &&
+ browserDiagnostics.length === 0 &&
+ renderDiagnostics.length === 0,
+ [...pageErrors, ...browserDiagnostics, ...renderDiagnostics].join("\n"),
+ );
+ } catch (cause) {
+ await browser.page.screenshot({
+ path: path.join(t.testDir, "exchange-aml-webui-failure.png"),
+ fullPage: true,
+ });
+ throw new Error(
+ [
+ String(cause),
+ ...pageErrors,
+ ...browserDiagnostics,
+ ...renderDiagnostics,
+ ].join("\n"),
+ );
+ } finally {
+ await browser.close();
+ await webui.close();
+ }
+}
+
+runExchangeAmlWebuiTest.suites = ["web", "exchange", "kyc", "aml-webui"];
diff --git a/packages/taler-harness/src/integrationtests/testrunner.ts b/packages/taler-harness/src/integrationtests/testrunner.ts
@@ -67,6 +67,7 @@ import { runExchangeEphemeralTest } from "./test-exchange-ephemeral.js";
import { runExchangeKeysCherrypickTest } from "./test-exchange-keys-cherrypick.js";
import { runExchangeKeysWithdrawFilterTest } from "./test-exchange-keys-withdraw-filter.js";
import { runExchangeKycAuthTest } from "./test-exchange-kyc-auth.js";
+import { runExchangeAmlWebuiTest } from "./test-exchange-aml-webui.js";
import { runExchangeManagementFaultTest } from "./test-exchange-management-fault.js";
import { runExchangeManagementTest } from "./test-exchange-management.js";
import { runExchangeCurrencyChangeTest } from "./test-exchange-currency-change.js";
@@ -439,6 +440,7 @@ const allTests: TestMainFunction[] = [
runWalletTransactionsTest,
runKycWithdrawalVerbotenTest,
runKycDecisionsTest,
+ runExchangeAmlWebuiTest,
runKnownAccountsTest,
runKycDepositAggregateImplicitAuthTest,
runKycAmpTimeoutTest,
diff --git a/packages/taler-util/src/aml/reporting.test.ts b/packages/taler-util/src/aml/reporting.test.ts
@@ -0,0 +1,35 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import assert from "node:assert";
+import { test } from "node:test";
+import { TOPS_AmlEventsName } from "./events.js";
+import { fetchTopsInfoFromServer } from "./reporting.js";
+
+test("TOPS reporting preserves successful counters when one query fails", async () => {
+ const api = {
+ async getAmlKycStatistics(_officer: unknown, events: TOPS_AmlEventsName[]) {
+ if (events[0] === TOPS_AmlEventsName.DECR_HIGH_RISK_CUSTOMER) {
+ throw new Error("counter temporarily unavailable");
+ }
+ return {
+ type: "ok",
+ body: { statistics: [{ event: events[0], counter: 10 }] },
+ };
+ },
+ };
+
+ const result = await fetchTopsInfoFromServer(api as any, {} as any);
+ assert.strictEqual(result.values.accounts_opened, 0);
+ assert.strictEqual(result.values.gwg_files_high_risk, undefined);
+ assert.deepStrictEqual(
+ result.failures.map((failure) => failure.query),
+ ["gwg_files_high_risk_decr"],
+ );
+});
diff --git a/packages/taler-util/src/aml/reporting.ts b/packages/taler-util/src/aml/reporting.ts
@@ -327,6 +327,18 @@ export type CounterResultByEventName<T> = {
[name in keyof T]?: number;
};
+export interface StatisticsQueryFailure {
+ query: string;
+ event: string;
+ status?: number;
+ message?: string;
+}
+
+export interface PartialStatisticsResult<T> {
+ values: T;
+ failures: StatisticsQueryFailure[];
+}
+
export type EventQueryByEventName<T> = {
[name in keyof T]: EventQuery<string>;
};
@@ -347,30 +359,70 @@ function safeAdd(
export async function fetchTopsInfoFromServer(
api: TalerExchangeHttpClient,
officer: OfficerSession,
-) {
+): Promise<
+ PartialStatisticsResult<ReturnType<typeof EventReporting_TOPS_calculation>>
+> {
type EventType = typeof EventReporting_TOPS_queries;
const eventList = Object.entries(EventReporting_TOPS_queries);
const allQueries = eventList.map(async ([_key, value]) => {
const key = _key as keyof EventType;
- const response = await api.getAmlKycStatistics(officer, [value.event], {
- since: value.start,
- until: value.end,
- });
- return { key, response };
+ try {
+ const response = await api.getAmlKycStatistics(officer, [value.event], {
+ since: value.start,
+ until: value.end,
+ });
+ if (response.type !== "ok") {
+ return {
+ key,
+ value: undefined,
+ failure: {
+ query: String(key),
+ event: String(value.event),
+ status: response.response.status,
+ message: response.detail?.hint,
+ } satisfies StatisticsQueryFailure,
+ };
+ }
+ const statistic = response.body.statistics[0];
+ if (!statistic) {
+ return {
+ key,
+ value: undefined,
+ failure: {
+ query: String(key),
+ event: String(value.event),
+ message: "The exchange returned no statistic for the event",
+ } satisfies StatisticsQueryFailure,
+ };
+ }
+ return { key, value: statistic.counter, failure: undefined };
+ } catch (cause) {
+ return {
+ key,
+ value: undefined,
+ failure: {
+ query: String(key),
+ event: String(value.event),
+ message: cause instanceof Error ? cause.message : String(cause),
+ } satisfies StatisticsQueryFailure,
+ };
+ }
});
const allResponses = await Promise.all(allQueries);
const resultMap = allResponses.reduce((prev, event) => {
- prev[event.key] =
- event.response.type === "ok"
- ? event.response.body.statistics[0].counter
- : undefined;
+ prev[event.key] = event.value;
return prev;
}, {} as CounterResultByEventName<EventType>);
- return EventReporting_TOPS_calculation(resultMap);
+ return {
+ values: EventReporting_TOPS_calculation(resultMap),
+ failures: allResponses.flatMap((result) =>
+ result.failure ? [result.failure] : [],
+ ),
+ };
}
export async function fetchVqfInfoFromServer(
diff --git a/packages/taler-util/src/http-client/aml-accounts.test.ts b/packages/taler-util/src/http-client/aml-accounts.test.ts
@@ -0,0 +1,106 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+import assert from "node:assert";
+import { test } from "node:test";
+import {
+ HeadersImpl,
+ HttpRequestLibrary,
+ HttpRequestOptions,
+ HttpResponse,
+} from "../http-common.js";
+import { OfficerSession } from "../types-taler-common.js";
+import { TalerExchangeHttpClient } from "./exchange-client.js";
+
+class RecordingHttpLib implements HttpRequestLibrary {
+ lastUrl: string | undefined;
+
+ async fetch(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
+ this.lastUrl = url;
+ return {
+ requestUrl: url,
+ requestMethod: opt?.method ?? "GET",
+ status: 204,
+ headers: new HeadersImpl(),
+ async json() {
+ return {};
+ },
+ async text() {
+ return "";
+ },
+ async bytes() {
+ return new Uint8Array();
+ },
+ };
+ }
+}
+
+const officer: OfficerSession = {
+ id: "4TQZQ0M6CB0JZXJ3Z1B4H7X3EVAQXX45SB9QT0NXZYKAHQXZ3EYG" as any,
+ __signingKey: new Uint8Array(32) as any,
+};
+
+test("AML account list serializes negative filters", async () => {
+ const http = new RecordingHttpLib();
+ const client = new TalerExchangeHttpClient("https://exchange.example/", {
+ httpClient: http,
+ });
+ await client.getAmlAccounts(officer, {
+ investigation: false,
+ open: false,
+ highRisk: false,
+ });
+ assert.ok(http.lastUrl);
+ const url = new URL(http.lastUrl);
+ assert.strictEqual(url.searchParams.get("investigation"), "NO");
+ assert.strictEqual(url.searchParams.get("open"), "NO");
+ assert.strictEqual(url.searchParams.get("high_risk"), "NO");
+});
+
+test("AML account list serializes an exact account filter", async () => {
+ const http = new RecordingHttpLib();
+ const client = new TalerExchangeHttpClient("https://exchange.example/", {
+ httpClient: http,
+ });
+ const account = "0000000000000000000000000000000000000000000000000000" as any;
+ await client.getAmlAccounts(officer, { account });
+ assert.ok(http.lastUrl);
+ const url = new URL(http.lastUrl);
+ assert.strictEqual(url.searchParams.get("h_payto"), account);
+});
+
+test("AML account export serializes positive and negative filters", async () => {
+ const http = new RecordingHttpLib();
+ const client = new TalerExchangeHttpClient("https://exchange.example/", {
+ httpClient: http,
+ });
+ await client.getAmlAccountsAsOtherFormat(officer, "text/csv", {
+ investigation: true,
+ open: false,
+ highRisk: true,
+ });
+ assert.ok(http.lastUrl);
+ const url = new URL(http.lastUrl);
+ assert.strictEqual(url.searchParams.get("investigation"), "YES");
+ assert.strictEqual(url.searchParams.get("open"), "NO");
+ assert.strictEqual(url.searchParams.get("high_risk"), "YES");
+});
+
+test("AML account list omits all filters", async () => {
+ const http = new RecordingHttpLib();
+ const client = new TalerExchangeHttpClient("https://exchange.example/", {
+ httpClient: http,
+ });
+ await client.getAmlAccounts(officer);
+ assert.ok(http.lastUrl);
+ const url = new URL(http.lastUrl);
+ assert.strictEqual(url.searchParams.get("investigation"), null);
+ assert.strictEqual(url.searchParams.get("open"), null);
+ assert.strictEqual(url.searchParams.get("high_risk"), null);
+ assert.strictEqual(url.searchParams.get("h_payto"), null);
+});
diff --git a/packages/taler-util/src/http-client/aml-wallet-credit.test.ts b/packages/taler-util/src/http-client/aml-wallet-credit.test.ts
@@ -0,0 +1,82 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+import assert from "node:assert/strict";
+import test from "node:test";
+import {
+ HeadersImpl,
+ HttpRequestLibrary,
+ HttpRequestOptions,
+ HttpResponse,
+} from "../http-common.js";
+import { OfficerSession } from "../types-taler-common.js";
+import { TalerExchangeHttpClient } from "./exchange-client.js";
+
+class RecordingHttpLib implements HttpRequestLibrary {
+ lastUrl: string | undefined;
+ lastOptions: HttpRequestOptions | undefined;
+
+ async fetch(
+ url: string,
+ options?: HttpRequestOptions,
+ ): Promise<HttpResponse> {
+ this.lastUrl = url;
+ this.lastOptions = options;
+ return {
+ requestUrl: url,
+ requestMethod: options?.method ?? "GET",
+ status: 204,
+ headers: new HeadersImpl(),
+ async json() {
+ return {};
+ },
+ async text() {
+ return "";
+ },
+ async bytes() {
+ return new Uint8Array();
+ },
+ };
+ }
+}
+
+const officer: OfficerSession = {
+ id: "4TQZQ0M6CB0JZXJ3Z1B4H7X3EVAQXX45SB9QT0NXZYKAHQXZ3EYG" as never,
+ __signingKey: new Uint8Array(32) as never,
+};
+
+test("wallet credit requests serialize filters and return an empty list", async () => {
+ const http = new RecordingHttpLib();
+ const client = new TalerExchangeHttpClient("https://exchange.example/", {
+ httpClient: http,
+ });
+
+ const result = await client.getWalletCredit(officer, {
+ order: "dec",
+ offset: "42",
+ limit: 11,
+ threshold: { currency: "CHF", value: 12, fraction: 50000000 },
+ account: "1111111111111111111111111111111111111111111111111111" as never,
+ });
+
+ assert.ok(http.lastUrl);
+ const url = new URL(http.lastUrl);
+ assert.equal(url.pathname, `/aml/${officer.id}/wallet-credit`);
+ assert.equal(url.searchParams.get("offset"), "42");
+ assert.equal(url.searchParams.get("limit"), "-11");
+ assert.equal(url.searchParams.get("threshold"), "CHF:12.5");
+ assert.equal(
+ url.searchParams.get("h_payto"),
+ "1111111111111111111111111111111111111111111111111111",
+ );
+ assert.ok(http.lastOptions?.headers?.["Taler-AML-Officer-Signature"]);
+ assert.equal(result.type, "ok");
+ if (result.type === "ok") {
+ assert.deepEqual(result.body, { transfers: [] });
+ }
+});
diff --git a/packages/taler-util/src/http-client/exchange-client.ts b/packages/taler-util/src/http-client/exchange-client.ts
@@ -56,6 +56,7 @@ import {
AccountKycStatus,
AmlDecisionRequest,
AmlDecisionsResponse,
+ AmlOfficerInfo,
AvailableMeasureSummary,
BatchDepositSuccess,
BlindingPrepareRequest,
@@ -105,6 +106,7 @@ import {
codecForAmlDecisionsAccounts,
codecForAmlDecisionsResponse,
codecForAmlKycAttributes,
+ codecForAmlOfficerInfo,
codecForAmlStatisticsResponse,
codecForAmlWalletKycCheckResponse,
codecForAvailableMeasureSummary,
@@ -195,6 +197,16 @@ export function formatAcceptHeader(formats: string[]): string {
.join(", ");
}
+function addYesNoFilter(
+ url: URL,
+ name: string,
+ value: boolean | undefined,
+): void {
+ if (value !== undefined) {
+ url.searchParams.set(name, value ? "YES" : "NO");
+ }
+}
+
/**
* Client library for the GNU Taler exchange service.
*/
@@ -1048,6 +1060,40 @@ export class TalerExchangeHttpClient {
//
/**
+ * https://docs.taler.net/core/api-exchange.html#get--aml-$OFFICER_PUB
+ */
+ async getAmlOfficer(
+ auth: OfficerSession,
+ ): Promise<
+ | OperationOk<AmlOfficerInfo>
+ | OperationFail<
+ | HttpStatusCode.BadRequest
+ | HttpStatusCode.Forbidden
+ | HttpStatusCode.NotFound
+ >
+ > {
+ const resp = await this.fetch(`aml/${pathSegment(auth.id)}`, {
+ method: "GET",
+ headers: {
+ "Taler-AML-Officer-Signature": encodeCrock(
+ signAmlQuery(auth.__signingKey),
+ ),
+ },
+ });
+
+ switch (resp.status) {
+ case HttpStatusCode.Ok:
+ return opSuccessFromHttp(resp, codecForAmlOfficerInfo());
+ case HttpStatusCode.BadRequest:
+ case HttpStatusCode.Forbidden:
+ case HttpStatusCode.NotFound:
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownHttpFailure(resp);
+ }
+ }
+
+ /**
* https://docs.taler.net/core/api-exchange.html#get--aml-$OFFICER_PUB-measures
*
*/
@@ -1146,6 +1192,7 @@ export class TalerExchangeHttpClient {
async getAmlAccounts(
auth: OfficerSession,
params: PaginationParams & {
+ account?: PaytoHash;
highRisk?: boolean;
open?: boolean;
investigation?: boolean;
@@ -1154,18 +1201,12 @@ export class TalerExchangeHttpClient {
const url = new URL(`aml/${pathSegment(auth.id)}/accounts`, this.baseUrl);
addPaginationParams(url, params);
- if (params.investigation !== undefined) {
- url.searchParams.set(
- "investigation",
- params.investigation ? "YES" : "NO",
- );
- }
- if (params.open !== undefined && params.open) {
- url.searchParams.set("open", "YES");
- }
- if (params.highRisk !== undefined && params.highRisk) {
- url.searchParams.set("high_risk", "YES");
+ if (params.account !== undefined) {
+ url.searchParams.set("h_payto", params.account);
}
+ addYesNoFilter(url, "investigation", params.investigation);
+ addYesNoFilter(url, "open", params.open);
+ addYesNoFilter(url, "high_risk", params.highRisk);
const resp = await this.fetch(url, {
headers: {
@@ -1197,6 +1238,7 @@ export class TalerExchangeHttpClient {
auth: OfficerSession,
mime: "text/csv" | "application/vnd.ms-excel" | "application/json",
params: {
+ account?: PaytoHash;
highRisk?: boolean;
open?: boolean;
investigation?: boolean;
@@ -1211,19 +1253,14 @@ export class TalerExchangeHttpClient {
url.searchParams.set("offset", "0");
url.searchParams.set("limit", "99999999");
- if (params.investigation !== undefined) {
- url.searchParams.set(
- "investigation",
- params.investigation ? "YES" : "NO",
- );
- }
- if (params.open !== undefined && params.open) {
- url.searchParams.set("open", "YES");
- }
- if (params.highRisk !== undefined && params.highRisk) {
- url.searchParams.set("high_risk", "YES");
+ if (params.account !== undefined) {
+ url.searchParams.set("h_payto", params.account);
}
+ addYesNoFilter(url, "investigation", params.investigation);
+ addYesNoFilter(url, "open", params.open);
+ addYesNoFilter(url, "high_risk", params.highRisk);
+
const resp = await this.fetch(url, {
headers: {
Accept: mime,
@@ -1475,7 +1512,7 @@ export class TalerExchangeHttpClient {
switch (resp.status) {
case HttpStatusCode.NoContent: {
- this.cacheEvictor.notifySuccess(
+ await this.cacheEvictor.notifySuccess(
TalerExchangeCacheEviction.MAKE_AML_DECISION,
);
return opEmptySuccess(resp);
@@ -1652,6 +1689,60 @@ export class TalerExchangeHttpClient {
}
/**
+ * https://docs.taler.net/core/api-exchange.html#get--aml-$OFFICER_PUB-wallet-credit
+ *
+ */
+ async getWalletCredit(
+ auth: OfficerSession,
+ params: PaginationParams & {
+ threshold?: AmountJson;
+ account?: PaytoHash;
+ } = {},
+ ): Promise<
+ | OperationOk<ExchangeTransferList>
+ | OperationFail<
+ | HttpStatusCode.Forbidden
+ | HttpStatusCode.NotFound
+ | HttpStatusCode.Conflict
+ >
+ > {
+ const url = new URL(
+ `aml/${pathSegment(auth.id)}/wallet-credit`,
+ this.baseUrl,
+ );
+
+ addPaginationParams(url, params);
+
+ if (params.threshold) {
+ url.searchParams.set("threshold", Amounts.stringify(params.threshold));
+ }
+ if (params.account) {
+ url.searchParams.set("h_payto", params.account);
+ }
+
+ const resp = await this.fetch(url, {
+ headers: {
+ "Taler-AML-Officer-Signature": encodeCrock(
+ signAmlQuery(auth.__signingKey),
+ ),
+ },
+ });
+
+ switch (resp.status) {
+ case HttpStatusCode.Ok:
+ return opSuccessFromHttp(resp, codecForExchangeTransferList());
+ case HttpStatusCode.NoContent:
+ return opFixedSuccess(resp, { transfers: [] });
+ case HttpStatusCode.Forbidden:
+ case HttpStatusCode.NotFound:
+ case HttpStatusCode.Conflict:
+ return opKnownHttpFailure(resp.status, resp);
+ default:
+ return opUnknownHttpFailure(resp);
+ }
+ }
+
+ /**
* Request: POST /withdraw
*
* https://docs.taler.net/core/api-exchange.html#withdrawal
diff --git a/packages/taler-util/src/http-client/status-handling.test.ts b/packages/taler-util/src/http-client/status-handling.test.ts
@@ -24,6 +24,7 @@ import {
} from "../http-common.js";
import { Amounts } from "../amounts.js";
import { TalerErrorCode } from "../taler-error-codes.js";
+import { OfficerId, OfficerSession } from "../types-taler-common.js";
import { MonitorTimeframeParam } from "../types-taler-corebank.js";
import { TalerBankConversionHttpClient } from "./bank-conversion.js";
import { TalerCoreBankHttpClient } from "./bank-core.js";
@@ -34,12 +35,14 @@ import { TalerExchangeHttpClient } from "./exchange-client.js";
*/
class StubHttpLib implements HttpRequestLibrary {
lastUrl: string | undefined;
+ lastOptions: HttpRequestOptions | undefined;
constructor(
private status: number,
private body: unknown = {},
) {}
async fetch(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
this.lastUrl ??= url;
+ this.lastOptions ??= opt;
const headers = new HeadersImpl();
headers.set("content-type", "application/json");
const body = this.body;
@@ -62,6 +65,32 @@ class StubHttpLib implements HttpRequestLibrary {
}
}
+test("AML officer resource returns identity and signs the request", async () => {
+ const lib = new StubHttpLib(200, {
+ officer_name: "Alice Example",
+ read_only: true,
+ });
+ const client = new TalerExchangeHttpClient("https://exchange.example/", {
+ httpClient: lib,
+ });
+ const officer: OfficerSession = {
+ id: "4TQZQ0M6CB0JZXJ3Z1B4H7X3EVAQXX45SB9QT0NXZYKAHQXZ3EYG" as OfficerId,
+ __signingKey: new Uint8Array(32) as any,
+ };
+
+ const result = await client.getAmlOfficer(officer);
+
+ assert.strictEqual(lib.lastUrl, `${client.baseUrl}aml/${officer.id}`);
+ assert.ok(lib.lastOptions?.headers?.["Taler-AML-Officer-Signature"]);
+ assert.strictEqual(result.type, "ok");
+ if (result.type === "ok") {
+ assert.deepStrictEqual(result.body, {
+ officer_name: "Alice Example",
+ read_only: true,
+ });
+ }
+});
+
test("an unknown corebank account is not an empty token list", async (t) => {
// 404 means the base URL is wrong or the account is gone. Reporting it as
// a successful empty list makes a misconfigured bank indistinguishable from
diff --git a/packages/taler-util/src/types-taler-exchange.test.ts b/packages/taler-util/src/types-taler-exchange.test.ts
@@ -18,6 +18,9 @@ import { test } from "node:test";
import assert from "node:assert";
import {
codecForAuditor,
+ codecForAmlCustomerAccountSummary,
+ codecForAmlDecision,
+ codecForAmlKycAttributes,
codecForAmlSpaDialect,
codecForEventCounter,
codecForExchangeKeysResponse,
@@ -32,6 +35,94 @@ test("AML SPA dialect rejects removed GLS configuration", () => {
assert.throws(() => codecForAmlSpaDialect.decode("gls"));
});
+test("AML account summary accepts only defined system notes", () => {
+ const summary = {
+ h_payto: "0000000000000000000000000000000000000000000000000000",
+ full_payto: "payto://void/test-account",
+ high_risk: false,
+ rowid: 1,
+ open_time: { t_s: "never" },
+ close_time: { t_s: "never" },
+ to_investigate: false,
+ };
+ assert.strictEqual(
+ codecForAmlCustomerAccountSummary().decode({
+ ...summary,
+ system_note: "BELOW_ACCOUNT_OPENING_THRESHOLD",
+ }).system_note,
+ "BELOW_ACCOUNT_OPENING_THRESHOLD",
+ );
+ assert.throws(() =>
+ codecForAmlCustomerAccountSummary().decode({
+ ...summary,
+ system_note: "UNKNOWN_NOTE",
+ }),
+ );
+});
+
+test("AML account summary keeps customer and system information together", () => {
+ const decoded = codecForAmlCustomerAccountSummary().decode({
+ h_payto: "0000000000000000000000000000000000000000000000000000",
+ full_payto: "payto://void/test-account",
+ high_risk: false,
+ comments: "Officer follow-up note",
+ customer_label: "Example customer",
+ system_note: "BELOW_ACCOUNT_OPENING_THRESHOLD",
+ rowid: 1,
+ open_time: { t_s: "never" },
+ close_time: { t_s: "never" },
+ to_investigate: false,
+ });
+ assert.strictEqual(decoded.comments, "Officer follow-up note");
+ assert.strictEqual(decoded.customer_label, "Example customer");
+ assert.strictEqual(decoded.system_note, "BELOW_ACCOUNT_OPENING_THRESHOLD");
+});
+
+test("AML KYC attributes retain collection provenance", () => {
+ const decoded = codecForAmlKycAttributes().decode({
+ details: [
+ {
+ rowid: 7,
+ by_aml_officer: true,
+ attributes: { FORM_ID: "generic_note" },
+ collection_time: { t_s: 1_788_000_000 },
+ },
+ ],
+ });
+ assert.strictEqual(decoded.details[0].by_aml_officer, true);
+ assert.strictEqual(decoded.details[0].attributes?.FORM_ID, "generic_note");
+});
+
+test("AML decisions decode additive audit fields and remain backward compatible", () => {
+ const base = {
+ h_payto: "0000000000000000000000000000000000000000000000000000",
+ rowid: 7,
+ is_wallet: false,
+ decision_time: { t_s: 1_788_000_000 },
+ limits: {
+ expiration_time: { t_s: "never" },
+ rules: [],
+ custom_measures: {},
+ },
+ to_investigate: false,
+ is_active: true,
+ };
+ const oldDecision = codecForAmlDecision().decode(base);
+ assert.strictEqual(oldDecision.new_measures, undefined);
+ assert.strictEqual(oldDecision.decider_pub, undefined);
+
+ const decoded = codecForAmlDecision().decode({
+ ...base,
+ new_measures: "+review screen",
+ decider_pub: "OFFICER-PUBLIC-KEY",
+ decider_name: "Alex Compliance",
+ kyc_attributes_rowid: 42,
+ });
+ assert.strictEqual(decoded.new_measures, "+review screen");
+ assert.strictEqual(decoded.decider_name, "Alex Compliance");
+ assert.strictEqual(decoded.kyc_attributes_rowid, 42);
+});
+
/**
* A /keys response captured from a live exchange (protocol 37:0:3), reduced
* to one denomination group per cipher and one denomination each, with the
diff --git a/packages/taler-util/src/types-taler-exchange.ts b/packages/taler-util/src/types-taler-exchange.ts
@@ -1000,10 +1000,7 @@ export const codecForBlindingPrepareResponse =
(): Codec<BlindingPrepareResponse> =>
buildCodecForObject<BlindingPrepareResponse>()
.property("cipher", codecForConstString(DenomKeyType.ClauseSchnorr))
- .property(
- "r_pubs",
- codecForList(codecForCsRPair()),
- )
+ .property("r_pubs", codecForList(codecForCsRPair()))
.build("BlindingPrepareResponse");
export interface ExchangeLegacyWithdrawRequest {
@@ -1461,8 +1458,7 @@ export const codecForPurseCreateSuccessResponse =
.property("exchange_pub", codecForEddsaPublicKey())
.build("PurseCreateSuccessResponse");
-export interface PurseDepositSuccessResponse
- extends PurseCreateSuccessResponse {
+export interface PurseDepositSuccessResponse extends PurseCreateSuccessResponse {
// Total value the purse must contain after deposit fees.
purse_value_after_fees: AmountString;
@@ -1854,6 +1850,15 @@ export interface BatchDepositRequestCoin {
h_age_commitment?: string;
}
+/** Information about the authenticated AML officer. Since protocol v40. */
+export interface AmlOfficerInfo {
+ /** Legal name configured by the exchange operator. */
+ officer_name: string;
+
+ /** Whether this officer may read AML data but not submit decisions. */
+ read_only: boolean;
+}
+
export interface AvailableMeasureSummary {
// Available original measures that can be
// triggered directly by default rules.
@@ -2346,6 +2351,19 @@ export interface AmlDecision {
// is available.
justification?: string;
+ // Space-separated names of measures requested immediately. A leading
+ // plus sign means all listed measures are required.
+ new_measures?: string;
+
+ // AML officer who made the decision. Missing for automated outcomes.
+ decider_pub?: AmlOfficerPublicKeyP;
+
+ // Human-readable officer name valid at the time of the decision.
+ decider_name?: string;
+
+ // Submitted customer information linked to this decision.
+ kyc_attributes_rowid?: Integer;
+
// When was the decision made?
decision_time: Timestamp;
@@ -2547,10 +2565,9 @@ export interface KycAttributeCollectionEvent {
// Row ID of the record. Used to filter by offset.
rowid: Integer;
- // Name of the provider
- // which was used to collect the attributes. NULL if they were
- // just uploaded via a form by the account owner.
- provider_name?: string;
+ // True if the attributes were filed by an AML officer,
+ // otherwise they were provided directly by the customer.
+ by_aml_officer: boolean;
// The collected KYC data. NULL if the attribute data could not
// be decrypted (internal error of the exchange, likely the
@@ -2823,6 +2840,12 @@ export const codecForAvailableMeasureSummary =
.property("default_rules", codecForList(codecForKycRules()))
.build("TalerExchangeApi.AvailableMeasureSummary");
+export const codecForAmlOfficerInfo = (): Codec<AmlOfficerInfo> =>
+ buildCodecForObject<AmlOfficerInfo>()
+ .property("officer_name", codecForString())
+ .property("read_only", codecForBoolean())
+ .build("TalerExchangeApi.AmlOfficerInfo");
+
export const codecForAmlProgramRequirement = (): Codec<AmlProgramRequirement> =>
buildCodecForObject<AmlProgramRequirement>()
.property("description", codecForString())
@@ -2868,9 +2891,15 @@ export interface CustomerAccountSummary {
// True if the account was assessed as being high risk.
high_risk: boolean;
- // Latest comments about the account (if any).
+ // Latest officer-authored file note about the account (if any).
comments?: string;
+ // Human-readable label assigned to the customer (if any).
+ customer_label?: string;
+
+ // Machine-readable system information about the account (if any).
+ system_note?: AmlAccountSystemNote;
+
// Row of the account in the exchange tables. Useful to filter
// by offset.
rowid: Integer;
@@ -2878,13 +2907,16 @@ export interface CustomerAccountSummary {
// When was the account opened? "never" if it was never opened.
open_time: Timestamp;
- // When was the account opened? "never" if it was never closed.
+ // When was the account closed? "never" if it was never closed.
close_time: Timestamp;
// True if the account is under investigation by AML staff
// after this decision.
to_investigate: boolean;
}
+
+export type AmlAccountSystemNote = "BELOW_ACCOUNT_OPENING_THRESHOLD";
+
export interface AmlAccountsResponse {
// Array of customer accounts matching the query.
accounts: CustomerAccountSummary[];
@@ -2896,6 +2928,11 @@ export const codecForAmlCustomerAccountSummary =
.property("close_time", codecForTimestamp)
.property("open_time", codecForTimestamp)
.property("comments", codecOptional(codecForString()))
+ .property("customer_label", codecOptional(codecForString()))
+ .property(
+ "system_note",
+ codecOptional(codecForConstString("BELOW_ACCOUNT_OPENING_THRESHOLD")),
+ )
.property("full_payto", codecFullForPaytoString())
.property("high_risk", codecForBoolean())
.property("rowid", codecForNumber())
@@ -2937,6 +2974,10 @@ export const codecForAmlDecision = (): Codec<AmlDecision> =>
.property("rowid", codecForNumber())
.property("is_wallet", codecForBoolean())
.property("justification", codecOptional(codecForString()))
+ .property("new_measures", codecOptional(codecForString()))
+ .property("decider_pub", codecOptional(codecForString()))
+ .property("decider_name", codecOptional(codecForString()))
+ .property("kyc_attributes_rowid", codecOptional(codecForNumber()))
.property("decision_time", codecForTimestamp)
.property("properties", codecOptional(codecForAccountProperties()))
.property("limits", codecForLegitimizationRuleSet())
@@ -2984,7 +3025,7 @@ export const codecForKycAttributeCollectionEvent =
(): Codec<KycAttributeCollectionEvent> =>
buildCodecForObject<KycAttributeCollectionEvent>()
.property("rowid", codecForNumber())
- .property("provider_name", codecOptional(codecForString()))
+ .property("by_aml_officer", codecForBoolean())
.property("collection_time", codecForTimestamp)
.property("attributes", codecOptional(codecForAny()))
.build("TalerExchangeApi.KycAttributeCollectionEvent");
diff --git a/packages/web-util/src/components/ErrorLoading.tsx b/packages/web-util/src/components/ErrorLoading.tsx
@@ -56,11 +56,22 @@ export function ErrorLoading({
.join("\n\n")}
title={title}
>
- {(description ?? []).map((d, idx) => (
- <p key={idx}>{d}</p>
- ))}
- {debug ? (
- <pre class="whitespace-break-spaces text-black">{debug}</pre>
+ {description.length || debug ? (
+ <details>
+ <summary class="min-h-11 cursor-pointer py-2 font-semibold underline">
+ <i18n.Translate>Technical details</i18n.Translate>
+ </summary>
+ <div class="space-y-1">
+ {description.map((d, idx) => (
+ <p key={idx}>{d}</p>
+ ))}
+ {debug ? (
+ <pre class="mt-3 max-h-72 overflow-auto whitespace-pre-wrap break-words rounded-md bg-white/70 p-3 text-xs text-black">
+ {debug}
+ </pre>
+ ) : undefined}
+ </div>
+ </details>
) : undefined}
</Attention>
);
diff --git a/packages/web-util/src/components/Footer.test.tsx b/packages/web-util/src/components/Footer.test.tsx
@@ -0,0 +1,36 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import assert from "node:assert/strict";
+import test from "node:test";
+import { setupI18n } from "@gnu-taler/taler-util";
+import { h } from "preact";
+import { render as renderToString } from "preact-render-to-string";
+import { Footer } from "./Footer.js";
+
+setupI18n("en", {});
+
+test("compact footer keeps metadata in a quiet inline row", () => {
+ const output = renderToString(
+ <Footer variant="compact" VERSION="1.2.3" GIT_HASH="1234567890abcdef" />,
+ );
+
+ assert.match(output, /border-slate-200/);
+ assert.match(output, /py-2/);
+ assert.doesNotMatch(output, /bg-slate-100/);
+ assert.match(output, /GNU Taler/);
+ assert.match(output, /Version 1.2.3 \(12345678\)/);
+});
+
+test("default footer retains its existing surface", () => {
+ const output = renderToString(<Footer VERSION="1.2.3" />);
+
+ assert.match(output, /bg-slate-100/);
+ assert.match(output, /py-4/);
+});
diff --git a/packages/web-util/src/components/Footer.tsx b/packages/web-util/src/components/Footer.tsx
@@ -14,7 +14,7 @@ export function Footer({
testingUrlKey?: string;
backgroundClass?: string;
actions?: ComponentChildren;
- variant?: "default" | "demo";
+ variant?: "default" | "demo" | "compact";
}) {
const { i18n } = useTranslationContext();
@@ -40,14 +40,22 @@ export function Footer({
""
);
const effectiveBackgroundClass =
- backgroundClass ?? (variant === "demo" ? "" : "bg-slate-200");
+ backgroundClass ??
+ (variant === "default" ? "bg-slate-100 dark:bg-slate-900" : "");
const testingNotice = testingUrlKey && testingUrl && (
- <p class="text-xs leading-5 text-gray-300">
+ <p
+ class={`text-xs leading-5 ${
+ variant === "demo"
+ ? "text-secondary"
+ : "text-slate-700 dark:text-slate-200"
+ }`}
+ >
<i18n.Translate>
Testing with <span>{testingUrl}</span>
</i18n.Translate>{" "}
<a
href=""
+ class="font-semibold underline hover:text-primary"
onClick={(e) => {
e.preventDefault();
localStorage.removeItem(testingUrlKey);
@@ -59,6 +67,36 @@ export function Footer({
</p>
);
+ if (variant === "compact") {
+ return (
+ <footer
+ class={`mt-auto border-t border-slate-200 dark:border-slate-700 ${effectiveBackgroundClass}`}
+ >
+ <div class="mx-auto flex max-w-screen-2xl flex-wrap items-center gap-x-4 gap-y-1 px-6 py-2 text-xs leading-5 text-slate-600 sm:px-8 dark:text-slate-300">
+ <p class="m-0">
+ <i18n.Translate>
+ Learn more about{" "}
+ <a
+ target="_blank"
+ rel="noreferrer noopener"
+ class="font-semibold text-slate-700 underline hover:text-primary dark:text-slate-100"
+ href="https://taler.net"
+ >
+ GNU Taler
+ </a>
+ </i18n.Translate>
+ <span aria-hidden="true"> · </span>
+ Copyright © 2014—2026 Taler Systems SA. {versionText}
+ </p>
+ {actions ? <div class="shrink-0">{actions}</div> : undefined}
+ {testingNotice ? (
+ <div class="basis-full">{testingNotice}</div>
+ ) : undefined}
+ </div>
+ </footer>
+ );
+ }
+
if (variant === "demo") {
return (
<footer
@@ -93,30 +131,36 @@ export function Footer({
}
return (
- <footer class={`bottom-4 my-4 mx-8 ${effectiveBackgroundClass}`}>
- <div class="flex items-start justify-between gap-4">
+ <footer
+ class={`mt-auto border-t border-slate-300 dark:border-slate-700 ${effectiveBackgroundClass}`}
+ >
+ <div class="mx-auto flex max-w-screen-2xl items-start justify-between gap-4 px-6 py-4 sm:px-8">
<div>
- <p class="text-xs leading-5 text-gray-400">
+ <p class="text-xs leading-5 text-slate-700 dark:text-slate-200">
<i18n.Translate>
Learn more about{" "}
<a
target="_blank"
rel="noreferrer noopener"
- class="font-semibold text-gray-500 hover:text-gray-400"
+ class="font-semibold text-slate-900 underline hover:text-primary dark:text-white"
href="https://taler.net"
>
GNU Taler
</a>
</i18n.Translate>
</p>
- <p class="text-xs leading-5 text-gray-400">
+ <p class="text-xs leading-5 text-slate-700 dark:text-slate-200">
Copyright © 2014—2026 Taler Systems SA.{" "}
{versionText}{" "}
</p>
</div>
{actions ? <div class="shrink-0">{actions}</div> : undefined}
</div>
- {testingNotice}
+ {testingNotice ? (
+ <div class="mx-auto max-w-screen-2xl px-6 pb-4 sm:px-8">
+ {testingNotice}
+ </div>
+ ) : undefined}
</footer>
);
}
diff --git a/packages/web-util/src/components/Header.tsx b/packages/web-util/src/components/Header.tsx
@@ -9,23 +9,27 @@ interface Props {
iconLinkURL: string;
profileURL?: string;
notificationURL?: string;
+ actions?: ComponentChildren;
children?: ComponentChildren;
onLogout: (() => void) | undefined;
sites: Array<Array<string>>;
showMenu?: boolean;
backgroundClass?: string;
+ logoSrc?: string;
}
export function Header({
title,
profileURL,
notificationURL,
+ actions,
iconLinkURL,
sites,
onLogout,
children,
showMenu = true,
backgroundClass = "bg-primary",
+ logoSrc,
}: Props): VNode {
const { i18n } = useTranslationContext();
const [open, setOpen] = useState(false);
@@ -53,7 +57,11 @@ export function Header({
<div class="flex px-2 justify-start">
<div class="flex-shrink-0 rounded-lg">
<a href={iconLinkURL ?? "#"} name="logo">
- <img class="h-8 w-auto m-1" src={logo} alt="GNU Taler" />
+ <img
+ class="h-8 w-auto m-1"
+ src={logoSrc ?? logo}
+ alt="GNU Taler"
+ />
</a>
</div>
<span class="flex items-center text-white text-lg font-bold ml-4">
@@ -78,7 +86,7 @@ export function Header({
})}
</div>
</div>
- <div class="flex justify-end">
+ <div class="flex items-center justify-end gap-1">
{!notificationURL ? undefined : (
<a
href={notificationURL}
@@ -151,6 +159,7 @@ export function Header({
</svg>
</a>
)}
+ {actions}
<LangSelector type="icon" />
{showMenu ? (
diff --git a/packages/web-util/src/components/LangSelector.tsx b/packages/web-util/src/components/LangSelector.tsx
@@ -119,7 +119,7 @@ export function LangSelector({
return (
<button
type="button"
- class="relative w-full rounded-md bg-white p-2 text-left text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-600"
+ class="relative rounded-md p-2 text-white hover:bg-white/10 focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-primary"
aria-haspopup="true"
aria-expanded={!hidden}
aria-label={i18n.str`Select language`}
diff --git a/packages/web-util/src/components/Pagination.tsx b/packages/web-util/src/components/Pagination.tsx
@@ -8,10 +8,12 @@ import { useTranslationContext } from "../context/translation.js";
* @returns
*/
export function Pagination({
+ currentPage,
onFirstPage,
onPrevious,
onNext,
}: {
+ currentPage: number;
onFirstPage?: () => void;
onPrevious?: () => void;
onNext?: () => void;
@@ -19,26 +21,32 @@ export function Pagination({
const { i18n } = useTranslationContext();
return (
<nav
- class="flex items-center justify-between border-t border-gray-200 bg-white px-4 py-3 sm:px-6 rounded-lg"
- aria-label="Pagination"
+ class="flex flex-col gap-3 border-t border-gray-200 bg-white px-4 py-3 sm:flex-row sm:items-center sm:justify-between sm:px-6 dark:border-gray-700 dark:bg-gray-950"
+ aria-label={i18n.str`Pagination`}
>
- <div class="flex flex-1 justify-between sm:justify-end">
+ <p
+ class="text-sm font-medium text-gray-700 dark:text-gray-300"
+ aria-live="polite"
+ >
+ {i18n.str`Page ${currentPage}`}
+ </p>
+ <div class="flex justify-between sm:justify-end">
<button
- class="relative disabled:bg-gray-100 disabled:text-gray-500 inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus-visible:outline-offset-0"
+ class="relative inline-flex min-h-11 items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus-visible:outline-offset-0 disabled:bg-gray-100 disabled:text-gray-500 dark:bg-gray-950 dark:text-gray-100 dark:ring-gray-600 dark:hover:bg-gray-900 dark:disabled:bg-gray-800 dark:disabled:text-gray-400"
disabled={!onFirstPage}
onClick={onFirstPage}
>
<i18n.Translate>First page</i18n.Translate>
</button>
<button
- class="relative disabled:bg-gray-100 disabled:text-gray-500 ml-3 inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus-visible:outline-offset-0"
+ class="relative ml-3 inline-flex min-h-11 items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus-visible:outline-offset-0 disabled:bg-gray-100 disabled:text-gray-500 dark:bg-gray-950 dark:text-gray-100 dark:ring-gray-600 dark:hover:bg-gray-900 dark:disabled:bg-gray-800 dark:disabled:text-gray-400"
disabled={!onPrevious}
onClick={onPrevious}
>
<i18n.Translate>Previous</i18n.Translate>
</button>
<button
- class="relative disabled:bg-gray-100 disabled:text-gray-500 ml-3 inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus-visible:outline-offset-0"
+ class="relative ml-3 inline-flex min-h-11 items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus-visible:outline-offset-0 disabled:bg-gray-100 disabled:text-gray-500 dark:bg-gray-950 dark:text-gray-100 dark:ring-gray-600 dark:hover:bg-gray-900 dark:disabled:bg-gray-800 dark:disabled:text-gray-400"
disabled={!onNext}
onClick={onNext}
>
diff --git a/packages/web-util/src/context/exchange-api.ts b/packages/web-util/src/context/exchange-api.ts
@@ -104,12 +104,14 @@ export const ExchangeApiProvider = ({
evictors = NO_EVICTORS,
frameOnError,
preventCompression,
+ compatibilityLoading,
}: {
baseUrl: URL;
evictors?: Evictors;
children: ComponentChildren;
frameOnError: FunctionComponent<{ children: ComponentChildren }>;
preventCompression?: boolean;
+ compatibilityLoading?: ComponentChildren;
}): VNode => {
const [checked, setChecked] = useState<ConfigResult<KeysAndConfigType>>();
const checkedFor = useRef<string>();
@@ -168,11 +170,13 @@ export const ExchangeApiProvider = ({
if (currentChecked === undefined) {
return h(frameOnError, {
- children: h(
- "div",
- {},
- i18n.str`Checking compatibility of this webapp with backend service...`,
- ),
+ children:
+ compatibilityLoading ??
+ h(
+ "div",
+ {},
+ i18n.str`Checking compatibility of this webapp with backend service...`,
+ ),
});
}
if (currentChecked.type === "error") {
diff --git a/packages/web-util/src/forms/AcceptTosForm.test.tsx b/packages/web-util/src/forms/AcceptTosForm.test.tsx
@@ -4,6 +4,7 @@ import { i18n, setupI18n, TalerFormAttributes } from "@gnu-taler/taler-util";
import { Window } from "happy-dom";
import { h } from "preact";
import { useForm } from "../hooks/useForm.js";
+import { AcceptTosOfficerView } from "./AcceptTosForm.js";
import { acceptTos } from "./gana/accept-tos.js";
import { FormUI } from "./forms-ui.js";
@@ -40,6 +41,43 @@ const design = acceptTos(i18n, {
tos_version: "terms-v4",
});
+test("the officer view summarizes the submitted acceptance", async () => {
+ const window = installDom();
+ const { cleanup, render } = await import("@testing-library/preact");
+ const view = render(
+ <AcceptTosOfficerView
+ design={design}
+ context={{}}
+ data={{
+ [TalerFormAttributes.ACCEPTED_TERMS_OF_SERVICE]: "accepted-v3",
+ [TalerFormAttributes.DOWNLOADED_TERMS_OF_SERVICE]: true,
+ }}
+ />,
+ );
+ assert.match(view.container.textContent, /Acceptance statusAccepted/);
+ assert.match(view.container.textContent, /Accepted terms versionaccepted-v3/);
+ assert.match(view.container.textContent, /Terms opened or downloadedYes/);
+ assert.match(view.container.textContent, /ProviderExample Exchange/);
+ assert.equal(view.queryByRole("checkbox"), null);
+ assert.equal(view.queryByRole("button"), null);
+
+ view.rerender(
+ <AcceptTosOfficerView design={design} context={{}} data={{}} />,
+ );
+ assert.match(view.container.textContent, /Acceptance statusNot recorded/);
+ assert.match(
+ view.container.textContent,
+ /Accepted terms versionNot recorded/,
+ );
+ assert.match(
+ view.container.textContent,
+ /Terms opened or downloadedNot recorded/,
+ );
+
+ cleanup();
+ await window.happyDOM.abort();
+});
+
async function eventually(assertion: () => void): Promise<void> {
let lastError: unknown;
for (let attempt = 0; attempt < 50; attempt++) {
diff --git a/packages/web-util/src/forms/AcceptTosForm.tsx b/packages/web-util/src/forms/AcceptTosForm.tsx
@@ -8,7 +8,10 @@ import {
isSafeMarkdownSize,
SafeMarkdown,
} from "../components/SafeMarkdown.js";
-import type { AcceptTosFormDesign } from "./forms-types.js";
+import type {
+ AcceptTosFormDesign,
+ FormOfficerViewProps,
+} from "./forms-types.js";
type ReaderDocument = {
content: string;
@@ -17,6 +20,62 @@ type ReaderDocument = {
type ReaderError = "load" | "format" | "large";
+export function AcceptTosOfficerView({
+ design,
+ data,
+}: FormOfficerViewProps): VNode {
+ const { i18n } = useTranslationContext();
+ const accepted = data[TalerFormAttributes.ACCEPTED_TERMS_OF_SERVICE];
+ const acceptedVersion =
+ typeof accepted === "string" && accepted.trim() ? accepted : undefined;
+ const downloaded = data[TalerFormAttributes.DOWNLOADED_TERMS_OF_SERVICE];
+ const providerName =
+ design.type === "accept-tos" ? design.providerName?.trim() : undefined;
+
+ return (
+ <dl class="grid gap-4 sm:grid-cols-2">
+ <div>
+ <dt class="text-sm font-semibold text-gray-900 dark:text-gray-100">
+ <i18n.Translate>Acceptance status</i18n.Translate>
+ </dt>
+ <dd class="mt-1 text-sm text-gray-700 dark:text-gray-300">
+ {acceptedVersion ? i18n.str`Accepted` : i18n.str`Not recorded`}
+ </dd>
+ </div>
+ <div>
+ <dt class="text-sm font-semibold text-gray-900 dark:text-gray-100">
+ <i18n.Translate>Accepted terms version</i18n.Translate>
+ </dt>
+ <dd class="mt-1 break-words font-mono text-sm text-gray-700 dark:text-gray-300">
+ {acceptedVersion ?? i18n.str`Not recorded`}
+ </dd>
+ </div>
+ <div>
+ <dt class="text-sm font-semibold text-gray-900 dark:text-gray-100">
+ <i18n.Translate>Terms opened or downloaded</i18n.Translate>
+ </dt>
+ <dd class="mt-1 text-sm text-gray-700 dark:text-gray-300">
+ {downloaded === true
+ ? i18n.str`Yes`
+ : downloaded === false
+ ? i18n.str`No`
+ : i18n.str`Not recorded`}
+ </dd>
+ </div>
+ {!providerName ? undefined : (
+ <div>
+ <dt class="text-sm font-semibold text-gray-900 dark:text-gray-100">
+ <i18n.Translate>Provider</i18n.Translate>
+ </dt>
+ <dd class="mt-1 text-sm text-gray-700 dark:text-gray-300">
+ {providerName}
+ </dd>
+ </div>
+ )}
+ </dl>
+ );
+}
+
function mediaType(contentType: string | null): string {
return contentType?.split(";", 1)[0].trim().toLowerCase() ?? "";
}
diff --git a/packages/web-util/src/forms/FormProvider.tsx b/packages/web-util/src/forms/FormProvider.tsx
@@ -50,6 +50,11 @@ export interface UIFormProps<ValType> {
*/
label: TranslatedString;
+ /**
+ * Untranslated technical identifier shown below the label.
+ */
+ technicalName?: string;
+
before?: Addon;
after?: Addon;
diff --git a/packages/web-util/src/forms/fields/InputArray.tsx b/packages/web-util/src/forms/fields/InputArray.tsx
@@ -242,6 +242,7 @@ export function InputArray(
<div class="sm:col-span-6">
<LabelWithTooltipMaybeRequired
label={label}
+ technicalName={props.technicalName}
required={required}
tooltip={tooltip}
labelId={labelId}
diff --git a/packages/web-util/src/forms/fields/InputChoiceHorizontal.tsx b/packages/web-util/src/forms/fields/InputChoiceHorizontal.tsx
@@ -25,6 +25,7 @@ export function InputChoiceHorizontal<ChoiceVal>(
<div class="sm:col-span-6">
<LabelWithTooltipMaybeRequired
label={label}
+ technicalName={props.technicalName}
required={required}
tooltip={tooltip}
name={props.name as string}
diff --git a/packages/web-util/src/forms/fields/InputChoiceStacked.tsx b/packages/web-util/src/forms/fields/InputChoiceStacked.tsx
@@ -48,6 +48,7 @@ export function InputChoiceStacked<Choices>(
<div class="sm:col-span-6">
<LabelWithTooltipMaybeRequired
label={label}
+ technicalName={props.technicalName}
required={required}
tooltip={tooltip}
name={props.name as string}
diff --git a/packages/web-util/src/forms/fields/InputDurationText.tsx b/packages/web-util/src/forms/fields/InputDurationText.tsx
@@ -91,7 +91,7 @@ export function InputDurationText(props: UIFormProps<Duration>): VNode {
);
}}
/>
- {i18n.str`No expiration`}
+ {i18n.str`Forever`}
</label>
</div>
);
diff --git a/packages/web-util/src/forms/fields/InputFile.tsx b/packages/web-util/src/forms/fields/InputFile.tsx
@@ -71,6 +71,7 @@ export function InputFile(
<div class="col-span-full">
<LabelWithTooltipMaybeRequired
label={label}
+ technicalName={props.technicalName}
tooltip={tooltip}
required={required}
name={String(props.name)}
diff --git a/packages/web-util/src/forms/fields/InputLine.tsx b/packages/web-util/src/forms/fields/InputLine.tsx
@@ -23,12 +23,14 @@ const TooltipIcon = (
export function LabelWithTooltipMaybeRequired({
label,
+ technicalName,
required,
tooltip,
name,
labelId,
}: {
label: TranslatedString;
+ technicalName?: string;
required?: boolean;
tooltip?: TranslatedString;
name?: string;
@@ -41,7 +43,12 @@ export function LabelWithTooltipMaybeRequired({
for={name}
class="block text-sm font-medium leading-6 text-gray-900"
>
- {label}
+ <span class="block">{label}</span>
+ {technicalName ? (
+ <code class="mt-1 block break-all text-xs font-normal text-gray-500 dark:text-gray-400">
+ {technicalName}
+ </code>
+ ) : undefined}
</label>
</div>
);
@@ -119,6 +126,7 @@ export function RenderAddon({
export function InputWrapper<T>({
children,
label,
+ technicalName,
tooltip,
before,
after,
@@ -136,6 +144,7 @@ export function InputWrapper<T>({
<div class="sm:col-span-6 ">
<LabelWithTooltipMaybeRequired
label={label}
+ technicalName={technicalName}
required={required}
tooltip={tooltip}
name={name as string}
diff --git a/packages/web-util/src/forms/fields/InputSelectMultiple.tsx b/packages/web-util/src/forms/fields/InputSelectMultiple.tsx
@@ -60,6 +60,7 @@ export function InputSelectMultiple<ChoiceVal>(
<div class="sm:col-span-6">
<LabelWithTooltipMaybeRequired
label={label}
+ technicalName={props.technicalName}
required={required}
tooltip={tooltip}
name={props.name as string}
diff --git a/packages/web-util/src/forms/fields/InputSelectOne.stories.tsx b/packages/web-util/src/forms/fields/InputSelectOne.stories.tsx
@@ -114,3 +114,44 @@ export const SimpleRequired = tests.createExample(TestedComponent, {
initial: {},
design: design2,
});
+
+const descriptiveDesign: FormDesign = {
+ type: "single-column",
+ fields: [
+ {
+ type: "selectOne",
+ label: "AML/KYC form" as TranslatedString,
+ id: "things",
+ placeholder: "Search AML/KYC forms" as TranslatedString,
+ choices: [
+ {
+ label:
+ "Establishing the controlling person of operating legal entities and partnerships" as TranslatedString,
+ description:
+ "Use for entities and partnerships whose controlling persons must be documented." as TranslatedString,
+ value: "control",
+ },
+ {
+ label: "Identification form" as TranslatedString,
+ description:
+ "Use when accepting a new permanent business relationship." as TranslatedString,
+ value: "identity",
+ },
+ {
+ label: "Special clarifications" as TranslatedString,
+ description:
+ "Use for unusual transactions or relationships associated with increased risk." as TranslatedString,
+ value: "clarification",
+ },
+ ],
+ },
+ ],
+};
+
+export const LongOptionsWithDescriptions = tests.createExample(
+ TestedComponent,
+ {
+ initial: {},
+ design: descriptiveDesign,
+ },
+);
diff --git a/packages/web-util/src/forms/fields/InputSelectOne.test.tsx b/packages/web-util/src/forms/fields/InputSelectOne.test.tsx
@@ -0,0 +1,149 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+import { setupI18n, TranslatedString } from "@gnu-taler/taler-util";
+import { Window } from "happy-dom";
+import assert from "node:assert/strict";
+import test from "node:test";
+import { h } from "preact";
+import { useForm } from "../../hooks/useForm.js";
+import { FormUI } from "../forms-ui.js";
+import { FormDesign } from "../forms-types.js";
+
+setupI18n("en", {});
+
+function installDom(): Window {
+ const window = new Window({ url: "https://forms.example/" });
+ for (const [key, value] of Object.entries({
+ window,
+ document: window.document,
+ navigator: window.navigator,
+ Node: window.Node,
+ Element: window.Element,
+ Event: window.Event,
+ KeyboardEvent: window.KeyboardEvent,
+ HTMLElement: window.HTMLElement,
+ HTMLButtonElement: window.HTMLButtonElement,
+ HTMLInputElement: window.HTMLInputElement,
+ MutationObserver: window.MutationObserver,
+ })) {
+ Object.defineProperty(globalThis, key, {
+ configurable: true,
+ writable: true,
+ value,
+ });
+ }
+ return window;
+}
+
+async function eventually(assertion: () => void): Promise<void> {
+ let lastError: unknown;
+ for (let attempt = 0; attempt < 50; attempt++) {
+ try {
+ assertion();
+ return;
+ } catch (error) {
+ lastError = error;
+ await new Promise((resolve) => setTimeout(resolve, 0));
+ }
+ }
+ throw lastError;
+}
+
+const design: FormDesign = {
+ type: "single-column",
+ fields: [
+ {
+ type: "selectOne",
+ id: "formId",
+ label: "AML/KYC form" as TranslatedString,
+ placeholder: "Search forms" as TranslatedString,
+ choices: [
+ {
+ label: "Identity form" as TranslatedString,
+ description: "Collect and review a passport" as TranslatedString,
+ value: "identity",
+ },
+ {
+ label: "Proof of address" as TranslatedString,
+ description: "Collect a recent utility bill" as TranslatedString,
+ value: "address",
+ },
+ ],
+ },
+ ],
+};
+
+test("single-select options use full rows and expose keyboard activity", async () => {
+ const window = installDom();
+ const { cleanup, render } = await import("@testing-library/preact");
+ let result: Record<string, unknown> = {};
+
+ function Harness() {
+ const form = useForm<Record<string, unknown>>(design, {});
+ result = form.status.result;
+ return <FormUI design={design} model={form.model} />;
+ }
+
+ const view = render(<Harness />);
+ const input = view.getByRole("combobox") as HTMLInputElement;
+ input.focus();
+ const options = await view.findAllByRole("option");
+ assert.equal(options.length, 2);
+ const first = options[0] as HTMLButtonElement;
+ const second = options[1] as HTMLButtonElement;
+ assert.equal(first.classList.contains("w-full"), true);
+ assert.equal(first.classList.contains("text-left"), true);
+ assert.equal(first.tabIndex, -1);
+ assert.equal(first.getAttribute("aria-selected"), "true");
+ assert.match(first.textContent ?? "", /Collect and review a passport/);
+
+ input.dispatchEvent(
+ new KeyboardEvent("keydown", { key: "ArrowDown", bubbles: true }),
+ );
+ await eventually(() =>
+ assert.equal(second.getAttribute("aria-selected"), "true"),
+ );
+ second.click();
+ await eventually(() => assert.equal(result.formId, "address"));
+
+ cleanup();
+ await window.happyDOM.abort();
+});
+
+test("single-select searches descriptions and has a neutral empty state", async () => {
+ const window = installDom();
+ const { cleanup, render } = await import("@testing-library/preact");
+
+ function Harness() {
+ const form = useForm<Record<string, unknown>>(design, {});
+ return <FormUI design={design} model={form.model} />;
+ }
+
+ const view = render(<Harness />);
+ const input = view.getByRole("combobox") as HTMLInputElement;
+ input.focus();
+ input.value = "passport";
+ input.dispatchEvent(new Event("change", { bubbles: true }));
+ await eventually(() => {
+ const options = view.getAllByRole("option");
+ assert.equal(options.length, 1);
+ assert.match(options[0].textContent ?? "", /Identity form/);
+ });
+
+ input.value = "does not exist";
+ input.dispatchEvent(new Event("change", { bubbles: true }));
+ await eventually(() => {
+ const empty = view.getByRole("option", { name: "No element found" });
+ assert.equal(empty.getAttribute("aria-disabled"), "true");
+ assert.equal(empty.classList.contains("cursor-pointer"), false);
+ });
+
+ cleanup();
+ await window.happyDOM.abort();
+});
diff --git a/packages/web-util/src/forms/fields/InputSelectOne.tsx b/packages/web-util/src/forms/fields/InputSelectOne.tsx
@@ -53,7 +53,9 @@ export function InputSelectOne<Choices>(
filter === undefined
? undefined
: sortedChoices.filter((v) => {
- return v.label.toLocaleLowerCase().includes(normalizedFilter);
+ return [v.label, v.description].some((text) =>
+ text?.toLocaleLowerCase().includes(normalizedFilter),
+ );
});
const noItems =
@@ -64,12 +66,13 @@ export function InputSelectOne<Choices>(
<div class="sm:col-span-6">
<LabelWithTooltipMaybeRequired
label={label}
+ technicalName={props.technicalName}
required={required}
tooltip={tooltip}
name={id}
/>
{value !== undefined ? (
- <span class="inline-flex items-center gap-x-0.5 rounded-md bg-gray-100 p-1 mr-2 font-medium text-gray-600">
+ <span class="mr-2 inline-flex items-center gap-x-0.5 rounded-md bg-gray-100 p-1 font-medium text-gray-600 dark:bg-gray-800 dark:text-gray-200">
{choiceMap[value as string]}
<button
type="button"
@@ -78,7 +81,7 @@ export function InputSelectOne<Choices>(
onChange(undefined!);
setDirty(true);
}}
- class="group relative h-5 w-5 rounded-sm hover:bg-gray-500/20 disabled:cursor-not-allowed"
+ class="group relative h-5 w-5 rounded-sm hover:bg-gray-500/20 focus-visible:outline focus-visible:outline-2 focus-visible:outline-indigo-600 disabled:cursor-not-allowed"
aria-label={i18n.str`Clear selection`}
>
<svg
@@ -136,7 +139,7 @@ export function InputSelectOne<Choices>(
setFilter("");
}}
placeholder={placeholder}
- class="w-full rounded-md border-0 bg-white py-1.5 pl-3 pr-12 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
+ class="w-full rounded-md border-0 bg-white py-1.5 pl-3 pr-12 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 dark:bg-gray-950 dark:text-gray-100 dark:ring-gray-600 sm:text-sm sm:leading-6"
role="combobox"
aria-controls={`${id}-options`}
aria-expanded={filter !== undefined}
@@ -166,7 +169,7 @@ export function InputSelectOne<Choices>(
setDirty(true);
inputRef.current?.focus();
}}
- class="absolute inset-y-0 right-0 flex items-center rounded-r-md px-2 focus:outline-none"
+ class="absolute inset-y-0 right-0 flex items-center rounded-r-md px-2 focus-visible:outline focus-visible:outline-2 focus-visible:outline-indigo-600"
aria-label={i18n.str`Toggle choices`}
>
<svg
@@ -184,12 +187,17 @@ export function InputSelectOne<Choices>(
</button>
{noItems && (
<ul
- class="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm"
+ class="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:bg-gray-950 dark:ring-gray-700 sm:text-sm"
id={`${id}-options`}
role="listbox"
>
- <li class="relative cursor-pointer select-none py-2 pl-3 pr-9 text-gray-900 hover:text-white hover:bg-indigo-600">
- <span class="block truncate font-bold">
+ <li
+ class="px-3 py-2 text-gray-500 dark:text-gray-400"
+ role="option"
+ aria-disabled="true"
+ aria-selected="false"
+ >
+ <span class="block font-medium">
<i18n.Translate>No element found</i18n.Translate>
</span>
</li>
@@ -197,20 +205,31 @@ export function InputSelectOne<Choices>(
)}
{!noItems && filteredChoices && (
<ul
- class="absolute overflow-y-scroll z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm"
+ class="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:bg-gray-950 dark:ring-gray-700 sm:text-sm"
id={`${id}-options`}
role="listbox"
>
{filteredChoices.map((v, idx) => {
+ const active = idx === activeIndex;
return (
- <li key={idx} role="none">
+ <li key={String(v.value)} role="none">
<button
type="button"
- class="relative cursor-pointer select-none py-2 pl-3 pr-9 text-gray-900 hover:text-white hover:bg-indigo-600"
+ class={`group relative w-full cursor-pointer select-none px-3 py-2 text-left hover:bg-indigo-600 hover:text-white ${
+ active
+ ? "bg-indigo-600 text-white"
+ : "text-gray-900 dark:text-gray-100"
+ }`}
id={`${id}-option-${idx}`}
role="option"
- aria-selected={idx === activeIndex}
- data-active={idx === activeIndex}
+ aria-selected={active}
+ aria-describedby={
+ v.description
+ ? `${id}-option-${idx}-description`
+ : undefined
+ }
+ data-active={active}
+ tabIndex={-1}
onMouseEnter={() => setActiveIndex(idx)}
onMouseDown={(e) => {
// Input element should not lose focus
@@ -222,7 +241,21 @@ export function InputSelectOne<Choices>(
setDirty(true);
}}
>
- <span class="block truncate">{v.label}</span>
+ <span class="block break-words font-medium">
+ {v.label}
+ </span>
+ {v.description ? (
+ <span
+ id={`${id}-option-${idx}-description`}
+ class={`mt-0.5 block break-words text-xs group-hover:text-indigo-100 ${
+ active
+ ? "text-indigo-100"
+ : "text-gray-500 dark:text-gray-400"
+ }`}
+ >
+ {v.description}
+ </span>
+ ) : undefined}
</button>
</li>
);
diff --git a/packages/web-util/src/forms/fields/InputToggle.tsx b/packages/web-util/src/forms/fields/InputToggle.tsx
@@ -44,6 +44,7 @@ export function InputToggle(
<div class="flex items-center justify-between">
<LabelWithTooltipMaybeRequired
label={label}
+ technicalName={props.technicalName}
required={required}
tooltip={tooltip}
name={props.name as string}
diff --git a/packages/web-util/src/forms/forms-types.ts b/packages/web-util/src/forms/forms-types.ts
@@ -34,6 +34,7 @@ import {
TranslatedString,
codecForEither,
} from "@gnu-taler/taler-util";
+import type { FunctionComponent } from "preact";
export type FormDesign =
| DoubleColumnFormDesign
@@ -298,6 +299,9 @@ export type UIFieldElementDescription = ComputableFieldConfig & {
/* label if the field, visible for the user */
label: string;
+ /* untranslated technical identifier shown below the label */
+ technicalName?: string;
+
/* long text to be shown on user demand */
tooltip?: string;
@@ -364,6 +368,7 @@ const codecForUIFormFieldBaseDescriptionTemplate = <
.property("required", codecOptional(codecForBoolean()))
.property("help", codecOptional(codecForString()))
.property("label", codecForString())
+ .property("technicalName", codecOptional(codecForString()))
.property("tooltip", codecOptional(codecForString()));
const codecForUIFormFieldBaseConfigTemplate = <
@@ -641,6 +646,7 @@ const codecForFormMetadata = (): Codec<FormMetadata> =>
FormDesign | ((context: any) => FormDesign)
>,
)
+ .property("contextForm", codecOptional(codecForFormDesign()))
.build("FormMetadata");
export const codecForUIForms = (): Codec<UiForms> =>
@@ -654,6 +660,16 @@ export type FormMetadata = {
id: string;
version: number;
config: FormDesign | ((context: any) => FormDesign);
+ /** Optional officer-facing form used to build FORM_CONTEXT. */
+ contextForm?: FormDesign;
+ /** Optional programmatic presentation of submitted data for AML officers. */
+ officerView?: FunctionComponent<FormOfficerViewProps>;
+};
+
+export type FormOfficerViewProps = {
+ design: FormDesign;
+ context: unknown;
+ data: Readonly<Record<string, unknown>>;
};
export interface UiForms {
diff --git a/packages/web-util/src/forms/forms-ui.test.tsx b/packages/web-util/src/forms/forms-ui.test.tsx
@@ -0,0 +1,185 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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 assert from "node:assert/strict";
+import test from "node:test";
+import { setupI18n, TranslatedString } from "@gnu-taler/taler-util";
+import { Window } from "happy-dom";
+import { h } from "preact";
+import { useForm } from "../hooks/useForm.js";
+import { FormUI, redactFileContents } from "./forms-ui.js";
+import { FormDesign } from "./forms-types.js";
+
+setupI18n("en", {});
+
+test("raw form data redacts nested file contents without changing other values", () => {
+ assert.deepEqual(
+ redactFileContents({
+ empty: null,
+ files: [
+ {
+ ENCODING: "base64",
+ CONTENTS: "large-payload",
+ FILENAME: "evidence.pdf",
+ },
+ ],
+ note: "keep this",
+ }),
+ {
+ empty: null,
+ files: [
+ {
+ ENCODING: "base64",
+ CONTENTS: "[... skipped ...]",
+ FILENAME: "evidence.pdf",
+ },
+ ],
+ note: "keep this",
+ },
+ );
+});
+
+function installDom(): Window {
+ const window = new Window({ url: "https://forms.example/" });
+ for (const [key, value] of Object.entries({
+ window,
+ document: window.document,
+ navigator: window.navigator,
+ Node: window.Node,
+ Element: window.Element,
+ Event: window.Event,
+ HTMLElement: window.HTMLElement,
+ HTMLButtonElement: window.HTMLButtonElement,
+ HTMLFormElement: window.HTMLFormElement,
+ HTMLInputElement: window.HTMLInputElement,
+ MutationObserver: window.MutationObserver,
+ })) {
+ Object.defineProperty(globalThis, key, {
+ configurable: true,
+ writable: true,
+ value,
+ });
+ }
+ return window;
+}
+
+const design: FormDesign = {
+ type: "single-column",
+ fields: [
+ {
+ type: "text",
+ id: "first",
+ label: "First field" as TranslatedString,
+ },
+ {
+ type: "text",
+ id: "second",
+ label: "Second field" as TranslatedString,
+ },
+ ],
+};
+
+test("submittable forms include a native implicit-submit trigger", async () => {
+ const window = installDom();
+ const { cleanup, render } = await import("@testing-library/preact");
+ let submissions = 0;
+
+ function Harness() {
+ const form = useForm(design, {});
+ return (
+ <FormUI
+ design={design}
+ model={form.model}
+ onSubmit={() => submissions++}
+ />
+ );
+ }
+
+ const view = render(<Harness />);
+ const form = view.container.querySelector("form");
+ assert.ok(form);
+ const submitTrigger = form.querySelector<HTMLButtonElement>(
+ 'button[type="submit"]',
+ );
+ assert.ok(submitTrigger);
+ assert.equal(submitTrigger.classList.contains("sr-only"), true);
+ assert.equal(submitTrigger.tabIndex, -1);
+ assert.equal(submitTrigger.getAttribute("aria-hidden"), "true");
+
+ form.dispatchEvent(new Event("submit", { bubbles: true, cancelable: true }));
+ assert.equal(submissions, 1);
+
+ cleanup();
+ await window.happyDOM.abort();
+});
+
+test("form fields show untranslated technical names below their labels", async () => {
+ const window = installDom();
+ const { cleanup, render } = await import("@testing-library/preact");
+ const designWithTechnicalNames: FormDesign = {
+ type: "single-column",
+ fields: [
+ {
+ type: "text",
+ id: "note",
+ label: "Note" as TranslatedString,
+ technicalName: "FILE_NOTE",
+ },
+ {
+ type: "integer",
+ id: "rating",
+ label: "Rating" as TranslatedString,
+ technicalName: "SANCTION_LIST_RATING",
+ },
+ {
+ type: "toggle",
+ id: "active",
+ label: "Active" as TranslatedString,
+ technicalName: "ACCOUNT_OPEN",
+ },
+ {
+ type: "choiceStacked",
+ id: "state",
+ label: "State" as TranslatedString,
+ technicalName: "INVESTIGATION_STATE",
+ choices: [{ label: "None", value: "NONE" }],
+ },
+ ],
+ };
+
+ function Harness() {
+ const form = useForm(designWithTechnicalNames, {});
+ return <FormUI design={designWithTechnicalNames} model={form.model} />;
+ }
+
+ const view = render(<Harness />);
+ const technicalNameElements = view.container.querySelectorAll(
+ "label code",
+ ) as NodeListOf<HTMLElement>;
+ const technicalNames = Array.from(
+ technicalNameElements,
+ (element) => element.textContent,
+ );
+ assert.deepEqual(technicalNames, [
+ "FILE_NOTE",
+ "SANCTION_LIST_RATING",
+ "ACCOUNT_OPEN",
+ "INVESTIGATION_STATE",
+ ]);
+
+ cleanup();
+ await window.happyDOM.abort();
+});
diff --git a/packages/web-util/src/forms/forms-ui.tsx b/packages/web-util/src/forms/forms-ui.tsx
@@ -65,12 +65,12 @@ export function DefaultForm<T>({
);
}
-export function redactFileContents(result: any): any {
+export function redactFileContents(result: unknown): unknown {
if (Array.isArray(result)) {
return result.map((x) => redactFileContents(x));
}
+ if (result === null || typeof result !== "object") return result;
if (
- typeof result === "object" &&
"ENCODING" in result &&
result.ENCODING === "base64" &&
"CONTENTS" in result
@@ -80,14 +80,11 @@ export function redactFileContents(result: any): any {
CONTENTS: "[... skipped ...]",
};
}
- if (typeof result === "object") {
- return Object.fromEntries(
- Object.entries(result).map(([k, v]) => {
- return [k, redactFileContents(v)];
- }),
- );
- }
- return result;
+ return Object.fromEntries(
+ Object.entries(result).map(([k, v]) => {
+ return [k, redactFileContents(v)];
+ }),
+ );
}
export const DEFAULT_FORM_UI_NAME = "form-ui";
@@ -217,6 +214,14 @@ export function DoubleColumnFormSectionUI<T>({
if (onSubmit) onSubmit();
}}
>
+ {onSubmit ? (
+ <button
+ type="submit"
+ class="sr-only"
+ tabIndex={-1}
+ aria-hidden="true"
+ />
+ ) : undefined}
<div class="px-4 sm:px-0">
<h2 class="text-base font-semibold leading-7 text-gray-900">
{section.title}
@@ -268,6 +273,14 @@ export function SingleColumnFormSectionUI<T>({
if (onSubmit) onSubmit();
}}
>
+ {onSubmit ? (
+ <button
+ type="submit"
+ class="sr-only"
+ tabIndex={-1}
+ aria-hidden="true"
+ />
+ ) : undefined}
<div class="p-3">
<div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
<RenderAllFieldsByUiConfig
diff --git a/packages/web-util/src/forms/forms-utils.ts b/packages/web-util/src/forms/forms-utils.ts
@@ -459,6 +459,7 @@ function convertBaseFieldsProps(
return {
help: i18n_.str`${p.help}`,
label: i18n_.str`${p.label}`,
+ technicalName: p.technicalName,
tooltip: i18n_.str`${p.tooltip}`,
};
}
diff --git a/packages/web-util/src/forms/gana/VQF_902_9_customer.ts b/packages/web-util/src/forms/gana/VQF_902_9_customer.ts
@@ -7,7 +7,8 @@ import { format, intervalToDuration, isFuture, isValid, parse } from "date-fns";
export const form_vqf_902_9_customer = (
i18n: InternationalizationAPI,
): FormMetadata => ({
- label: i18n.str`Declaration of identity of the beneficial owner (A)`,
+ label: i18n.str`Declaration of identity of the beneficial owner (A) — customer`,
+ description: i18n.str`The customer completes the declaration directly in the form.`,
id: "vqf_902_9_customer",
version: 1,
config: VQF_902_9_customer(i18n),
diff --git a/packages/web-util/src/forms/gana/VQF_902_9_metadata.test.ts b/packages/web-util/src/forms/gana/VQF_902_9_metadata.test.ts
@@ -0,0 +1,34 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import { i18n, setupI18n } from "@gnu-taler/taler-util";
+import assert from "node:assert/strict";
+import test from "node:test";
+import { form_vqf_902_9_customer } from "./VQF_902_9_customer.js";
+import { form_vqf_902_9_officer } from "./VQF_902_9_officer.js";
+
+setupI18n("en", {});
+
+test("VQF Form A variants preserve the title and explain their actors", () => {
+ const prescribedTitle = "Declaration of identity of the beneficial owner (A)";
+ const customer = form_vqf_902_9_customer(i18n);
+ const officer = form_vqf_902_9_officer(i18n);
+
+ assert.equal(customer.label, `${prescribedTitle} — customer`);
+ assert.equal(officer.label, `${prescribedTitle} — AML officer`);
+ assert.notEqual(customer.label, officer.label);
+ assert.equal(
+ customer.description,
+ "The customer completes the declaration directly in the form.",
+ );
+ assert.equal(
+ officer.description,
+ "The AML officer records the declaration and uploads the customer's signed PDF.",
+ );
+});
diff --git a/packages/web-util/src/forms/gana/VQF_902_9_officer.ts b/packages/web-util/src/forms/gana/VQF_902_9_officer.ts
@@ -7,7 +7,8 @@ import { intervalToDuration, isFuture, isValid, parse } from "date-fns";
export const form_vqf_902_9_officer = (
i18n: InternationalizationAPI,
): FormMetadata => ({
- label: i18n.str`Declaration of identity of the beneficial owner (A)`,
+ label: i18n.str`Declaration of identity of the beneficial owner (A) — AML officer`,
+ description: i18n.str`The AML officer records the declaration and uploads the customer's signed PDF.`,
id: "vqf_902_9_officer",
version: 1,
config: VQF_902_9_officer(i18n),
diff --git a/packages/web-util/src/forms/gana/accept-tos.stories.tsx b/packages/web-util/src/forms/gana/accept-tos.stories.tsx
@@ -22,6 +22,7 @@
import { i18n, setupI18n } from "@gnu-taler/taler-util";
import * as tests from "../../tests/hook.js";
import { DefaultForm } from "../forms-ui.js";
+import { AcceptTosOfficerView } from "../AcceptTosForm.js";
import { acceptTos } from "./accept-tos.js";
setupI18n("en", {});
@@ -57,4 +58,17 @@ export const AlreadyAccepted = tests.createExample(DefaultForm, {
}),
});
+export const OfficerSummary = tests.createExample(AcceptTosOfficerView, {
+ design: acceptTos(i18n, {
+ tos_url: "https://exchange.demo.taler.net/terms",
+ provider_name: "Taler Operations AG",
+ tos_version: "v1",
+ }),
+ context: {},
+ data: {
+ DOWNLOADED_TERMS_OF_SERVICE: true,
+ ACCEPTED_TERMS_OF_SERVICE: "v1",
+ },
+});
+
export default { title: "accept tos" };
diff --git a/packages/web-util/src/forms/gana/index.stories.ts b/packages/web-util/src/forms/gana/index.stories.ts
@@ -2,6 +2,7 @@ import acceptTosMeta, {
AlreadyAccepted,
EmptyForm as EmptyAcceptTosForm,
LinkOnly,
+ OfficerSummary,
} from "./accept-tos.stories.js";
import vqf9021CustomerMeta, {
DisabledForm,
@@ -13,6 +14,7 @@ export const accept_tops_stories = {
EmptyForm: EmptyAcceptTosForm,
LinkOnly,
AlreadyAccepted,
+ OfficerSummary,
};
export * as generic_note_stories from "./generic_note.stories.js";
export * as generic_upload_stories from "./generic_upload.stories.js";
diff --git a/packages/web-util/src/forms/gana/multi_upload.ts b/packages/web-util/src/forms/gana/multi_upload.ts
@@ -34,6 +34,42 @@ export const form_multi_upload = (
id: "multi_upload",
version: 1,
config: (context: any) => design_multi_upload(i18n, context),
+ contextForm: {
+ type: "single-column",
+ fields: [
+ {
+ id: "REQUESTED_FILES",
+ type: "array",
+ label: i18n.str`Requested documents`,
+ labelFieldId: "REQUESTED_FILE_TITLE",
+ fields: [
+ {
+ id: "REQUESTED_FILE_ID",
+ type: "text",
+ label: i18n.str`Document identifier`,
+ required: true,
+ },
+ {
+ id: "REQUESTED_FILE_TITLE",
+ type: "text",
+ label: i18n.str`Title`,
+ required: true,
+ },
+ {
+ id: "REQUESTED_FILE_DESCRIPTION",
+ type: "textArea",
+ label: i18n.str`Description`,
+ required: true,
+ },
+ {
+ id: "REQUESTED_FILE_REQUIRED",
+ type: "toggle",
+ label: i18n.str`Required`,
+ },
+ ],
+ },
+ ],
+ },
});
/**
@@ -45,7 +81,7 @@ export function design_multi_upload(
): DoubleColumnFormDesign {
return {
type: "double-column",
- sections: context.REQUESTED_FILES.map((x, i) => {
+ sections: (context.REQUESTED_FILES ?? []).map((x, i) => {
let fileId: string;
if (x.REQUESTED_FILE_ID != null) {
fileId = x.REQUESTED_FILE_ID;
diff --git a/packages/web-util/src/forms/index.ts b/packages/web-util/src/forms/index.ts
@@ -16,6 +16,7 @@
import { InternationalizationAPI } from "@gnu-taler/taler-util";
import { FormMetadata } from "./forms-types.js";
+import { AcceptTosOfficerView } from "./AcceptTosForm.js";
import { acceptTos } from "./gana/accept-tos.js";
import { form_challenger_email } from "./gana/challenger_email.js";
import { form_challenger_postal } from "./gana/challenger_postal.js";
@@ -90,6 +91,34 @@ export const preloadedForms: (
id: "accept-tos",
version: 1,
config: (context: any) => acceptTos(i18n, context),
+ officerView: AcceptTosOfficerView,
+ contextForm: {
+ type: "single-column",
+ fields: [
+ {
+ id: "tos_url",
+ type: "text",
+ label: i18n.str`Terms URL`,
+ required: true,
+ },
+ {
+ id: "tos_version",
+ type: "text",
+ label: i18n.str`Terms version`,
+ required: true,
+ },
+ {
+ id: "provider_name",
+ type: "text",
+ label: i18n.str`Provider name`,
+ },
+ {
+ id: "link_only",
+ type: "toggle",
+ label: i18n.str`Only show the external link`,
+ },
+ ],
+ },
},
{
label: i18n.str`Name and birthdate`,
diff --git a/packages/web-util/src/hooks/index.ts b/packages/web-util/src/hooks/index.ts
@@ -9,6 +9,7 @@ export {
useAsyncAsHook,
} from "./useAsyncAsHook.js";
export {
+ type FormModel,
FormErrors,
FormValues,
RecursivePartial,
diff --git a/packages/web-util/src/i18n/de.po b/packages/web-util/src/i18n/de.po
@@ -36,8 +36,8 @@ msgstr ""
"Entwickler: %1$s"
#: packages/web-util/src/hooks/useForm.ts:436
-#: packages/web-util/src/forms/AcceptTosForm.tsx:177
-#: packages/web-util/src/forms/index.ts:89
+#: packages/web-util/src/forms/AcceptTosForm.tsx:236
+#: packages/web-util/src/forms/index.ts:90
msgid "Terms of service"
msgstr "Allgemeine Geschäftsbedingungen"
@@ -200,6 +200,10 @@ msgstr "Benachrichtigung schließen"
msgid "Copy this text manually:"
msgstr "Kopieren Sie diesen Text manuell:"
+#: packages/web-util/src/components/ErrorLoading.tsx:62
+msgid "Technical details"
+msgstr "Technische Details"
+
#: packages/web-util/src/components/LangSelector.tsx:87
#: packages/web-util/src/components/LangSelector.tsx:125
#: packages/web-util/src/components/LangSelector.tsx:149
@@ -215,49 +219,50 @@ msgstr "Sprachen"
msgid "Loading"
msgstr "Wird geladen"
-#: packages/web-util/src/components/Header.tsx:92
+#: packages/web-util/src/components/Header.tsx:100
msgid "Show notifications"
msgstr "Benachrichtigungen anzeigen"
-#: packages/web-util/src/components/Header.tsx:136
+#: packages/web-util/src/components/Header.tsx:144
msgid "Open profile"
msgstr "Profil öffnen"
-#: packages/web-util/src/components/Header.tsx:168
+#: packages/web-util/src/components/Header.tsx:177
msgid "Open settings"
msgstr "Einstellungen öffnen"
-#: packages/web-util/src/components/Header.tsx:202
-#: packages/web-util/src/components/Header.tsx:231
+#: packages/web-util/src/components/Header.tsx:211
+#: packages/web-util/src/components/Header.tsx:240
msgid "Close panel"
msgstr "Panel schließen"
-#: packages/web-util/src/components/Header.tsx:217
+#: packages/web-util/src/components/Header.tsx:226
msgid "Menu"
msgstr "Menü"
-#: packages/web-util/src/components/Header.tsx:254
+#: packages/web-util/src/components/Header.tsx:263
msgid "Sidebar"
msgstr "Seitenleiste"
-#: packages/web-util/src/components/Header.tsx:282
+#: packages/web-util/src/components/Header.tsx:291
msgid "Log out"
msgstr "Abmelden"
-#: packages/web-util/src/components/Header.tsx:295
+#: packages/web-util/src/components/Header.tsx:304
msgid "Sites"
msgstr "Websites"
-#: packages/web-util/src/components/Footer.tsx:46
+#: packages/web-util/src/components/Footer.tsx:53
msgid "Testing with %1$s"
msgstr "Test mit %1$s"
-#: packages/web-util/src/components/Footer.tsx:57
+#: packages/web-util/src/components/Footer.tsx:65
msgid "stop testing"
msgstr "Test beenden"
-#: packages/web-util/src/components/Footer.tsx:75
-#: packages/web-util/src/components/Footer.tsx:100
+#: packages/web-util/src/components/Footer.tsx:77
+#: packages/web-util/src/components/Footer.tsx:113
+#: packages/web-util/src/components/Footer.tsx:140
msgid "Learn more about %1$s"
msgstr "Mehr über %1$s erfahren"
@@ -285,33 +290,41 @@ msgstr "in %1$s"
msgid "%1$s ago"
msgstr "vor %1$s"
+#: packages/web-util/src/components/Pagination.tsx:25
+msgid "Pagination"
+msgstr "Seitennavigation"
+
#: packages/web-util/src/components/Pagination.tsx:31
+msgid "Page %1$s"
+msgstr "Seite %1$s"
+
+#: packages/web-util/src/components/Pagination.tsx:39
msgid "First page"
msgstr "Erste Seite"
-#: packages/web-util/src/components/Pagination.tsx:38
+#: packages/web-util/src/components/Pagination.tsx:46
msgid "Previous"
msgstr "Zurück"
-#: packages/web-util/src/components/Pagination.tsx:45
+#: packages/web-util/src/components/Pagination.tsx:53
msgid "Next"
msgstr "Weiter"
#: packages/web-util/src/context/bank-api.ts:147
-#: packages/web-util/src/context/challenger-api.ts:170
+#: packages/web-util/src/context/challenger-api.ts:196
#: packages/web-util/src/context/exchange-api.ts:173
msgid "Checking compatibility of this webapp with backend service..."
msgstr ""
"Kompatibilität dieser Webanwendung mit dem Backend-Dienst wird geprüft …"
#: packages/web-util/src/context/bank-api.ts:155
-#: packages/web-util/src/context/challenger-api.ts:179
+#: packages/web-util/src/context/challenger-api.ts:208
#: packages/web-util/src/context/exchange-api.ts:181
msgid "There was an error trying to contact the backend service."
msgstr "Beim Kontaktieren des Backend-Dienstes ist ein Fehler aufgetreten."
#: packages/web-util/src/context/bank-api.ts:164
-#: packages/web-util/src/context/challenger-api.ts:199
+#: packages/web-util/src/context/challenger-api.ts:230
#: packages/web-util/src/context/exchange-api.ts:187
msgid ""
"The server version is not supported. Supported version \"%1$s\", server "
@@ -320,14 +333,153 @@ msgstr ""
"Die Serverversion wird nicht unterstützt. Unterstützte Version „%1$s“, "
"Serverversion „%2$s“"
-#: packages/web-util/src/context/challenger-api.ts:187
+#: packages/web-util/src/context/challenger-api.ts:216
msgid "Retry"
msgstr "Erneut versuchen"
-#: packages/web-util/src/context/challenger-api.ts:200
+#: packages/web-util/src/context/challenger-api.ts:231
msgid "The server version is not supported. Supported version \"%1$s\"."
msgstr "Die Serverversion wird nicht unterstützt. Unterstützte Version „%1$s“."
+#: packages/web-util/src/forms/AcceptTosForm.tsx:39
+#, fuzzy
+#| msgid "Acceptance date"
+msgid "Acceptance status"
+msgstr "Datum der Annahme"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:42
+#, fuzzy
+#| msgid "Accepted via:"
+msgid "Accepted"
+msgstr "Angenommen über:"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:42
+#: packages/web-util/src/forms/AcceptTosForm.tsx:50
+#: packages/web-util/src/forms/AcceptTosForm.tsx:62
+msgid "Not recorded"
+msgstr ""
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:47
+#, fuzzy
+#| msgid "Terms of service"
+msgid "Accepted terms version"
+msgstr "Allgemeine Geschäftsbedingungen"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:55
+#, fuzzy
+#| msgid "The PDF could not be downloaded."
+msgid "Terms opened or downloaded"
+msgstr "Die PDF-Datei konnte nicht heruntergeladen werden."
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:59
+#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:100
+#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:101
+#: packages/web-util/src/forms/gana/personal-info.ts:35
+msgid "Yes"
+msgstr "Ja"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:61
+#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:104
+#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:105
+#: packages/web-util/src/forms/gana/personal-info.ts:39
+msgid "No"
+msgstr "Nein"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:68
+msgid "Provider"
+msgstr ""
+
+#. Translators: Button that retries loading the terms-of-service document.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:115
+msgid "Try again"
+msgstr "Erneut versuchen"
+
+#. Translators: Status shown while the terms-of-service PDF is downloading.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:117
+msgid "Downloading PDF…"
+msgstr "PDF wird heruntergeladen …"
+
+#. Translators: Button that downloads the terms-of-service document as a PDF.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:119
+msgid "Download PDF"
+msgstr "PDF herunterladen"
+
+#. Translators: Button that closes the terms reader. It does not accept the
+#. terms.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:122
+msgid "Done"
+msgstr "Fertig"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:199
+msgid "The terms are not available as Markdown or plain text."
+msgstr "Die Bedingungen sind weder als Markdown noch als Klartext verfügbar."
+
+#. Translators: “terms” means the terms-of-service document, not words or
+#. terminology.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:204
+#: packages/web-util/src/forms/AcceptTosForm.tsx:282
+msgid "These terms are too large to display safely."
+msgstr "Diese Bedingungen sind zu umfangreich, um sie sicher anzuzeigen."
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:207
+msgid "The terms of service could not be loaded."
+msgstr "Die Allgemeinen Geschäftsbedingungen konnten nicht geladen werden."
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:248
+msgid "Close terms of service"
+msgstr "Allgemeine Geschäftsbedingungen schließen"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:260
+msgid "Loading terms of service…"
+msgstr "Allgemeine Geschäftsbedingungen werden geladen …"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:311
+msgid "The PDF could not be downloaded."
+msgstr "Die PDF-Datei konnte nicht heruntergeladen werden."
+
+#. Translators: %1$s is the name of the organization or service provider
+#. whose terms the user must review.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:414
+msgid "Read the terms provided by %1$s before recording your acceptance."
+msgstr ""
+"Lesen Sie die von %1$s bereitgestellten Bedingungen, bevor Sie Ihre "
+"Zustimmung bestätigen."
+
+#. Translators: Button that reopens a terms-of-service document the user has
+#. already viewed.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:419
+msgid "Read terms again"
+msgstr "Bedingungen erneut lesen"
+
+#. Translators: Button that opens the terms-of-service document in an in-app
+#. reader.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:422
+msgid "Read terms"
+msgstr "Bedingungen lesen"
+
+#. Translators: The accepted version is the exact version of the
+#. terms-of-service document that was opened in the reader.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:425
+msgid "Your acceptance applies to the version shown above."
+msgstr "Ihre Zustimmung gilt für die oben angezeigte Version."
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:439
+msgid "Review the terms of service"
+msgstr "Allgemeine Geschäftsbedingungen prüfen"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:444
+msgid "Read the terms before recording your acceptance."
+msgstr "Lesen Sie die Bedingungen, bevor Sie Ihre Zustimmung bestätigen."
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:484
+msgid "I have read and accept the terms of service"
+msgstr ""
+"Ich habe die Allgemeinen Geschäftsbedingungen gelesen und akzeptiere sie"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:494
+msgid "Open the terms before accepting them."
+msgstr "Öffnen Sie die Bedingungen, bevor Sie sie akzeptieren."
+
#: packages/web-util/src/forms/gana/challenger_email.ts:29
msgid "Email verification"
msgstr "E-Mail-Verifizierung"
@@ -410,13 +562,14 @@ msgid "Supplemental Files"
msgstr "Zusätzliche Dokumente"
#: packages/web-util/src/forms/gana/generic_note.ts:67
+#: packages/web-util/src/forms/gana/multi_upload.ts:61
#: packages/web-util/src/forms/gana/VQF_902_14.ts:102
#: packages/web-util/src/forms/gana/VQF_902_1_officer.ts:165
msgid "Description"
msgstr "Beschreibung"
#: packages/web-util/src/forms/gana/generic_note.ts:73
-#: packages/web-util/src/forms/gana/multi_upload.ts:61
+#: packages/web-util/src/forms/gana/multi_upload.ts:97
#: packages/web-util/src/forms/gana/VQF_902_14.ts:108
#: packages/web-util/src/forms/gana/VQF_902_1_officer.ts:171
#: packages/web-util/src/forms/gana/generic_upload.ts:43
@@ -431,7 +584,27 @@ msgstr "Mehrere Dokumente hochladen"
msgid "Upload multiple documents."
msgstr "Mehrere Dokumente hochladen."
-#: packages/web-util/src/forms/gana/multi_upload.ts:56
+#: packages/web-util/src/forms/gana/multi_upload.ts:43
+#, fuzzy
+#| msgid "Gathered/Consulted documents"
+msgid "Requested documents"
+msgstr "Eingeholte/konsultierte Dokumente"
+
+#: packages/web-util/src/forms/gana/multi_upload.ts:49
+msgid "Document identifier"
+msgstr ""
+
+#: packages/web-util/src/forms/gana/multi_upload.ts:55
+msgid "Title"
+msgstr ""
+
+#: packages/web-util/src/forms/gana/multi_upload.ts:67
+#, fuzzy
+#| msgid "required"
+msgid "Required"
+msgstr "erforderlich"
+
+#: packages/web-util/src/forms/gana/multi_upload.ts:92
#: packages/web-util/src/forms/gana/generic_upload.ts:38
msgid "Document upload (%1$s)"
msgstr "Dokument-Upload (%1$s)"
@@ -507,8 +680,8 @@ msgstr "Feststellung des Kontrollinhabers (durch den Kunden eingereicht)"
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:30
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:31
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:30
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:28
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:31
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:29
msgid "Contracting partner"
msgstr "Vertragspartner"
@@ -575,8 +748,8 @@ msgstr ""
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:68
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:69
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:46
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:44
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:47
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:45
msgid "Can't be empty"
msgstr "Darf nicht leer sein"
@@ -584,8 +757,8 @@ msgstr "Darf nicht leer sein"
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:77
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:108
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:288
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:54
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:52
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:55
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:53
msgid "Full name"
msgstr "Vollständiger Name"
@@ -608,33 +781,21 @@ msgstr ""
"Ist eine Drittperson an den auf dem Konto/Depot liegenden Vermögenswerten "
"wirtschaftlich berechtigt?"
-#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:100
-#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:101
-#: packages/web-util/src/forms/gana/personal-info.ts:35
-msgid "Yes"
-msgstr "Ja"
-
-#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:104
-#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:105
-#: packages/web-util/src/forms/gana/personal-info.ts:39
-msgid "No"
-msgstr "Nein"
-
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:112
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:121
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:113
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:125
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:481
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:490
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:104
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:113
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:105
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:114
msgid "Signature(s)"
msgstr "Unterschrift(en)"
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:113
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:114
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:482
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:105
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:106
msgid ""
"It is a criminal offence to deliberately provide false information on this "
"form (article 251 of the Swiss Criminal Code, document forgery)"
@@ -646,7 +807,7 @@ msgstr ""
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:117
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:121
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:486
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:109
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:110
msgid ""
"The contracting partner hereby undertakes to inform automatically of any "
"changes to the information contained herein."
@@ -657,7 +818,7 @@ msgstr ""
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:127
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:131
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:496
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:119
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:120
msgid "Date"
msgstr "Datum"
@@ -667,17 +828,17 @@ msgstr ""
"Feststellung des Kontrollinhabers (durch den AML-Beauftragten eingereicht)"
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:142
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:102
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:103
msgid "Signed Declaration"
msgstr "Unterzeichnete Erklärung"
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:143
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:103
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:104
msgid "Signed declaration by the customer"
msgstr "Vom Kunden unterzeichnete Erklärung"
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:150
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:107
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:108
msgid ""
"The uploaded document must contain the customer's signature on the "
"beneficial owner declaration."
@@ -686,7 +847,7 @@ msgstr ""
"zum wirtschaftlich Berechtigten enthalten."
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:154
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:111
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:112
msgid "Signed Document"
msgstr "Unterzeichnetes Dokument"
@@ -781,8 +942,8 @@ msgstr "E-Mail"
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:132
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:300
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:66
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:64
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:67
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:65
msgid "Date of birth"
msgstr "Geburtsdatum"
@@ -792,8 +953,8 @@ msgstr "Geburtsdatum"
#: packages/web-util/src/forms/gana/VQF_902_4.ts:102
#: packages/web-util/src/forms/gana/VQF_902_4.ts:159
#: packages/web-util/src/forms/gana/VQF_902_4.ts:398
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:75
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:73
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:76
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:74
msgid "invalid format"
msgstr "ungültiges Format"
@@ -803,8 +964,8 @@ msgstr "ungültiges Format"
#: packages/web-util/src/forms/gana/VQF_902_4.ts:105
#: packages/web-util/src/forms/gana/VQF_902_4.ts:162
#: packages/web-util/src/forms/gana/VQF_902_4.ts:401
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:78
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:76
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:79
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:77
msgid "it can't be in the future"
msgstr "darf nicht in der Zukunft liegen"
@@ -814,15 +975,15 @@ msgstr "darf nicht in der Zukunft liegen"
#: packages/web-util/src/forms/gana/VQF_902_4.ts:112
#: packages/web-util/src/forms/gana/VQF_902_4.ts:169
#: packages/web-util/src/forms/gana/VQF_902_4.ts:408
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:85
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:83
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:86
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:84
msgid "it can't be greater than 120 years"
msgstr "darf nicht größer als 120 Jahre sein"
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:159
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:327
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:92
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:90
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:93
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:91
msgid "Nationality"
msgstr "Staatsangehörigkeit"
@@ -1674,27 +1835,32 @@ msgid "Other relevant information"
msgstr "Weitere relevante Angaben"
#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:10
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:10
-msgid "Declaration of identity of the beneficial owner (A)"
+#, fuzzy
+#| msgid "Declaration of identity of the beneficial owner (A)"
+msgid "Declaration of identity of the beneficial owner (A) — customer"
msgstr "Feststellung des wirtschaftlich Berechtigten (A)"
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:23
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:21
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:11
+msgid "The customer completes the declaration directly in the form."
+msgstr ""
+
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:24
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:22
msgid "Declaration of identity of the beneficial owner"
msgstr "Feststellung des wirtschaftlich Berechtigten"
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:37
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:35
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:38
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:36
msgid "Beneficial owner details"
msgstr "Angaben zum wirtschaftlich Berechtigten"
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:41
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:39
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:42
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:40
msgid "Beneficial owner(s)"
msgstr "Wirtschaftlich Berechtigte(r)"
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:42
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:40
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:43
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:41
msgid ""
"The person(s) listed below is/are the beneficial owner(s) of the assets "
"involved in the business relationship. If the contracting partner is also "
@@ -1706,11 +1872,23 @@ msgstr ""
"Ist der Vertragspartner selber allein an diesen Vermögenswerten "
"wirtschaftlich berechtigt, so sind nachstehend seine Personalien festzuhalten"
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:60
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:58
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:61
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:59
msgid "Domicile address"
msgstr "Sitzadresse"
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:10
+#, fuzzy
+#| msgid "Declaration of identity of the beneficial owner (A)"
+msgid "Declaration of identity of the beneficial owner (A) — AML officer"
+msgstr "Feststellung des wirtschaftlich Berechtigten (A)"
+
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:11
+msgid ""
+"The AML officer records the declaration and uploads the customer's signed "
+"PDF."
+msgstr ""
+
#: packages/web-util/src/forms/Calendar.tsx:56
msgid "January"
msgstr "Januar"
@@ -1775,107 +1953,16 @@ msgstr "Vorheriger Monat"
msgid "Next month"
msgstr "Nächster Monat"
-#. Translators: Button that retries loading the terms-of-service document.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:56
-msgid "Try again"
-msgstr "Erneut versuchen"
-
-#. Translators: Status shown while the terms-of-service PDF is downloading.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:58
-msgid "Downloading PDF…"
-msgstr "PDF wird heruntergeladen …"
-
-#. Translators: Button that downloads the terms-of-service document as a PDF.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:60
-msgid "Download PDF"
-msgstr "PDF herunterladen"
-
-#. Translators: Button that closes the terms reader. It does not accept the
-#. terms.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:63
-msgid "Done"
-msgstr "Fertig"
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:140
-msgid "The terms are not available as Markdown or plain text."
-msgstr "Die Bedingungen sind weder als Markdown noch als Klartext verfügbar."
-
-#. Translators: “terms” means the terms-of-service document, not words or
-#. terminology.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:145
-#: packages/web-util/src/forms/AcceptTosForm.tsx:223
-msgid "These terms are too large to display safely."
-msgstr "Diese Bedingungen sind zu umfangreich, um sie sicher anzuzeigen."
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:148
-msgid "The terms of service could not be loaded."
-msgstr "Die Allgemeinen Geschäftsbedingungen konnten nicht geladen werden."
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:189
-msgid "Close terms of service"
-msgstr "Allgemeine Geschäftsbedingungen schließen"
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:201
-msgid "Loading terms of service…"
-msgstr "Allgemeine Geschäftsbedingungen werden geladen …"
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:252
-msgid "The PDF could not be downloaded."
-msgstr "Die PDF-Datei konnte nicht heruntergeladen werden."
-
-#. Translators: %1$s is the name of the organization or service provider
-#. whose terms the user must review.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:355
-msgid "Read the terms provided by %1$s before recording your acceptance."
-msgstr ""
-"Lesen Sie die von %1$s bereitgestellten Bedingungen, bevor Sie Ihre "
-"Zustimmung bestätigen."
-
-#. Translators: Button that reopens a terms-of-service document the user has
-#. already viewed.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:360
-msgid "Read terms again"
-msgstr "Bedingungen erneut lesen"
-
-#. Translators: Button that opens the terms-of-service document in an in-app
-#. reader.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:363
-msgid "Read terms"
-msgstr "Bedingungen lesen"
-
-#. Translators: The accepted version is the exact version of the
-#. terms-of-service document that was opened in the reader.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:366
-msgid "Your acceptance applies to the version shown above."
-msgstr "Ihre Zustimmung gilt für die oben angezeigte Version."
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:380
-msgid "Review the terms of service"
-msgstr "Allgemeine Geschäftsbedingungen prüfen"
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:385
-msgid "Read the terms before recording your acceptance."
-msgstr "Lesen Sie die Bedingungen, bevor Sie Ihre Zustimmung bestätigen."
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:425
-msgid "I have read and accept the terms of service"
-msgstr ""
-"Ich habe die Allgemeinen Geschäftsbedingungen gelesen und akzeptiere sie"
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:435
-msgid "Open the terms before accepting them."
-msgstr "Öffnen Sie die Bedingungen, bevor Sie sie akzeptieren."
-
-#: packages/web-util/src/forms/fields/InputSelectOne.tsx:82
+#: packages/web-util/src/forms/fields/InputSelectOne.tsx:85
msgid "Clear selection"
msgstr "Auswahl löschen"
-#: packages/web-util/src/forms/fields/InputSelectOne.tsx:170
+#: packages/web-util/src/forms/fields/InputSelectOne.tsx:173
msgid "Toggle choices"
msgstr "Auswahlmöglichkeiten anzeigen"
-#: packages/web-util/src/forms/fields/InputSelectOne.tsx:193
-#: packages/web-util/src/forms/fields/InputSelectMultiple.tsx:132
+#: packages/web-util/src/forms/fields/InputSelectOne.tsx:201
+#: packages/web-util/src/forms/fields/InputSelectMultiple.tsx:133
msgid "No element found"
msgstr "Kein Element gefunden"
@@ -1904,10 +1991,13 @@ msgid "seconds"
msgstr "Sekunden"
#: packages/web-util/src/forms/fields/InputDuration.tsx:339
-#: packages/web-util/src/forms/fields/InputDurationText.tsx:94
msgid "No expiration"
msgstr "Keine Ablaufzeit"
+#: packages/web-util/src/forms/fields/InputDurationText.tsx:94
+msgid "Forever"
+msgstr "Für immer"
+
#: packages/web-util/src/forms/fields/InputFile.tsx:46
msgid "The selected file is too large."
msgstr "Die ausgewählte Datei ist zu groß."
@@ -1916,23 +2006,23 @@ msgstr "Die ausgewählte Datei ist zu groß."
msgid "The selected file could not be read."
msgstr "Die ausgewählte Datei konnte nicht gelesen werden."
-#: packages/web-util/src/forms/fields/InputFile.tsx:99
+#: packages/web-util/src/forms/fields/InputFile.tsx:100
msgid "Upload a file"
msgstr "Eine Datei hochladen"
-#: packages/web-util/src/forms/fields/InputFile.tsx:153
+#: packages/web-util/src/forms/fields/InputFile.tsx:154
msgid "Clear"
msgstr "Leeren"
-#: packages/web-util/src/forms/fields/InputFile.tsx:162
+#: packages/web-util/src/forms/fields/InputFile.tsx:163
msgid "Download a copy."
msgstr "Eine Kopie herunterladen."
-#: packages/web-util/src/forms/fields/InputSelectMultiple.tsx:193
+#: packages/web-util/src/forms/fields/InputSelectMultiple.tsx:194
msgid "Remove"
msgstr "Entfernen"
-#: packages/web-util/src/forms/forms-ui.tsx:344
+#: packages/web-util/src/forms/forms-ui.tsx:357
msgid "List of fields with errors"
msgstr "Liste der Felder mit Fehlern"
@@ -1957,7 +2047,7 @@ msgid "Delete"
msgstr "Löschen"
#: packages/web-util/src/forms/fields/InputArray.tsx:129
-#: packages/web-util/src/forms/fields/InputArray.tsx:315
+#: packages/web-util/src/forms/fields/InputArray.tsx:316
msgid "Add item"
msgstr "Eintrag hinzufügen"
@@ -1970,19 +2060,37 @@ msgstr "Änderungen speichern"
msgid "Item %1$s"
msgstr "Eintrag %1$s"
-#: packages/web-util/src/forms/fields/InputArray.tsx:282
+#: packages/web-util/src/forms/fields/InputArray.tsx:283
msgid "Edit %1$s"
msgstr "%1$s bearbeiten"
-#: packages/web-util/src/forms/fields/InputArray.tsx:289
+#: packages/web-util/src/forms/fields/InputArray.tsx:290
msgid "Edit"
msgstr "Bearbeiten"
-#: packages/web-util/src/forms/index.ts:83
+#: packages/web-util/src/forms/index.ts:84
msgid "Simple comment"
msgstr "Einfacher Kommentar"
-#: packages/web-util/src/forms/index.ts:95
+#: packages/web-util/src/forms/index.ts:101
+msgid "Terms URL"
+msgstr ""
+
+#: packages/web-util/src/forms/index.ts:107
+#, fuzzy
+#| msgid "Terms of service"
+msgid "Terms version"
+msgstr "Allgemeine Geschäftsbedingungen"
+
+#: packages/web-util/src/forms/index.ts:113
+msgid "Provider name"
+msgstr ""
+
+#: packages/web-util/src/forms/index.ts:118
+msgid "Only show the external link"
+msgstr ""
+
+#: packages/web-util/src/forms/index.ts:124
msgid "Name and birthdate"
msgstr "Name und Geburtsdatum"
diff --git a/packages/web-util/src/i18n/es.po b/packages/web-util/src/i18n/es.po
@@ -35,8 +35,8 @@ msgstr ""
"La validación falló inesperadamente. Contacte a los desarrolladores: %1$s"
#: packages/web-util/src/hooks/useForm.ts:436
-#: packages/web-util/src/forms/AcceptTosForm.tsx:177
-#: packages/web-util/src/forms/index.ts:89
+#: packages/web-util/src/forms/AcceptTosForm.tsx:236
+#: packages/web-util/src/forms/index.ts:90
msgid "Terms of service"
msgstr "Términos de servicio"
@@ -192,6 +192,10 @@ msgstr "Descartar notificación"
msgid "Copy this text manually:"
msgstr "Copie este texto manualmente:"
+#: packages/web-util/src/components/ErrorLoading.tsx:62
+msgid "Technical details"
+msgstr "Detalles técnicos"
+
#: packages/web-util/src/components/LangSelector.tsx:87
#: packages/web-util/src/components/LangSelector.tsx:125
#: packages/web-util/src/components/LangSelector.tsx:149
@@ -207,49 +211,50 @@ msgstr "Idiomas"
msgid "Loading"
msgstr "Cargando"
-#: packages/web-util/src/components/Header.tsx:92
+#: packages/web-util/src/components/Header.tsx:100
msgid "Show notifications"
msgstr "Mostrar notificaciones"
-#: packages/web-util/src/components/Header.tsx:136
+#: packages/web-util/src/components/Header.tsx:144
msgid "Open profile"
msgstr "Abrir perfil"
-#: packages/web-util/src/components/Header.tsx:168
+#: packages/web-util/src/components/Header.tsx:177
msgid "Open settings"
msgstr "Abrir configuración"
-#: packages/web-util/src/components/Header.tsx:202
-#: packages/web-util/src/components/Header.tsx:231
+#: packages/web-util/src/components/Header.tsx:211
+#: packages/web-util/src/components/Header.tsx:240
msgid "Close panel"
msgstr "Cerrar panel"
-#: packages/web-util/src/components/Header.tsx:217
+#: packages/web-util/src/components/Header.tsx:226
msgid "Menu"
msgstr "Menú"
-#: packages/web-util/src/components/Header.tsx:254
+#: packages/web-util/src/components/Header.tsx:263
msgid "Sidebar"
msgstr "Barra lateral"
-#: packages/web-util/src/components/Header.tsx:282
+#: packages/web-util/src/components/Header.tsx:291
msgid "Log out"
msgstr "Cerrar sesión"
-#: packages/web-util/src/components/Header.tsx:295
+#: packages/web-util/src/components/Header.tsx:304
msgid "Sites"
msgstr "Sitios"
-#: packages/web-util/src/components/Footer.tsx:46
+#: packages/web-util/src/components/Footer.tsx:53
msgid "Testing with %1$s"
msgstr "Prueba con %1$s"
-#: packages/web-util/src/components/Footer.tsx:57
+#: packages/web-util/src/components/Footer.tsx:65
msgid "stop testing"
msgstr "finalizar la prueba"
-#: packages/web-util/src/components/Footer.tsx:75
-#: packages/web-util/src/components/Footer.tsx:100
+#: packages/web-util/src/components/Footer.tsx:77
+#: packages/web-util/src/components/Footer.tsx:113
+#: packages/web-util/src/components/Footer.tsx:140
msgid "Learn more about %1$s"
msgstr "Más información sobre %1$s"
@@ -277,20 +282,28 @@ msgstr "en %1$s"
msgid "%1$s ago"
msgstr "hace %1$s"
+#: packages/web-util/src/components/Pagination.tsx:25
+msgid "Pagination"
+msgstr "Paginación"
+
#: packages/web-util/src/components/Pagination.tsx:31
+msgid "Page %1$s"
+msgstr "Página %1$s"
+
+#: packages/web-util/src/components/Pagination.tsx:39
msgid "First page"
msgstr "Primera página"
-#: packages/web-util/src/components/Pagination.tsx:38
+#: packages/web-util/src/components/Pagination.tsx:46
msgid "Previous"
msgstr "Anterior"
-#: packages/web-util/src/components/Pagination.tsx:45
+#: packages/web-util/src/components/Pagination.tsx:53
msgid "Next"
msgstr "Siguiente"
#: packages/web-util/src/context/bank-api.ts:147
-#: packages/web-util/src/context/challenger-api.ts:170
+#: packages/web-util/src/context/challenger-api.ts:196
#: packages/web-util/src/context/exchange-api.ts:173
msgid "Checking compatibility of this webapp with backend service..."
msgstr ""
@@ -298,13 +311,13 @@ msgstr ""
"backend..."
#: packages/web-util/src/context/bank-api.ts:155
-#: packages/web-util/src/context/challenger-api.ts:179
+#: packages/web-util/src/context/challenger-api.ts:208
#: packages/web-util/src/context/exchange-api.ts:181
msgid "There was an error trying to contact the backend service."
msgstr "Se produjo un error al intentar contactar con el servicio backend."
#: packages/web-util/src/context/bank-api.ts:164
-#: packages/web-util/src/context/challenger-api.ts:199
+#: packages/web-util/src/context/challenger-api.ts:230
#: packages/web-util/src/context/exchange-api.ts:187
msgid ""
"The server version is not supported. Supported version \"%1$s\", server "
@@ -313,15 +326,152 @@ msgstr ""
"La versión del servidor no es compatible. Versión compatible \"%1$s\", "
"versión del servidor \"%2$s\""
-#: packages/web-util/src/context/challenger-api.ts:187
+#: packages/web-util/src/context/challenger-api.ts:216
msgid "Retry"
msgstr "Reintentar"
-#: packages/web-util/src/context/challenger-api.ts:200
+#: packages/web-util/src/context/challenger-api.ts:231
msgid "The server version is not supported. Supported version \"%1$s\"."
msgstr ""
"La versión del servidor no es compatible. Versión compatible: \"%1$s\"."
+#: packages/web-util/src/forms/AcceptTosForm.tsx:39
+#, fuzzy
+#| msgid "Acceptance date"
+msgid "Acceptance status"
+msgstr "Fecha de aceptación"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:42
+#, fuzzy
+#| msgid "Accepted via:"
+msgid "Accepted"
+msgstr "Aceptado mediante:"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:42
+#: packages/web-util/src/forms/AcceptTosForm.tsx:50
+#: packages/web-util/src/forms/AcceptTosForm.tsx:62
+msgid "Not recorded"
+msgstr ""
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:47
+#, fuzzy
+#| msgid "Terms of service"
+msgid "Accepted terms version"
+msgstr "Términos de servicio"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:55
+#, fuzzy
+#| msgid "The PDF could not be downloaded."
+msgid "Terms opened or downloaded"
+msgstr "No se pudo descargar el PDF."
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:59
+#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:100
+#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:101
+#: packages/web-util/src/forms/gana/personal-info.ts:35
+msgid "Yes"
+msgstr "Sí"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:61
+#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:104
+#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:105
+#: packages/web-util/src/forms/gana/personal-info.ts:39
+msgid "No"
+msgstr "No"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:68
+msgid "Provider"
+msgstr ""
+
+#. Translators: Button that retries loading the terms-of-service document.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:115
+msgid "Try again"
+msgstr "Intentar de nuevo"
+
+#. Translators: Status shown while the terms-of-service PDF is downloading.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:117
+msgid "Downloading PDF…"
+msgstr "Descargando el PDF…"
+
+#. Translators: Button that downloads the terms-of-service document as a PDF.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:119
+msgid "Download PDF"
+msgstr "Descargar PDF"
+
+#. Translators: Button that closes the terms reader. It does not accept the
+#. terms.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:122
+msgid "Done"
+msgstr "Listo"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:199
+msgid "The terms are not available as Markdown or plain text."
+msgstr "Los términos no están disponibles en Markdown ni en texto sin formato."
+
+#. Translators: “terms” means the terms-of-service document, not words or
+#. terminology.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:204
+#: packages/web-util/src/forms/AcceptTosForm.tsx:282
+msgid "These terms are too large to display safely."
+msgstr "Estos términos son demasiado grandes para mostrarlos de forma segura."
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:207
+msgid "The terms of service could not be loaded."
+msgstr "No se pudieron cargar los términos de servicio."
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:248
+msgid "Close terms of service"
+msgstr "Cerrar los términos de servicio"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:260
+msgid "Loading terms of service…"
+msgstr "Cargando los términos de servicio…"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:311
+msgid "The PDF could not be downloaded."
+msgstr "No se pudo descargar el PDF."
+
+#. Translators: %1$s is the name of the organization or service provider
+#. whose terms the user must review.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:414
+msgid "Read the terms provided by %1$s before recording your acceptance."
+msgstr ""
+"Lea los términos proporcionados por %1$s antes de registrar su aceptación."
+
+#. Translators: Button that reopens a terms-of-service document the user has
+#. already viewed.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:419
+msgid "Read terms again"
+msgstr "Volver a leer los términos"
+
+#. Translators: Button that opens the terms-of-service document in an in-app
+#. reader.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:422
+msgid "Read terms"
+msgstr "Leer los términos"
+
+#. Translators: The accepted version is the exact version of the
+#. terms-of-service document that was opened in the reader.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:425
+msgid "Your acceptance applies to the version shown above."
+msgstr "Su aceptación se aplica a la versión mostrada arriba."
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:439
+msgid "Review the terms of service"
+msgstr "Revisar los términos de servicio"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:444
+msgid "Read the terms before recording your acceptance."
+msgstr "Lea los términos antes de registrar su aceptación."
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:484
+msgid "I have read and accept the terms of service"
+msgstr "He leído y acepto los términos de servicio"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:494
+msgid "Open the terms before accepting them."
+msgstr "Abra los términos antes de aceptarlos."
+
#: packages/web-util/src/forms/gana/challenger_email.ts:29
msgid "Email verification"
msgstr "Verificación del correo electrónico"
@@ -404,13 +554,14 @@ msgid "Supplemental Files"
msgstr "Archivos adicionales"
#: packages/web-util/src/forms/gana/generic_note.ts:67
+#: packages/web-util/src/forms/gana/multi_upload.ts:61
#: packages/web-util/src/forms/gana/VQF_902_14.ts:102
#: packages/web-util/src/forms/gana/VQF_902_1_officer.ts:165
msgid "Description"
msgstr "Descripción"
#: packages/web-util/src/forms/gana/generic_note.ts:73
-#: packages/web-util/src/forms/gana/multi_upload.ts:61
+#: packages/web-util/src/forms/gana/multi_upload.ts:97
#: packages/web-util/src/forms/gana/VQF_902_14.ts:108
#: packages/web-util/src/forms/gana/VQF_902_1_officer.ts:171
#: packages/web-util/src/forms/gana/generic_upload.ts:43
@@ -425,7 +576,27 @@ msgstr "Subir varios documentos"
msgid "Upload multiple documents."
msgstr "Sube varios documentos."
-#: packages/web-util/src/forms/gana/multi_upload.ts:56
+#: packages/web-util/src/forms/gana/multi_upload.ts:43
+#, fuzzy
+#| msgid "Gathered/Consulted documents"
+msgid "Requested documents"
+msgstr "Documentos recopilados/consultados"
+
+#: packages/web-util/src/forms/gana/multi_upload.ts:49
+msgid "Document identifier"
+msgstr ""
+
+#: packages/web-util/src/forms/gana/multi_upload.ts:55
+msgid "Title"
+msgstr ""
+
+#: packages/web-util/src/forms/gana/multi_upload.ts:67
+#, fuzzy
+#| msgid "required"
+msgid "Required"
+msgstr "obligatorio"
+
+#: packages/web-util/src/forms/gana/multi_upload.ts:92
#: packages/web-util/src/forms/gana/generic_upload.ts:38
msgid "Document upload (%1$s)"
msgstr "Carga de documentos (%1$s)"
@@ -502,8 +673,8 @@ msgstr ""
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:30
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:31
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:30
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:28
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:31
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:29
msgid "Contracting partner"
msgstr "Parte contratante"
@@ -571,8 +742,8 @@ msgstr ""
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:68
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:69
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:46
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:44
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:47
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:45
msgid "Can't be empty"
msgstr "No puede estar vacío"
@@ -580,8 +751,8 @@ msgstr "No puede estar vacío"
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:77
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:108
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:288
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:54
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:52
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:55
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:53
msgid "Full name"
msgstr "Nombre completo"
@@ -604,33 +775,21 @@ msgstr ""
"¿Es un tercero el beneficiario efectivo de los activos mantenidos en la "
"cuenta/cuenta de valores?"
-#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:100
-#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:101
-#: packages/web-util/src/forms/gana/personal-info.ts:35
-msgid "Yes"
-msgstr "Sí"
-
-#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:104
-#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:105
-#: packages/web-util/src/forms/gana/personal-info.ts:39
-msgid "No"
-msgstr "No"
-
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:112
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:121
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:113
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:125
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:481
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:490
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:104
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:113
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:105
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:114
msgid "Signature(s)"
msgstr "Firma(s)"
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:113
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:114
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:482
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:105
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:106
msgid ""
"It is a criminal offence to deliberately provide false information on this "
"form (article 251 of the Swiss Criminal Code, document forgery)"
@@ -642,7 +801,7 @@ msgstr ""
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:117
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:121
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:486
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:109
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:110
msgid ""
"The contracting partner hereby undertakes to inform automatically of any "
"changes to the information contained herein."
@@ -653,7 +812,7 @@ msgstr ""
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:127
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:131
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:496
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:119
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:120
msgid "Date"
msgstr "Fecha"
@@ -664,17 +823,17 @@ msgstr ""
"de prevención de blanqueo de capitales)"
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:142
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:102
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:103
msgid "Signed Declaration"
msgstr "Declaración firmada"
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:143
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:103
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:104
msgid "Signed declaration by the customer"
msgstr "Declaración firmada por el cliente"
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:150
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:107
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:108
msgid ""
"The uploaded document must contain the customer's signature on the "
"beneficial owner declaration."
@@ -683,7 +842,7 @@ msgstr ""
"del beneficiario efectivo."
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:154
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:111
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:112
msgid "Signed Document"
msgstr "Documento firmado"
@@ -778,8 +937,8 @@ msgstr "Correo electrónico"
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:132
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:300
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:66
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:64
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:67
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:65
msgid "Date of birth"
msgstr "Fecha de nacimiento"
@@ -789,8 +948,8 @@ msgstr "Fecha de nacimiento"
#: packages/web-util/src/forms/gana/VQF_902_4.ts:102
#: packages/web-util/src/forms/gana/VQF_902_4.ts:159
#: packages/web-util/src/forms/gana/VQF_902_4.ts:398
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:75
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:73
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:76
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:74
msgid "invalid format"
msgstr "formato inválido"
@@ -800,8 +959,8 @@ msgstr "formato inválido"
#: packages/web-util/src/forms/gana/VQF_902_4.ts:105
#: packages/web-util/src/forms/gana/VQF_902_4.ts:162
#: packages/web-util/src/forms/gana/VQF_902_4.ts:401
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:78
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:76
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:79
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:77
msgid "it can't be in the future"
msgstr "no puede estar en el futuro"
@@ -811,15 +970,15 @@ msgstr "no puede estar en el futuro"
#: packages/web-util/src/forms/gana/VQF_902_4.ts:112
#: packages/web-util/src/forms/gana/VQF_902_4.ts:169
#: packages/web-util/src/forms/gana/VQF_902_4.ts:408
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:85
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:83
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:86
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:84
msgid "it can't be greater than 120 years"
msgstr "no puede ser mayor a 120 años"
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:159
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:327
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:92
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:90
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:93
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:91
msgid "Nationality"
msgstr "Nacionalidad"
@@ -1669,27 +1828,32 @@ msgid "Other relevant information"
msgstr "Otra información relevante"
#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:10
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:10
-msgid "Declaration of identity of the beneficial owner (A)"
+#, fuzzy
+#| msgid "Declaration of identity of the beneficial owner (A)"
+msgid "Declaration of identity of the beneficial owner (A) — customer"
msgstr "Declaración de identidad del beneficiario efectivo (A)"
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:23
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:21
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:11
+msgid "The customer completes the declaration directly in the form."
+msgstr ""
+
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:24
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:22
msgid "Declaration of identity of the beneficial owner"
msgstr "Declaración de identidad del beneficiario efectivo"
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:37
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:35
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:38
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:36
msgid "Beneficial owner details"
msgstr "Datos del beneficiario efectivo"
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:41
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:39
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:42
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:40
msgid "Beneficial owner(s)"
msgstr "Beneficiario(s) efectivo(s)"
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:42
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:40
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:43
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:41
msgid ""
"The person(s) listed below is/are the beneficial owner(s) of the assets "
"involved in the business relationship. If the contracting partner is also "
@@ -1701,11 +1865,23 @@ msgstr ""
"contraparte contractual es también el único beneficiario efectivo de los "
"activos, sus datos deben indicarse a continuación"
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:60
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:58
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:61
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:59
msgid "Domicile address"
msgstr "Dirección de domicilio"
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:10
+#, fuzzy
+#| msgid "Declaration of identity of the beneficial owner (A)"
+msgid "Declaration of identity of the beneficial owner (A) — AML officer"
+msgstr "Declaración de identidad del beneficiario efectivo (A)"
+
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:11
+msgid ""
+"The AML officer records the declaration and uploads the customer's signed "
+"PDF."
+msgstr ""
+
#: packages/web-util/src/forms/Calendar.tsx:56
msgid "January"
msgstr "Enero"
@@ -1770,105 +1946,16 @@ msgstr "Mes anterior"
msgid "Next month"
msgstr "Mes siguiente"
-#. Translators: Button that retries loading the terms-of-service document.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:56
-msgid "Try again"
-msgstr "Intentar de nuevo"
-
-#. Translators: Status shown while the terms-of-service PDF is downloading.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:58
-msgid "Downloading PDF…"
-msgstr "Descargando el PDF…"
-
-#. Translators: Button that downloads the terms-of-service document as a PDF.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:60
-msgid "Download PDF"
-msgstr "Descargar PDF"
-
-#. Translators: Button that closes the terms reader. It does not accept the
-#. terms.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:63
-msgid "Done"
-msgstr "Listo"
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:140
-msgid "The terms are not available as Markdown or plain text."
-msgstr "Los términos no están disponibles en Markdown ni en texto sin formato."
-
-#. Translators: “terms” means the terms-of-service document, not words or
-#. terminology.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:145
-#: packages/web-util/src/forms/AcceptTosForm.tsx:223
-msgid "These terms are too large to display safely."
-msgstr "Estos términos son demasiado grandes para mostrarlos de forma segura."
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:148
-msgid "The terms of service could not be loaded."
-msgstr "No se pudieron cargar los términos de servicio."
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:189
-msgid "Close terms of service"
-msgstr "Cerrar los términos de servicio"
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:201
-msgid "Loading terms of service…"
-msgstr "Cargando los términos de servicio…"
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:252
-msgid "The PDF could not be downloaded."
-msgstr "No se pudo descargar el PDF."
-
-#. Translators: %1$s is the name of the organization or service provider
-#. whose terms the user must review.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:355
-msgid "Read the terms provided by %1$s before recording your acceptance."
-msgstr ""
-"Lea los términos proporcionados por %1$s antes de registrar su aceptación."
-
-#. Translators: Button that reopens a terms-of-service document the user has
-#. already viewed.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:360
-msgid "Read terms again"
-msgstr "Volver a leer los términos"
-
-#. Translators: Button that opens the terms-of-service document in an in-app
-#. reader.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:363
-msgid "Read terms"
-msgstr "Leer los términos"
-
-#. Translators: The accepted version is the exact version of the
-#. terms-of-service document that was opened in the reader.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:366
-msgid "Your acceptance applies to the version shown above."
-msgstr "Su aceptación se aplica a la versión mostrada arriba."
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:380
-msgid "Review the terms of service"
-msgstr "Revisar los términos de servicio"
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:385
-msgid "Read the terms before recording your acceptance."
-msgstr "Lea los términos antes de registrar su aceptación."
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:425
-msgid "I have read and accept the terms of service"
-msgstr "He leído y acepto los términos de servicio"
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:435
-msgid "Open the terms before accepting them."
-msgstr "Abra los términos antes de aceptarlos."
-
-#: packages/web-util/src/forms/fields/InputSelectOne.tsx:82
+#: packages/web-util/src/forms/fields/InputSelectOne.tsx:85
msgid "Clear selection"
msgstr "Borrar selección"
-#: packages/web-util/src/forms/fields/InputSelectOne.tsx:170
+#: packages/web-util/src/forms/fields/InputSelectOne.tsx:173
msgid "Toggle choices"
msgstr "Mostrar opciones"
-#: packages/web-util/src/forms/fields/InputSelectOne.tsx:193
-#: packages/web-util/src/forms/fields/InputSelectMultiple.tsx:132
+#: packages/web-util/src/forms/fields/InputSelectOne.tsx:201
+#: packages/web-util/src/forms/fields/InputSelectMultiple.tsx:133
msgid "No element found"
msgstr "No se encontró ningún elemento"
@@ -1897,10 +1984,13 @@ msgid "seconds"
msgstr "segundos"
#: packages/web-util/src/forms/fields/InputDuration.tsx:339
-#: packages/web-util/src/forms/fields/InputDurationText.tsx:94
msgid "No expiration"
msgstr "Sin vencimiento"
+#: packages/web-util/src/forms/fields/InputDurationText.tsx:94
+msgid "Forever"
+msgstr "Para siempre"
+
#: packages/web-util/src/forms/fields/InputFile.tsx:46
msgid "The selected file is too large."
msgstr "El archivo seleccionado es demasiado grande."
@@ -1909,23 +1999,23 @@ msgstr "El archivo seleccionado es demasiado grande."
msgid "The selected file could not be read."
msgstr "No se pudo leer el archivo seleccionado."
-#: packages/web-util/src/forms/fields/InputFile.tsx:99
+#: packages/web-util/src/forms/fields/InputFile.tsx:100
msgid "Upload a file"
msgstr "Subir un archivo"
-#: packages/web-util/src/forms/fields/InputFile.tsx:153
+#: packages/web-util/src/forms/fields/InputFile.tsx:154
msgid "Clear"
msgstr "Borrar"
-#: packages/web-util/src/forms/fields/InputFile.tsx:162
+#: packages/web-util/src/forms/fields/InputFile.tsx:163
msgid "Download a copy."
msgstr "Descargar una copia."
-#: packages/web-util/src/forms/fields/InputSelectMultiple.tsx:193
+#: packages/web-util/src/forms/fields/InputSelectMultiple.tsx:194
msgid "Remove"
msgstr "Quitar"
-#: packages/web-util/src/forms/forms-ui.tsx:344
+#: packages/web-util/src/forms/forms-ui.tsx:357
msgid "List of fields with errors"
msgstr "Lista de campos con errores"
@@ -1950,7 +2040,7 @@ msgid "Delete"
msgstr "Eliminar"
#: packages/web-util/src/forms/fields/InputArray.tsx:129
-#: packages/web-util/src/forms/fields/InputArray.tsx:315
+#: packages/web-util/src/forms/fields/InputArray.tsx:316
msgid "Add item"
msgstr "Añadir elemento"
@@ -1963,19 +2053,37 @@ msgstr "Guardar cambios"
msgid "Item %1$s"
msgstr "Elemento %1$s"
-#: packages/web-util/src/forms/fields/InputArray.tsx:282
+#: packages/web-util/src/forms/fields/InputArray.tsx:283
msgid "Edit %1$s"
msgstr "Editar %1$s"
-#: packages/web-util/src/forms/fields/InputArray.tsx:289
+#: packages/web-util/src/forms/fields/InputArray.tsx:290
msgid "Edit"
msgstr "Editar"
-#: packages/web-util/src/forms/index.ts:83
+#: packages/web-util/src/forms/index.ts:84
msgid "Simple comment"
msgstr "Comentario simple"
-#: packages/web-util/src/forms/index.ts:95
+#: packages/web-util/src/forms/index.ts:101
+msgid "Terms URL"
+msgstr ""
+
+#: packages/web-util/src/forms/index.ts:107
+#, fuzzy
+#| msgid "Terms of service"
+msgid "Terms version"
+msgstr "Términos de servicio"
+
+#: packages/web-util/src/forms/index.ts:113
+msgid "Provider name"
+msgstr ""
+
+#: packages/web-util/src/forms/index.ts:118
+msgid "Only show the external link"
+msgstr ""
+
+#: packages/web-util/src/forms/index.ts:124
msgid "Name and birthdate"
msgstr "Nombre y fecha de nacimiento"
diff --git a/packages/web-util/src/i18n/fr.po b/packages/web-util/src/i18n/fr.po
@@ -37,8 +37,8 @@ msgstr ""
"Échec inattendu de la validation. Veuillez contacter les développeurs : %1$s"
#: packages/web-util/src/hooks/useForm.ts:436
-#: packages/web-util/src/forms/AcceptTosForm.tsx:177
-#: packages/web-util/src/forms/index.ts:89
+#: packages/web-util/src/forms/AcceptTosForm.tsx:236
+#: packages/web-util/src/forms/index.ts:90
msgid "Terms of service"
msgstr "Conditions d'utilisation"
@@ -195,6 +195,10 @@ msgstr "Fermer la notification"
msgid "Copy this text manually:"
msgstr "Copiez ce texte manuellement :"
+#: packages/web-util/src/components/ErrorLoading.tsx:62
+msgid "Technical details"
+msgstr "Détails techniques"
+
#: packages/web-util/src/components/LangSelector.tsx:87
#: packages/web-util/src/components/LangSelector.tsx:125
#: packages/web-util/src/components/LangSelector.tsx:149
@@ -210,49 +214,50 @@ msgstr "Langues"
msgid "Loading"
msgstr "Chargement"
-#: packages/web-util/src/components/Header.tsx:92
+#: packages/web-util/src/components/Header.tsx:100
msgid "Show notifications"
msgstr "Afficher les notifications"
-#: packages/web-util/src/components/Header.tsx:136
+#: packages/web-util/src/components/Header.tsx:144
msgid "Open profile"
msgstr "Ouvrir le profil"
-#: packages/web-util/src/components/Header.tsx:168
+#: packages/web-util/src/components/Header.tsx:177
msgid "Open settings"
msgstr "Ouvrir les paramètres"
-#: packages/web-util/src/components/Header.tsx:202
-#: packages/web-util/src/components/Header.tsx:231
+#: packages/web-util/src/components/Header.tsx:211
+#: packages/web-util/src/components/Header.tsx:240
msgid "Close panel"
msgstr "Fermer le panneau"
-#: packages/web-util/src/components/Header.tsx:217
+#: packages/web-util/src/components/Header.tsx:226
msgid "Menu"
msgstr "Menu"
-#: packages/web-util/src/components/Header.tsx:254
+#: packages/web-util/src/components/Header.tsx:263
msgid "Sidebar"
msgstr "Barre latérale"
-#: packages/web-util/src/components/Header.tsx:282
+#: packages/web-util/src/components/Header.tsx:291
msgid "Log out"
msgstr "Déconnexion"
-#: packages/web-util/src/components/Header.tsx:295
+#: packages/web-util/src/components/Header.tsx:304
msgid "Sites"
msgstr "Sites"
-#: packages/web-util/src/components/Footer.tsx:46
+#: packages/web-util/src/components/Footer.tsx:53
msgid "Testing with %1$s"
msgstr "Test avec %1$s"
-#: packages/web-util/src/components/Footer.tsx:57
+#: packages/web-util/src/components/Footer.tsx:65
msgid "stop testing"
msgstr "arrêter le test"
-#: packages/web-util/src/components/Footer.tsx:75
-#: packages/web-util/src/components/Footer.tsx:100
+#: packages/web-util/src/components/Footer.tsx:77
+#: packages/web-util/src/components/Footer.tsx:113
+#: packages/web-util/src/components/Footer.tsx:140
msgid "Learn more about %1$s"
msgstr "En savoir plus sur %1$s"
@@ -280,20 +285,30 @@ msgstr "dans %1$s"
msgid "%1$s ago"
msgstr "il y a %1$s"
+# allow-english: "Pagination" is also the French term.
+#: packages/web-util/src/components/Pagination.tsx:25
+msgid "Pagination"
+msgstr "Pagination"
+
+# allow-english: "Page" is also the French term.
#: packages/web-util/src/components/Pagination.tsx:31
+msgid "Page %1$s"
+msgstr "Page %1$s"
+
+#: packages/web-util/src/components/Pagination.tsx:39
msgid "First page"
msgstr "Première page"
-#: packages/web-util/src/components/Pagination.tsx:38
+#: packages/web-util/src/components/Pagination.tsx:46
msgid "Previous"
msgstr "Précédent"
-#: packages/web-util/src/components/Pagination.tsx:45
+#: packages/web-util/src/components/Pagination.tsx:53
msgid "Next"
msgstr "Suivant"
#: packages/web-util/src/context/bank-api.ts:147
-#: packages/web-util/src/context/challenger-api.ts:170
+#: packages/web-util/src/context/challenger-api.ts:196
#: packages/web-util/src/context/exchange-api.ts:173
msgid "Checking compatibility of this webapp with backend service..."
msgstr ""
@@ -301,14 +316,14 @@ msgstr ""
"backend…"
#: packages/web-util/src/context/bank-api.ts:155
-#: packages/web-util/src/context/challenger-api.ts:179
+#: packages/web-util/src/context/challenger-api.ts:208
#: packages/web-util/src/context/exchange-api.ts:181
msgid "There was an error trying to contact the backend service."
msgstr ""
"Une erreur est survenue lors de la prise de contact avec le service backend."
#: packages/web-util/src/context/bank-api.ts:164
-#: packages/web-util/src/context/challenger-api.ts:199
+#: packages/web-util/src/context/challenger-api.ts:230
#: packages/web-util/src/context/exchange-api.ts:187
msgid ""
"The server version is not supported. Supported version \"%1$s\", server "
@@ -317,16 +332,155 @@ msgstr ""
"La version du serveur n'est pas prise en charge. Version prise en charge "
"« %1$s », version du serveur « %2$s »"
-#: packages/web-util/src/context/challenger-api.ts:187
+#: packages/web-util/src/context/challenger-api.ts:216
msgid "Retry"
msgstr "Réessayer"
-#: packages/web-util/src/context/challenger-api.ts:200
+#: packages/web-util/src/context/challenger-api.ts:231
msgid "The server version is not supported. Supported version \"%1$s\"."
msgstr ""
"La version du serveur n'est pas prise en charge. Version prise en charge : "
"« %1$s »."
+#: packages/web-util/src/forms/AcceptTosForm.tsx:39
+#, fuzzy
+#| msgid "Acceptance date"
+msgid "Acceptance status"
+msgstr "Date d'acceptation"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:42
+#, fuzzy
+#| msgid "Accepted via:"
+msgid "Accepted"
+msgstr "Accepté via :"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:42
+#: packages/web-util/src/forms/AcceptTosForm.tsx:50
+#: packages/web-util/src/forms/AcceptTosForm.tsx:62
+msgid "Not recorded"
+msgstr ""
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:47
+#, fuzzy
+#| msgid "Terms of service"
+msgid "Accepted terms version"
+msgstr "Conditions d'utilisation"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:55
+#, fuzzy
+#| msgid "The PDF could not be downloaded."
+msgid "Terms opened or downloaded"
+msgstr "Le PDF n’a pas pu être téléchargé."
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:59
+#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:100
+#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:101
+#: packages/web-util/src/forms/gana/personal-info.ts:35
+msgid "Yes"
+msgstr "Oui"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:61
+#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:104
+#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:105
+#: packages/web-util/src/forms/gana/personal-info.ts:39
+msgid "No"
+msgstr "Non"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:68
+msgid "Provider"
+msgstr ""
+
+#. Translators: Button that retries loading the terms-of-service document.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:115
+msgid "Try again"
+msgstr "Réessayer"
+
+#. Translators: Status shown while the terms-of-service PDF is downloading.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:117
+msgid "Downloading PDF…"
+msgstr "Téléchargement du PDF…"
+
+#. Translators: Button that downloads the terms-of-service document as a PDF.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:119
+msgid "Download PDF"
+msgstr "Télécharger le PDF"
+
+#. Translators: Button that closes the terms reader. It does not accept the
+#. terms.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:122
+msgid "Done"
+msgstr "Terminé"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:199
+msgid "The terms are not available as Markdown or plain text."
+msgstr ""
+"Les conditions ne sont disponibles ni au format Markdown ni en texte brut."
+
+#. Translators: “terms” means the terms-of-service document, not words or
+#. terminology.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:204
+#: packages/web-util/src/forms/AcceptTosForm.tsx:282
+msgid "These terms are too large to display safely."
+msgstr ""
+"Ces conditions sont trop volumineuses pour être affichées en toute sécurité."
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:207
+msgid "The terms of service could not be loaded."
+msgstr "Les conditions d’utilisation n’ont pas pu être chargées."
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:248
+msgid "Close terms of service"
+msgstr "Fermer les conditions d’utilisation"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:260
+msgid "Loading terms of service…"
+msgstr "Chargement des conditions d’utilisation…"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:311
+msgid "The PDF could not be downloaded."
+msgstr "Le PDF n’a pas pu être téléchargé."
+
+#. Translators: %1$s is the name of the organization or service provider
+#. whose terms the user must review.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:414
+msgid "Read the terms provided by %1$s before recording your acceptance."
+msgstr ""
+"Lisez les conditions fournies par %1$s avant d’enregistrer votre acceptation."
+
+#. Translators: Button that reopens a terms-of-service document the user has
+#. already viewed.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:419
+msgid "Read terms again"
+msgstr "Relire les conditions"
+
+#. Translators: Button that opens the terms-of-service document in an in-app
+#. reader.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:422
+msgid "Read terms"
+msgstr "Lire les conditions"
+
+#. Translators: The accepted version is the exact version of the
+#. terms-of-service document that was opened in the reader.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:425
+msgid "Your acceptance applies to the version shown above."
+msgstr "Votre acceptation s’applique à la version affichée ci-dessus."
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:439
+msgid "Review the terms of service"
+msgstr "Consulter les conditions d’utilisation"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:444
+msgid "Read the terms before recording your acceptance."
+msgstr "Lisez les conditions avant d’enregistrer votre acceptation."
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:484
+msgid "I have read and accept the terms of service"
+msgstr "J’ai lu et j’accepte les conditions d’utilisation"
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:494
+msgid "Open the terms before accepting them."
+msgstr "Ouvrez les conditions avant de les accepter."
+
#: packages/web-util/src/forms/gana/challenger_email.ts:29
msgid "Email verification"
msgstr "Vérification de l’adresse courriel"
@@ -409,13 +563,14 @@ msgid "Supplemental Files"
msgstr "Fichiers supplémentaires"
#: packages/web-util/src/forms/gana/generic_note.ts:67
+#: packages/web-util/src/forms/gana/multi_upload.ts:61
#: packages/web-util/src/forms/gana/VQF_902_14.ts:102
#: packages/web-util/src/forms/gana/VQF_902_1_officer.ts:165
msgid "Description"
msgstr "Description"
#: packages/web-util/src/forms/gana/generic_note.ts:73
-#: packages/web-util/src/forms/gana/multi_upload.ts:61
+#: packages/web-util/src/forms/gana/multi_upload.ts:97
#: packages/web-util/src/forms/gana/VQF_902_14.ts:108
#: packages/web-util/src/forms/gana/VQF_902_1_officer.ts:171
#: packages/web-util/src/forms/gana/generic_upload.ts:43
@@ -430,7 +585,27 @@ msgstr "Téléverser plusieurs documents"
msgid "Upload multiple documents."
msgstr "Téléversez plusieurs documents."
-#: packages/web-util/src/forms/gana/multi_upload.ts:56
+#: packages/web-util/src/forms/gana/multi_upload.ts:43
+#, fuzzy
+#| msgid "Gathered/Consulted documents"
+msgid "Requested documents"
+msgstr "Documents recueillis/consultés"
+
+#: packages/web-util/src/forms/gana/multi_upload.ts:49
+msgid "Document identifier"
+msgstr ""
+
+#: packages/web-util/src/forms/gana/multi_upload.ts:55
+msgid "Title"
+msgstr ""
+
+#: packages/web-util/src/forms/gana/multi_upload.ts:67
+#, fuzzy
+#| msgid "required"
+msgid "Required"
+msgstr "requis"
+
+#: packages/web-util/src/forms/gana/multi_upload.ts:92
#: packages/web-util/src/forms/gana/generic_upload.ts:38
msgid "Document upload (%1$s)"
msgstr "Téléversement de document (%1$s)"
@@ -506,8 +681,8 @@ msgstr "Établissement de la personne de contrôle (soumis par le client)"
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:30
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:31
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:30
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:28
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:31
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:29
msgid "Contracting partner"
msgstr "Partenaire contractant"
@@ -574,8 +749,8 @@ msgstr ""
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:68
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:69
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:46
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:44
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:47
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:45
msgid "Can't be empty"
msgstr "Ne peut pas être vide"
@@ -583,8 +758,8 @@ msgstr "Ne peut pas être vide"
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:77
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:108
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:288
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:54
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:52
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:55
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:53
msgid "Full name"
msgstr "Nom complet"
@@ -607,33 +782,21 @@ msgstr ""
"Une tierce personne est-elle l'ayant droit économique des actifs détenus sur "
"le compte/compte de titres ?"
-#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:100
-#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:101
-#: packages/web-util/src/forms/gana/personal-info.ts:35
-msgid "Yes"
-msgstr "Oui"
-
-#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:104
-#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:105
-#: packages/web-util/src/forms/gana/personal-info.ts:39
-msgid "No"
-msgstr "Non"
-
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:112
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:121
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:113
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:125
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:481
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:490
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:104
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:113
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:105
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:114
msgid "Signature(s)"
msgstr "Signature(s)"
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:113
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:114
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:482
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:105
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:106
msgid ""
"It is a criminal offence to deliberately provide false information on this "
"form (article 251 of the Swiss Criminal Code, document forgery)"
@@ -644,7 +807,7 @@ msgstr ""
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:117
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:121
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:486
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:109
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:110
msgid ""
"The contracting partner hereby undertakes to inform automatically of any "
"changes to the information contained herein."
@@ -655,7 +818,7 @@ msgstr ""
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:127
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:131
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:496
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:119
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:120
msgid "Date"
msgstr "Date"
@@ -665,17 +828,17 @@ msgstr ""
"Établissement de la personne de contrôle (soumis par le responsable LBA)"
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:142
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:102
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:103
msgid "Signed Declaration"
msgstr "Déclaration signée"
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:143
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:103
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:104
msgid "Signed declaration by the customer"
msgstr "Déclaration signée par le client"
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:150
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:107
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:108
msgid ""
"The uploaded document must contain the customer's signature on the "
"beneficial owner declaration."
@@ -684,7 +847,7 @@ msgstr ""
"déclaration de l'ayant droit économique."
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:154
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:111
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:112
msgid "Signed Document"
msgstr "Document signé"
@@ -779,8 +942,8 @@ msgstr "Courriel"
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:132
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:300
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:66
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:64
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:67
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:65
msgid "Date of birth"
msgstr "Date de naissance"
@@ -790,8 +953,8 @@ msgstr "Date de naissance"
#: packages/web-util/src/forms/gana/VQF_902_4.ts:102
#: packages/web-util/src/forms/gana/VQF_902_4.ts:159
#: packages/web-util/src/forms/gana/VQF_902_4.ts:398
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:75
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:73
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:76
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:74
msgid "invalid format"
msgstr "format non valide"
@@ -801,8 +964,8 @@ msgstr "format non valide"
#: packages/web-util/src/forms/gana/VQF_902_4.ts:105
#: packages/web-util/src/forms/gana/VQF_902_4.ts:162
#: packages/web-util/src/forms/gana/VQF_902_4.ts:401
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:78
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:76
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:79
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:77
msgid "it can't be in the future"
msgstr "cela ne peut pas être dans le futur"
@@ -812,15 +975,15 @@ msgstr "cela ne peut pas être dans le futur"
#: packages/web-util/src/forms/gana/VQF_902_4.ts:112
#: packages/web-util/src/forms/gana/VQF_902_4.ts:169
#: packages/web-util/src/forms/gana/VQF_902_4.ts:408
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:85
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:83
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:86
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:84
msgid "it can't be greater than 120 years"
msgstr "cela ne peut pas dépasser 120 ans"
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:159
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:327
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:92
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:90
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:93
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:91
msgid "Nationality"
msgstr "Nationalité"
@@ -1677,27 +1840,32 @@ msgid "Other relevant information"
msgstr "Autres informations pertinentes"
#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:10
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:10
-msgid "Declaration of identity of the beneficial owner (A)"
+#, fuzzy
+#| msgid "Declaration of identity of the beneficial owner (A)"
+msgid "Declaration of identity of the beneficial owner (A) — customer"
msgstr "Déclaration d'identité de l'ayant droit économique (A)"
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:23
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:21
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:11
+msgid "The customer completes the declaration directly in the form."
+msgstr ""
+
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:24
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:22
msgid "Declaration of identity of the beneficial owner"
msgstr "Déclaration d'identité de l'ayant droit économique"
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:37
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:35
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:38
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:36
msgid "Beneficial owner details"
msgstr "Coordonnées de l'ayant droit économique"
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:41
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:39
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:42
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:40
msgid "Beneficial owner(s)"
msgstr "Ayant(s) droit économique(s)"
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:42
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:40
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:43
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:41
msgid ""
"The person(s) listed below is/are the beneficial owner(s) of the assets "
"involved in the business relationship. If the contracting partner is also "
@@ -1709,11 +1877,23 @@ msgstr ""
"d'affaires. Si le cocontractant est également l'unique ayant droit "
"économique des avoirs, ses coordonnées doivent être indiquées ci-dessous."
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:60
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:58
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:61
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:59
msgid "Domicile address"
msgstr "Adresse de domicile"
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:10
+#, fuzzy
+#| msgid "Declaration of identity of the beneficial owner (A)"
+msgid "Declaration of identity of the beneficial owner (A) — AML officer"
+msgstr "Déclaration d'identité de l'ayant droit économique (A)"
+
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:11
+msgid ""
+"The AML officer records the declaration and uploads the customer's signed "
+"PDF."
+msgstr ""
+
#: packages/web-util/src/forms/Calendar.tsx:56
msgid "January"
msgstr "Janvier"
@@ -1778,107 +1958,16 @@ msgstr "Mois précédent"
msgid "Next month"
msgstr "Mois suivant"
-#. Translators: Button that retries loading the terms-of-service document.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:56
-msgid "Try again"
-msgstr "Réessayer"
-
-#. Translators: Status shown while the terms-of-service PDF is downloading.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:58
-msgid "Downloading PDF…"
-msgstr "Téléchargement du PDF…"
-
-#. Translators: Button that downloads the terms-of-service document as a PDF.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:60
-msgid "Download PDF"
-msgstr "Télécharger le PDF"
-
-#. Translators: Button that closes the terms reader. It does not accept the
-#. terms.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:63
-msgid "Done"
-msgstr "Terminé"
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:140
-msgid "The terms are not available as Markdown or plain text."
-msgstr ""
-"Les conditions ne sont disponibles ni au format Markdown ni en texte brut."
-
-#. Translators: “terms” means the terms-of-service document, not words or
-#. terminology.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:145
-#: packages/web-util/src/forms/AcceptTosForm.tsx:223
-msgid "These terms are too large to display safely."
-msgstr ""
-"Ces conditions sont trop volumineuses pour être affichées en toute sécurité."
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:148
-msgid "The terms of service could not be loaded."
-msgstr "Les conditions d’utilisation n’ont pas pu être chargées."
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:189
-msgid "Close terms of service"
-msgstr "Fermer les conditions d’utilisation"
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:201
-msgid "Loading terms of service…"
-msgstr "Chargement des conditions d’utilisation…"
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:252
-msgid "The PDF could not be downloaded."
-msgstr "Le PDF n’a pas pu être téléchargé."
-
-#. Translators: %1$s is the name of the organization or service provider
-#. whose terms the user must review.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:355
-msgid "Read the terms provided by %1$s before recording your acceptance."
-msgstr ""
-"Lisez les conditions fournies par %1$s avant d’enregistrer votre acceptation."
-
-#. Translators: Button that reopens a terms-of-service document the user has
-#. already viewed.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:360
-msgid "Read terms again"
-msgstr "Relire les conditions"
-
-#. Translators: Button that opens the terms-of-service document in an in-app
-#. reader.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:363
-msgid "Read terms"
-msgstr "Lire les conditions"
-
-#. Translators: The accepted version is the exact version of the
-#. terms-of-service document that was opened in the reader.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:366
-msgid "Your acceptance applies to the version shown above."
-msgstr "Votre acceptation s’applique à la version affichée ci-dessus."
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:380
-msgid "Review the terms of service"
-msgstr "Consulter les conditions d’utilisation"
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:385
-msgid "Read the terms before recording your acceptance."
-msgstr "Lisez les conditions avant d’enregistrer votre acceptation."
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:425
-msgid "I have read and accept the terms of service"
-msgstr "J’ai lu et j’accepte les conditions d’utilisation"
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:435
-msgid "Open the terms before accepting them."
-msgstr "Ouvrez les conditions avant de les accepter."
-
-#: packages/web-util/src/forms/fields/InputSelectOne.tsx:82
+#: packages/web-util/src/forms/fields/InputSelectOne.tsx:85
msgid "Clear selection"
msgstr "Effacer la sélection"
-#: packages/web-util/src/forms/fields/InputSelectOne.tsx:170
+#: packages/web-util/src/forms/fields/InputSelectOne.tsx:173
msgid "Toggle choices"
msgstr "Afficher les choix"
-#: packages/web-util/src/forms/fields/InputSelectOne.tsx:193
-#: packages/web-util/src/forms/fields/InputSelectMultiple.tsx:132
+#: packages/web-util/src/forms/fields/InputSelectOne.tsx:201
+#: packages/web-util/src/forms/fields/InputSelectMultiple.tsx:133
msgid "No element found"
msgstr "Aucun élément trouvé"
@@ -1907,10 +1996,13 @@ msgid "seconds"
msgstr "secondes"
#: packages/web-util/src/forms/fields/InputDuration.tsx:339
-#: packages/web-util/src/forms/fields/InputDurationText.tsx:94
msgid "No expiration"
msgstr "Sans date d’expiration"
+#: packages/web-util/src/forms/fields/InputDurationText.tsx:94
+msgid "Forever"
+msgstr "Indéfiniment"
+
#: packages/web-util/src/forms/fields/InputFile.tsx:46
msgid "The selected file is too large."
msgstr "Le fichier sélectionné est trop volumineux."
@@ -1919,23 +2011,23 @@ msgstr "Le fichier sélectionné est trop volumineux."
msgid "The selected file could not be read."
msgstr "Le fichier sélectionné n’a pas pu être lu."
-#: packages/web-util/src/forms/fields/InputFile.tsx:99
+#: packages/web-util/src/forms/fields/InputFile.tsx:100
msgid "Upload a file"
msgstr "Téléverser un fichier"
-#: packages/web-util/src/forms/fields/InputFile.tsx:153
+#: packages/web-util/src/forms/fields/InputFile.tsx:154
msgid "Clear"
msgstr "Effacer"
-#: packages/web-util/src/forms/fields/InputFile.tsx:162
+#: packages/web-util/src/forms/fields/InputFile.tsx:163
msgid "Download a copy."
msgstr "Télécharger une copie."
-#: packages/web-util/src/forms/fields/InputSelectMultiple.tsx:193
+#: packages/web-util/src/forms/fields/InputSelectMultiple.tsx:194
msgid "Remove"
msgstr "Supprimer"
-#: packages/web-util/src/forms/forms-ui.tsx:344
+#: packages/web-util/src/forms/forms-ui.tsx:357
msgid "List of fields with errors"
msgstr "Liste des champs comportant des erreurs"
@@ -1960,7 +2052,7 @@ msgid "Delete"
msgstr "Supprimer"
#: packages/web-util/src/forms/fields/InputArray.tsx:129
-#: packages/web-util/src/forms/fields/InputArray.tsx:315
+#: packages/web-util/src/forms/fields/InputArray.tsx:316
msgid "Add item"
msgstr "Ajouter un élément"
@@ -1973,19 +2065,37 @@ msgstr "Enregistrer les modifications"
msgid "Item %1$s"
msgstr "Élément %1$s"
-#: packages/web-util/src/forms/fields/InputArray.tsx:282
+#: packages/web-util/src/forms/fields/InputArray.tsx:283
msgid "Edit %1$s"
msgstr "Modifier %1$s"
-#: packages/web-util/src/forms/fields/InputArray.tsx:289
+#: packages/web-util/src/forms/fields/InputArray.tsx:290
msgid "Edit"
msgstr "Modifier"
-#: packages/web-util/src/forms/index.ts:83
+#: packages/web-util/src/forms/index.ts:84
msgid "Simple comment"
msgstr "Commentaire simple"
-#: packages/web-util/src/forms/index.ts:95
+#: packages/web-util/src/forms/index.ts:101
+msgid "Terms URL"
+msgstr ""
+
+#: packages/web-util/src/forms/index.ts:107
+#, fuzzy
+#| msgid "Terms of service"
+msgid "Terms version"
+msgstr "Conditions d'utilisation"
+
+#: packages/web-util/src/forms/index.ts:113
+msgid "Provider name"
+msgstr ""
+
+#: packages/web-util/src/forms/index.ts:118
+msgid "Only show the external link"
+msgstr ""
+
+#: packages/web-util/src/forms/index.ts:124
msgid "Name and birthdate"
msgstr "Nom et date de naissance"
diff --git a/packages/web-util/src/i18n/strings.ts b/packages/web-util/src/i18n/strings.ts
@@ -120,6 +120,9 @@ strings['fr'] = {
"Copy this text manually:": [
"Copiez ce texte manuellement :"
],
+ "Technical details": [
+ "Détails techniques"
+ ],
"Select language": [
"Sélectionner la langue"
],
@@ -180,6 +183,12 @@ strings['fr'] = {
"%1$s ago": [
"il y a %1$s"
],
+ "Pagination": [
+ "Pagination"
+ ],
+ "Page %1$s": [
+ "Page %1$s"
+ ],
"First page": [
"Première page"
],
@@ -204,6 +213,72 @@ strings['fr'] = {
"The server version is not supported. Supported version \"%1$s\".": [
"La version du serveur n'est pas prise en charge. Version prise en charge : « %1$s »."
],
+ "Not recorded": [
+ ""
+ ],
+ "Yes": [
+ "Oui"
+ ],
+ "No": [
+ "Non"
+ ],
+ "Provider": [
+ ""
+ ],
+ "Try again": [
+ "Réessayer"
+ ],
+ "Downloading PDF…": [
+ "Téléchargement du PDF…"
+ ],
+ "Download PDF": [
+ "Télécharger le PDF"
+ ],
+ "Done": [
+ "Terminé"
+ ],
+ "The terms are not available as Markdown or plain text.": [
+ "Les conditions ne sont disponibles ni au format Markdown ni en texte brut."
+ ],
+ "These terms are too large to display safely.": [
+ "Ces conditions sont trop volumineuses pour être affichées en toute sécurité."
+ ],
+ "The terms of service could not be loaded.": [
+ "Les conditions d’utilisation n’ont pas pu être chargées."
+ ],
+ "Close terms of service": [
+ "Fermer les conditions d’utilisation"
+ ],
+ "Loading terms of service…": [
+ "Chargement des conditions d’utilisation…"
+ ],
+ "The PDF could not be downloaded.": [
+ "Le PDF n’a pas pu être téléchargé."
+ ],
+ "Read the terms provided by %1$s before recording your acceptance.": [
+ "Lisez les conditions fournies par %1$s avant d’enregistrer votre acceptation."
+ ],
+ "Read terms again": [
+ "Relire les conditions"
+ ],
+ "Read terms": [
+ "Lire les conditions"
+ ],
+ "Your acceptance applies to the version shown above.": [
+ "Votre acceptation s’applique à la version affichée ci-dessus."
+ ],
+ "Review the terms of service": [
+ "Consulter les conditions d’utilisation"
+ ],
+ "Read the terms before recording your acceptance.": [
+ "Lisez les conditions avant d’enregistrer votre acceptation."
+ ],
+ "I have read and accept the terms of service": [
+ "J’ai lu et j’accepte les conditions d’utilisation"
+ ],
+ "Open the terms before accepting them.": [
+ "Ouvrez les conditions avant de les accepter."
+ ],
"Email verification": [
"Vérification de l’adresse courriel"
],
@@ -270,6 +345,12 @@ strings['fr'] = {
"Upload multiple documents.": [
"Téléversez plusieurs documents."
],
+ "Document identifier": [
+ ""
+ ],
+ "Title": [
+ ""
+ ],
"Document upload (%1$s)": [
"Téléversement de document (%1$s)"
],
@@ -354,12 +435,6 @@ strings['fr'] = {
"Is a third person the beneficial owner of the assets held in the account/securities account?": [
"Une tierce personne est-elle l'ayant droit économique des actifs détenus sur le compte/compte de titres ?"
],
- "Yes": [
- "Oui"
- ],
- "No": [
- "Non"
- ],
"Signature(s)": [
"Signature(s)"
],
@@ -939,8 +1014,8 @@ strings['fr'] = {
"Other relevant information": [
"Autres informations pertinentes"
],
- "Declaration of identity of the beneficial owner (A)": [
- "Déclaration d'identité de l'ayant droit économique (A)"
+ "The customer completes the declaration directly in the form.": [
+ ""
],
"Declaration of identity of the beneficial owner": [
"Déclaration d'identité de l'ayant droit économique"
@@ -957,6 +1032,9 @@ strings['fr'] = {
"Domicile address": [
"Adresse de domicile"
],
+ "The AML officer records the declaration and uploads the customer's signed PDF.": [
+ ""
+ ],
"January": [
"Janvier"
],
@@ -1005,60 +1083,6 @@ strings['fr'] = {
"Next month": [
"Mois suivant"
],
- "Try again": [
- "Réessayer"
- ],
- "Downloading PDF…": [
- "Téléchargement du PDF…"
- ],
- "Download PDF": [
- "Télécharger le PDF"
- ],
- "Done": [
- "Terminé"
- ],
- "The terms are not available as Markdown or plain text.": [
- "Les conditions ne sont disponibles ni au format Markdown ni en texte brut."
- ],
- "These terms are too large to display safely.": [
- "Ces conditions sont trop volumineuses pour être affichées en toute sécurité."
- ],
- "The terms of service could not be loaded.": [
- "Les conditions d’utilisation n’ont pas pu être chargées."
- ],
- "Close terms of service": [
- "Fermer les conditions d’utilisation"
- ],
- "Loading terms of service…": [
- "Chargement des conditions d’utilisation…"
- ],
- "The PDF could not be downloaded.": [
- "Le PDF n’a pas pu être téléchargé."
- ],
- "Read the terms provided by %1$s before recording your acceptance.": [
- "Lisez les conditions fournies par %1$s avant d’enregistrer votre acceptation."
- ],
- "Read terms again": [
- "Relire les conditions"
- ],
- "Read terms": [
- "Lire les conditions"
- ],
- "Your acceptance applies to the version shown above.": [
- "Votre acceptation s’applique à la version affichée ci-dessus."
- ],
- "Review the terms of service": [
- "Consulter les conditions d’utilisation"
- ],
- "Read the terms before recording your acceptance.": [
- "Lisez les conditions avant d’enregistrer votre acceptation."
- ],
- "I have read and accept the terms of service": [
- "J’ai lu et j’accepte les conditions d’utilisation"
- ],
- "Open the terms before accepting them.": [
- "Ouvrez les conditions avant de les accepter."
- ],
"Clear selection": [
"Effacer la sélection"
],
@@ -1089,6 +1113,9 @@ strings['fr'] = {
"No expiration": [
"Sans date d’expiration"
],
+ "Forever": [
+ "Indéfiniment"
+ ],
"The selected file is too large.": [
"Le fichier sélectionné est trop volumineux."
],
@@ -1143,6 +1170,15 @@ strings['fr'] = {
"Simple comment": [
"Commentaire simple"
],
+ "Terms URL": [
+ ""
+ ],
+ "Provider name": [
+ ""
+ ],
+ "Only show the external link": [
+ ""
+ ],
"Name and birthdate": [
"Nom et date de naissance"
],
@@ -1199,7 +1235,7 @@ strings['fr'] = {
"domain": "messages",
"plural_forms": "nplurals=2; plural=n > 1;",
"lang": "fr",
- "completeness": 100
+ "completeness": 95
};
strings['es'] = {
@@ -1312,6 +1348,9 @@ strings['es'] = {
"Copy this text manually:": [
"Copie este texto manualmente:"
],
+ "Technical details": [
+ "Detalles técnicos"
+ ],
"Select language": [
"Seleccionar idioma"
],
@@ -1372,6 +1411,12 @@ strings['es'] = {
"%1$s ago": [
"hace %1$s"
],
+ "Pagination": [
+ "Paginación"
+ ],
+ "Page %1$s": [
+ "Página %1$s"
+ ],
"First page": [
"Primera página"
],
@@ -1396,6 +1441,72 @@ strings['es'] = {
"The server version is not supported. Supported version \"%1$s\".": [
"La versión del servidor no es compatible. Versión compatible: \"%1$s\"."
],
+ "Not recorded": [
+ ""
+ ],
+ "Yes": [
+ "Sí"
+ ],
+ "No": [
+ "No"
+ ],
+ "Provider": [
+ ""
+ ],
+ "Try again": [
+ "Intentar de nuevo"
+ ],
+ "Downloading PDF…": [
+ "Descargando el PDF…"
+ ],
+ "Download PDF": [
+ "Descargar PDF"
+ ],
+ "Done": [
+ "Listo"
+ ],
+ "The terms are not available as Markdown or plain text.": [
+ "Los términos no están disponibles en Markdown ni en texto sin formato."
+ ],
+ "These terms are too large to display safely.": [
+ "Estos términos son demasiado grandes para mostrarlos de forma segura."
+ ],
+ "The terms of service could not be loaded.": [
+ "No se pudieron cargar los términos de servicio."
+ ],
+ "Close terms of service": [
+ "Cerrar los términos de servicio"
+ ],
+ "Loading terms of service…": [
+ "Cargando los términos de servicio…"
+ ],
+ "The PDF could not be downloaded.": [
+ "No se pudo descargar el PDF."
+ ],
+ "Read the terms provided by %1$s before recording your acceptance.": [
+ "Lea los términos proporcionados por %1$s antes de registrar su aceptación."
+ ],
+ "Read terms again": [
+ "Volver a leer los términos"
+ ],
+ "Read terms": [
+ "Leer los términos"
+ ],
+ "Your acceptance applies to the version shown above.": [
+ "Su aceptación se aplica a la versión mostrada arriba."
+ ],
+ "Review the terms of service": [
+ "Revisar los términos de servicio"
+ ],
+ "Read the terms before recording your acceptance.": [
+ "Lea los términos antes de registrar su aceptación."
+ ],
+ "I have read and accept the terms of service": [
+ "He leído y acepto los términos de servicio"
+ ],
+ "Open the terms before accepting them.": [
+ "Abra los términos antes de aceptarlos."
+ ],
"Email verification": [
"Verificación del correo electrónico"
],
@@ -1462,6 +1573,12 @@ strings['es'] = {
"Upload multiple documents.": [
"Sube varios documentos."
],
+ "Document identifier": [
+ ""
+ ],
+ "Title": [
+ ""
+ ],
"Document upload (%1$s)": [
"Carga de documentos (%1$s)"
],
@@ -1546,12 +1663,6 @@ strings['es'] = {
"Is a third person the beneficial owner of the assets held in the account/securities account?": [
"¿Es un tercero el beneficiario efectivo de los activos mantenidos en la cuenta/cuenta de valores?"
],
- "Yes": [
- "Sí"
- ],
- "No": [
- "No"
- ],
"Signature(s)": [
"Firma(s)"
],
@@ -2131,8 +2242,8 @@ strings['es'] = {
"Other relevant information": [
"Otra información relevante"
],
- "Declaration of identity of the beneficial owner (A)": [
- "Declaración de identidad del beneficiario efectivo (A)"
+ "The customer completes the declaration directly in the form.": [
+ ""
],
"Declaration of identity of the beneficial owner": [
"Declaración de identidad del beneficiario efectivo"
@@ -2149,6 +2260,9 @@ strings['es'] = {
"Domicile address": [
"Dirección de domicilio"
],
+ "The AML officer records the declaration and uploads the customer's signed PDF.": [
+ ""
+ ],
"January": [
"Enero"
],
@@ -2197,60 +2311,6 @@ strings['es'] = {
"Next month": [
"Mes siguiente"
],
- "Try again": [
- "Intentar de nuevo"
- ],
- "Downloading PDF…": [
- "Descargando el PDF…"
- ],
- "Download PDF": [
- "Descargar PDF"
- ],
- "Done": [
- "Listo"
- ],
- "The terms are not available as Markdown or plain text.": [
- "Los términos no están disponibles en Markdown ni en texto sin formato."
- ],
- "These terms are too large to display safely.": [
- "Estos términos son demasiado grandes para mostrarlos de forma segura."
- ],
- "The terms of service could not be loaded.": [
- "No se pudieron cargar los términos de servicio."
- ],
- "Close terms of service": [
- "Cerrar los términos de servicio"
- ],
- "Loading terms of service…": [
- "Cargando los términos de servicio…"
- ],
- "The PDF could not be downloaded.": [
- "No se pudo descargar el PDF."
- ],
- "Read the terms provided by %1$s before recording your acceptance.": [
- "Lea los términos proporcionados por %1$s antes de registrar su aceptación."
- ],
- "Read terms again": [
- "Volver a leer los términos"
- ],
- "Read terms": [
- "Leer los términos"
- ],
- "Your acceptance applies to the version shown above.": [
- "Su aceptación se aplica a la versión mostrada arriba."
- ],
- "Review the terms of service": [
- "Revisar los términos de servicio"
- ],
- "Read the terms before recording your acceptance.": [
- "Lea los términos antes de registrar su aceptación."
- ],
- "I have read and accept the terms of service": [
- "He leído y acepto los términos de servicio"
- ],
- "Open the terms before accepting them.": [
- "Abra los términos antes de aceptarlos."
- ],
"Clear selection": [
"Borrar selección"
],
@@ -2281,6 +2341,9 @@ strings['es'] = {
"No expiration": [
"Sin vencimiento"
],
+ "Forever": [
+ "Para siempre"
+ ],
"The selected file is too large.": [
"El archivo seleccionado es demasiado grande."
],
@@ -2335,6 +2398,15 @@ strings['es'] = {
"Simple comment": [
"Comentario simple"
],
+ "Terms URL": [
+ ""
+ ],
+ "Provider name": [
+ ""
+ ],
+ "Only show the external link": [
+ ""
+ ],
"Name and birthdate": [
"Nombre y fecha de nacimiento"
],
@@ -2391,7 +2463,7 @@ strings['es'] = {
"domain": "messages",
"plural_forms": "nplurals=2; plural=n != 1;",
"lang": "es_AR",
- "completeness": 100
+ "completeness": 95
};
strings['de'] = {
@@ -2504,6 +2576,9 @@ strings['de'] = {
"Copy this text manually:": [
"Kopieren Sie diesen Text manuell:"
],
+ "Technical details": [
+ "Technische Details"
+ ],
"Select language": [
"Sprache auswählen"
],
@@ -2564,6 +2639,12 @@ strings['de'] = {
"%1$s ago": [
"vor %1$s"
],
+ "Pagination": [
+ "Seitennavigation"
+ ],
+ "Page %1$s": [
+ "Seite %1$s"
+ ],
"First page": [
"Erste Seite"
],
@@ -2588,6 +2669,72 @@ strings['de'] = {
"The server version is not supported. Supported version \"%1$s\".": [
"Die Serverversion wird nicht unterstützt. Unterstützte Version „%1$s“."
],
+ "Not recorded": [
+ ""
+ ],
+ "Yes": [
+ "Ja"
+ ],
+ "No": [
+ "Nein"
+ ],
+ "Provider": [
+ ""
+ ],
+ "Try again": [
+ "Erneut versuchen"
+ ],
+ "Downloading PDF…": [
+ "PDF wird heruntergeladen …"
+ ],
+ "Download PDF": [
+ "PDF herunterladen"
+ ],
+ "Done": [
+ "Fertig"
+ ],
+ "The terms are not available as Markdown or plain text.": [
+ "Die Bedingungen sind weder als Markdown noch als Klartext verfügbar."
+ ],
+ "These terms are too large to display safely.": [
+ "Diese Bedingungen sind zu umfangreich, um sie sicher anzuzeigen."
+ ],
+ "The terms of service could not be loaded.": [
+ "Die Allgemeinen Geschäftsbedingungen konnten nicht geladen werden."
+ ],
+ "Close terms of service": [
+ "Allgemeine Geschäftsbedingungen schließen"
+ ],
+ "Loading terms of service…": [
+ "Allgemeine Geschäftsbedingungen werden geladen …"
+ ],
+ "The PDF could not be downloaded.": [
+ "Die PDF-Datei konnte nicht heruntergeladen werden."
+ ],
+ "Read the terms provided by %1$s before recording your acceptance.": [
+ "Lesen Sie die von %1$s bereitgestellten Bedingungen, bevor Sie Ihre Zustimmung bestätigen."
+ ],
+ "Read terms again": [
+ "Bedingungen erneut lesen"
+ ],
+ "Read terms": [
+ "Bedingungen lesen"
+ ],
+ "Your acceptance applies to the version shown above.": [
+ "Ihre Zustimmung gilt für die oben angezeigte Version."
+ ],
+ "Review the terms of service": [
+ "Allgemeine Geschäftsbedingungen prüfen"
+ ],
+ "Read the terms before recording your acceptance.": [
+ "Lesen Sie die Bedingungen, bevor Sie Ihre Zustimmung bestätigen."
+ ],
+ "I have read and accept the terms of service": [
+ "Ich habe die Allgemeinen Geschäftsbedingungen gelesen und akzeptiere sie"
+ ],
+ "Open the terms before accepting them.": [
+ "Öffnen Sie die Bedingungen, bevor Sie sie akzeptieren."
+ ],
"Email verification": [
"E-Mail-Verifizierung"
],
@@ -2654,6 +2801,12 @@ strings['de'] = {
"Upload multiple documents.": [
"Mehrere Dokumente hochladen."
],
+ "Document identifier": [
+ ""
+ ],
+ "Title": [
+ ""
+ ],
"Document upload (%1$s)": [
"Dokument-Upload (%1$s)"
],
@@ -2738,12 +2891,6 @@ strings['de'] = {
"Is a third person the beneficial owner of the assets held in the account/securities account?": [
"Ist eine Drittperson an den auf dem Konto/Depot liegenden Vermögenswerten wirtschaftlich berechtigt?"
],
- "Yes": [
- "Ja"
- ],
- "No": [
- "Nein"
- ],
"Signature(s)": [
"Unterschrift(en)"
],
@@ -3323,8 +3470,8 @@ strings['de'] = {
"Other relevant information": [
"Weitere relevante Angaben"
],
- "Declaration of identity of the beneficial owner (A)": [
- "Feststellung des wirtschaftlich Berechtigten (A)"
+ "The customer completes the declaration directly in the form.": [
+ ""
],
"Declaration of identity of the beneficial owner": [
"Feststellung des wirtschaftlich Berechtigten"
@@ -3341,6 +3488,9 @@ strings['de'] = {
"Domicile address": [
"Sitzadresse"
],
+ "The AML officer records the declaration and uploads the customer's signed PDF.": [
+ ""
+ ],
"January": [
"Januar"
],
@@ -3389,60 +3539,6 @@ strings['de'] = {
"Next month": [
"Nächster Monat"
],
- "Try again": [
- "Erneut versuchen"
- ],
- "Downloading PDF…": [
- "PDF wird heruntergeladen …"
- ],
- "Download PDF": [
- "PDF herunterladen"
- ],
- "Done": [
- "Fertig"
- ],
- "The terms are not available as Markdown or plain text.": [
- "Die Bedingungen sind weder als Markdown noch als Klartext verfügbar."
- ],
- "These terms are too large to display safely.": [
- "Diese Bedingungen sind zu umfangreich, um sie sicher anzuzeigen."
- ],
- "The terms of service could not be loaded.": [
- "Die Allgemeinen Geschäftsbedingungen konnten nicht geladen werden."
- ],
- "Close terms of service": [
- "Allgemeine Geschäftsbedingungen schließen"
- ],
- "Loading terms of service…": [
- "Allgemeine Geschäftsbedingungen werden geladen …"
- ],
- "The PDF could not be downloaded.": [
- "Die PDF-Datei konnte nicht heruntergeladen werden."
- ],
- "Read the terms provided by %1$s before recording your acceptance.": [
- "Lesen Sie die von %1$s bereitgestellten Bedingungen, bevor Sie Ihre Zustimmung bestätigen."
- ],
- "Read terms again": [
- "Bedingungen erneut lesen"
- ],
- "Read terms": [
- "Bedingungen lesen"
- ],
- "Your acceptance applies to the version shown above.": [
- "Ihre Zustimmung gilt für die oben angezeigte Version."
- ],
- "Review the terms of service": [
- "Allgemeine Geschäftsbedingungen prüfen"
- ],
- "Read the terms before recording your acceptance.": [
- "Lesen Sie die Bedingungen, bevor Sie Ihre Zustimmung bestätigen."
- ],
- "I have read and accept the terms of service": [
- "Ich habe die Allgemeinen Geschäftsbedingungen gelesen und akzeptiere sie"
- ],
- "Open the terms before accepting them.": [
- "Öffnen Sie die Bedingungen, bevor Sie sie akzeptieren."
- ],
"Clear selection": [
"Auswahl löschen"
],
@@ -3473,6 +3569,9 @@ strings['de'] = {
"No expiration": [
"Keine Ablaufzeit"
],
+ "Forever": [
+ "Für immer"
+ ],
"The selected file is too large.": [
"Die ausgewählte Datei ist zu groß."
],
@@ -3527,6 +3626,15 @@ strings['de'] = {
"Simple comment": [
"Einfacher Kommentar"
],
+ "Terms URL": [
+ ""
+ ],
+ "Provider name": [
+ ""
+ ],
+ "Only show the external link": [
+ ""
+ ],
"Name and birthdate": [
"Name und Geburtsdatum"
],
@@ -3583,6 +3691,6 @@ strings['de'] = {
"domain": "messages",
"plural_forms": "nplurals=2; plural=n != 1;",
"lang": "de",
- "completeness": 100
+ "completeness": 95
};
diff --git a/packages/web-util/src/i18n/web-util.pot b/packages/web-util/src/i18n/web-util.pot
@@ -33,8 +33,8 @@ msgid "Validation failed unexpectedly. Please contact the developers: %1$s"
msgstr ""
#: packages/web-util/src/hooks/useForm.ts:436
-#: packages/web-util/src/forms/AcceptTosForm.tsx:177
-#: packages/web-util/src/forms/index.ts:89
+#: packages/web-util/src/forms/AcceptTosForm.tsx:236
+#: packages/web-util/src/forms/index.ts:90
msgid "Terms of service"
msgstr ""
@@ -181,6 +181,10 @@ msgstr ""
msgid "Copy this text manually:"
msgstr ""
+#: packages/web-util/src/components/ErrorLoading.tsx:62
+msgid "Technical details"
+msgstr ""
+
#: packages/web-util/src/components/LangSelector.tsx:87
#: packages/web-util/src/components/LangSelector.tsx:125
#: packages/web-util/src/components/LangSelector.tsx:149
@@ -196,49 +200,50 @@ msgstr ""
msgid "Loading"
msgstr ""
-#: packages/web-util/src/components/Header.tsx:92
+#: packages/web-util/src/components/Header.tsx:100
msgid "Show notifications"
msgstr ""
-#: packages/web-util/src/components/Header.tsx:136
+#: packages/web-util/src/components/Header.tsx:144
msgid "Open profile"
msgstr ""
-#: packages/web-util/src/components/Header.tsx:168
+#: packages/web-util/src/components/Header.tsx:177
msgid "Open settings"
msgstr ""
-#: packages/web-util/src/components/Header.tsx:202
-#: packages/web-util/src/components/Header.tsx:231
+#: packages/web-util/src/components/Header.tsx:211
+#: packages/web-util/src/components/Header.tsx:240
msgid "Close panel"
msgstr ""
-#: packages/web-util/src/components/Header.tsx:217
+#: packages/web-util/src/components/Header.tsx:226
msgid "Menu"
msgstr ""
-#: packages/web-util/src/components/Header.tsx:254
+#: packages/web-util/src/components/Header.tsx:263
msgid "Sidebar"
msgstr ""
-#: packages/web-util/src/components/Header.tsx:282
+#: packages/web-util/src/components/Header.tsx:291
msgid "Log out"
msgstr ""
-#: packages/web-util/src/components/Header.tsx:295
+#: packages/web-util/src/components/Header.tsx:304
msgid "Sites"
msgstr ""
-#: packages/web-util/src/components/Footer.tsx:46
+#: packages/web-util/src/components/Footer.tsx:53
msgid "Testing with %1$s"
msgstr ""
-#: packages/web-util/src/components/Footer.tsx:57
+#: packages/web-util/src/components/Footer.tsx:65
msgid "stop testing"
msgstr ""
-#: packages/web-util/src/components/Footer.tsx:75
-#: packages/web-util/src/components/Footer.tsx:100
+#: packages/web-util/src/components/Footer.tsx:77
+#: packages/web-util/src/components/Footer.tsx:113
+#: packages/web-util/src/components/Footer.tsx:140
msgid "Learn more about %1$s"
msgstr ""
@@ -266,46 +271,182 @@ msgstr ""
msgid "%1$s ago"
msgstr ""
+#: packages/web-util/src/components/Pagination.tsx:25
+msgid "Pagination"
+msgstr ""
+
#: packages/web-util/src/components/Pagination.tsx:31
+msgid "Page %1$s"
+msgstr ""
+
+#: packages/web-util/src/components/Pagination.tsx:39
msgid "First page"
msgstr ""
-#: packages/web-util/src/components/Pagination.tsx:38
+#: packages/web-util/src/components/Pagination.tsx:46
msgid "Previous"
msgstr ""
-#: packages/web-util/src/components/Pagination.tsx:45
+#: packages/web-util/src/components/Pagination.tsx:53
msgid "Next"
msgstr ""
#: packages/web-util/src/context/bank-api.ts:147
-#: packages/web-util/src/context/challenger-api.ts:170
+#: packages/web-util/src/context/challenger-api.ts:196
#: packages/web-util/src/context/exchange-api.ts:173
msgid "Checking compatibility of this webapp with backend service..."
msgstr ""
#: packages/web-util/src/context/bank-api.ts:155
-#: packages/web-util/src/context/challenger-api.ts:179
+#: packages/web-util/src/context/challenger-api.ts:208
#: packages/web-util/src/context/exchange-api.ts:181
msgid "There was an error trying to contact the backend service."
msgstr ""
#: packages/web-util/src/context/bank-api.ts:164
-#: packages/web-util/src/context/challenger-api.ts:199
+#: packages/web-util/src/context/challenger-api.ts:230
#: packages/web-util/src/context/exchange-api.ts:187
msgid ""
"The server version is not supported. Supported version \"%1$s\", server version "
"\"%2$s\""
msgstr ""
-#: packages/web-util/src/context/challenger-api.ts:187
+#: packages/web-util/src/context/challenger-api.ts:216
msgid "Retry"
msgstr ""
-#: packages/web-util/src/context/challenger-api.ts:200
+#: packages/web-util/src/context/challenger-api.ts:231
msgid "The server version is not supported. Supported version \"%1$s\"."
msgstr ""
+#: packages/web-util/src/forms/AcceptTosForm.tsx:39
+msgid "Acceptance status"
+msgstr ""
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:42
+msgid "Accepted"
+msgstr ""
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:42
+#: packages/web-util/src/forms/AcceptTosForm.tsx:50
+#: packages/web-util/src/forms/AcceptTosForm.tsx:62
+msgid "Not recorded"
+msgstr ""
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:47
+msgid "Accepted terms version"
+msgstr ""
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:55
+msgid "Terms opened or downloaded"
+msgstr ""
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:59
+#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:100
+#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:101
+#: packages/web-util/src/forms/gana/personal-info.ts:35
+msgid "Yes"
+msgstr ""
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:61
+#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:104
+#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:105
+#: packages/web-util/src/forms/gana/personal-info.ts:39
+msgid "No"
+msgstr ""
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:68
+msgid "Provider"
+msgstr ""
+
+#. Translators: Button that retries loading the terms-of-service document.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:115
+msgid "Try again"
+msgstr ""
+
+#. Translators: Status shown while the terms-of-service PDF is downloading.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:117
+msgid "Downloading PDF…"
+msgstr ""
+
+#. Translators: Button that downloads the terms-of-service document as a PDF.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:119
+msgid "Download PDF"
+msgstr ""
+
+#. Translators: Button that closes the terms reader. It does not accept the
+#. terms.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:122
+msgid "Done"
+msgstr ""
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:199
+msgid "The terms are not available as Markdown or plain text."
+msgstr ""
+
+#. Translators: “terms” means the terms-of-service document, not words or
+#. terminology.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:204
+#: packages/web-util/src/forms/AcceptTosForm.tsx:282
+msgid "These terms are too large to display safely."
+msgstr ""
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:207
+msgid "The terms of service could not be loaded."
+msgstr ""
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:248
+msgid "Close terms of service"
+msgstr ""
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:260
+msgid "Loading terms of service…"
+msgstr ""
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:311
+msgid "The PDF could not be downloaded."
+msgstr ""
+
+#. Translators: %1$s is the name of the organization or service provider
+#. whose terms the user must review.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:414
+msgid "Read the terms provided by %1$s before recording your acceptance."
+msgstr ""
+
+#. Translators: Button that reopens a terms-of-service document the user has
+#. already viewed.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:419
+msgid "Read terms again"
+msgstr ""
+
+#. Translators: Button that opens the terms-of-service document in an in-app
+#. reader.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:422
+msgid "Read terms"
+msgstr ""
+
+#. Translators: The accepted version is the exact version of the
+#. terms-of-service document that was opened in the reader.
+#: packages/web-util/src/forms/AcceptTosForm.tsx:425
+msgid "Your acceptance applies to the version shown above."
+msgstr ""
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:439
+msgid "Review the terms of service"
+msgstr ""
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:444
+msgid "Read the terms before recording your acceptance."
+msgstr ""
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:484
+msgid "I have read and accept the terms of service"
+msgstr ""
+
+#: packages/web-util/src/forms/AcceptTosForm.tsx:494
+msgid "Open the terms before accepting them."
+msgstr ""
+
#: packages/web-util/src/forms/gana/challenger_email.ts:29
msgid "Email verification"
msgstr ""
@@ -386,13 +527,14 @@ msgid "Supplemental Files"
msgstr ""
#: packages/web-util/src/forms/gana/generic_note.ts:67
+#: packages/web-util/src/forms/gana/multi_upload.ts:61
#: packages/web-util/src/forms/gana/VQF_902_14.ts:102
#: packages/web-util/src/forms/gana/VQF_902_1_officer.ts:165
msgid "Description"
msgstr ""
#: packages/web-util/src/forms/gana/generic_note.ts:73
-#: packages/web-util/src/forms/gana/multi_upload.ts:61
+#: packages/web-util/src/forms/gana/multi_upload.ts:97
#: packages/web-util/src/forms/gana/VQF_902_14.ts:108
#: packages/web-util/src/forms/gana/VQF_902_1_officer.ts:171
#: packages/web-util/src/forms/gana/generic_upload.ts:43
@@ -407,7 +549,23 @@ msgstr ""
msgid "Upload multiple documents."
msgstr ""
-#: packages/web-util/src/forms/gana/multi_upload.ts:56
+#: packages/web-util/src/forms/gana/multi_upload.ts:43
+msgid "Requested documents"
+msgstr ""
+
+#: packages/web-util/src/forms/gana/multi_upload.ts:49
+msgid "Document identifier"
+msgstr ""
+
+#: packages/web-util/src/forms/gana/multi_upload.ts:55
+msgid "Title"
+msgstr ""
+
+#: packages/web-util/src/forms/gana/multi_upload.ts:67
+msgid "Required"
+msgstr ""
+
+#: packages/web-util/src/forms/gana/multi_upload.ts:92
#: packages/web-util/src/forms/gana/generic_upload.ts:38
msgid "Document upload (%1$s)"
msgstr ""
@@ -478,8 +636,8 @@ msgstr ""
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:30
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:31
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:30
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:28
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:31
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:29
msgid "Contracting partner"
msgstr ""
@@ -536,8 +694,8 @@ msgstr ""
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:68
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:69
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:46
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:44
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:47
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:45
msgid "Can't be empty"
msgstr ""
@@ -545,8 +703,8 @@ msgstr ""
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:77
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:108
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:288
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:54
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:52
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:55
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:53
msgid "Full name"
msgstr ""
@@ -567,33 +725,21 @@ msgid ""
"account/securities account?"
msgstr ""
-#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:100
-#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:101
-#: packages/web-util/src/forms/gana/personal-info.ts:35
-msgid "Yes"
-msgstr ""
-
-#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:104
-#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:105
-#: packages/web-util/src/forms/gana/personal-info.ts:39
-msgid "No"
-msgstr ""
-
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:112
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:121
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:113
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:125
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:481
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:490
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:104
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:113
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:105
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:114
msgid "Signature(s)"
msgstr ""
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:113
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:114
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:482
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:105
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:106
msgid ""
"It is a criminal offence to deliberately provide false information on this form "
"(article 251 of the Swiss Criminal Code, document forgery)"
@@ -602,7 +748,7 @@ msgstr ""
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:117
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:121
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:486
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:109
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:110
msgid ""
"The contracting partner hereby undertakes to inform automatically of any changes "
"to the information contained herein."
@@ -611,7 +757,7 @@ msgstr ""
#: packages/web-util/src/forms/gana/VQF_902_11_customer.ts:127
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:131
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:496
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:119
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:120
msgid "Date"
msgstr ""
@@ -620,24 +766,24 @@ msgid "Establishment of the controlling person (submitted by AML officer)"
msgstr ""
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:142
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:102
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:103
msgid "Signed Declaration"
msgstr ""
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:143
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:103
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:104
msgid "Signed declaration by the customer"
msgstr ""
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:150
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:107
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:108
msgid ""
"The uploaded document must contain the customer's signature on the beneficial "
"owner declaration."
msgstr ""
#: packages/web-util/src/forms/gana/VQF_902_11_officer.ts:154
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:111
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:112
msgid "Signed Document"
msgstr ""
@@ -725,8 +871,8 @@ msgstr ""
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:132
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:300
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:66
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:64
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:67
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:65
msgid "Date of birth"
msgstr ""
@@ -736,8 +882,8 @@ msgstr ""
#: packages/web-util/src/forms/gana/VQF_902_4.ts:102
#: packages/web-util/src/forms/gana/VQF_902_4.ts:159
#: packages/web-util/src/forms/gana/VQF_902_4.ts:398
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:75
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:73
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:76
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:74
msgid "invalid format"
msgstr ""
@@ -747,8 +893,8 @@ msgstr ""
#: packages/web-util/src/forms/gana/VQF_902_4.ts:105
#: packages/web-util/src/forms/gana/VQF_902_4.ts:162
#: packages/web-util/src/forms/gana/VQF_902_4.ts:401
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:78
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:76
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:79
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:77
msgid "it can't be in the future"
msgstr ""
@@ -758,15 +904,15 @@ msgstr ""
#: packages/web-util/src/forms/gana/VQF_902_4.ts:112
#: packages/web-util/src/forms/gana/VQF_902_4.ts:169
#: packages/web-util/src/forms/gana/VQF_902_4.ts:408
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:85
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:83
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:86
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:84
msgid "it can't be greater than 120 years"
msgstr ""
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:159
#: packages/web-util/src/forms/gana/VQF_902_1_customer.ts:327
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:92
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:90
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:93
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:91
msgid "Nationality"
msgstr ""
@@ -1514,27 +1660,30 @@ msgid "Other relevant information"
msgstr ""
#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:10
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:10
-msgid "Declaration of identity of the beneficial owner (A)"
+msgid "Declaration of identity of the beneficial owner (A) — customer"
+msgstr ""
+
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:11
+msgid "The customer completes the declaration directly in the form."
msgstr ""
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:23
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:21
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:24
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:22
msgid "Declaration of identity of the beneficial owner"
msgstr ""
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:37
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:35
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:38
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:36
msgid "Beneficial owner details"
msgstr ""
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:41
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:39
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:42
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:40
msgid "Beneficial owner(s)"
msgstr ""
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:42
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:40
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:43
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:41
msgid ""
"The person(s) listed below is/are the beneficial owner(s) of the assets involved "
"in the business relationship. If the contracting partner is also the sole "
@@ -1542,11 +1691,19 @@ msgid ""
"below"
msgstr ""
-#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:60
-#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:58
+#: packages/web-util/src/forms/gana/VQF_902_9_customer.ts:61
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:59
msgid "Domicile address"
msgstr ""
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:10
+msgid "Declaration of identity of the beneficial owner (A) — AML officer"
+msgstr ""
+
+#: packages/web-util/src/forms/gana/VQF_902_9_officer.ts:11
+msgid "The AML officer records the declaration and uploads the customer's signed PDF."
+msgstr ""
+
#: packages/web-util/src/forms/Calendar.tsx:56
msgid "January"
msgstr ""
@@ -1611,104 +1768,16 @@ msgstr ""
msgid "Next month"
msgstr ""
-#. Translators: Button that retries loading the terms-of-service document.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:56
-msgid "Try again"
-msgstr ""
-
-#. Translators: Status shown while the terms-of-service PDF is downloading.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:58
-msgid "Downloading PDF…"
-msgstr ""
-
-#. Translators: Button that downloads the terms-of-service document as a PDF.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:60
-msgid "Download PDF"
-msgstr ""
-
-#. Translators: Button that closes the terms reader. It does not accept the
-#. terms.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:63
-msgid "Done"
-msgstr ""
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:140
-msgid "The terms are not available as Markdown or plain text."
-msgstr ""
-
-#. Translators: “terms” means the terms-of-service document, not words or
-#. terminology.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:145
-#: packages/web-util/src/forms/AcceptTosForm.tsx:223
-msgid "These terms are too large to display safely."
-msgstr ""
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:148
-msgid "The terms of service could not be loaded."
-msgstr ""
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:189
-msgid "Close terms of service"
-msgstr ""
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:201
-msgid "Loading terms of service…"
-msgstr ""
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:252
-msgid "The PDF could not be downloaded."
-msgstr ""
-
-#. Translators: %1$s is the name of the organization or service provider
-#. whose terms the user must review.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:355
-msgid "Read the terms provided by %1$s before recording your acceptance."
-msgstr ""
-
-#. Translators: Button that reopens a terms-of-service document the user has
-#. already viewed.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:360
-msgid "Read terms again"
-msgstr ""
-
-#. Translators: Button that opens the terms-of-service document in an in-app
-#. reader.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:363
-msgid "Read terms"
-msgstr ""
-
-#. Translators: The accepted version is the exact version of the
-#. terms-of-service document that was opened in the reader.
-#: packages/web-util/src/forms/AcceptTosForm.tsx:366
-msgid "Your acceptance applies to the version shown above."
-msgstr ""
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:380
-msgid "Review the terms of service"
-msgstr ""
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:385
-msgid "Read the terms before recording your acceptance."
-msgstr ""
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:425
-msgid "I have read and accept the terms of service"
-msgstr ""
-
-#: packages/web-util/src/forms/AcceptTosForm.tsx:435
-msgid "Open the terms before accepting them."
-msgstr ""
-
-#: packages/web-util/src/forms/fields/InputSelectOne.tsx:82
+#: packages/web-util/src/forms/fields/InputSelectOne.tsx:85
msgid "Clear selection"
msgstr ""
-#: packages/web-util/src/forms/fields/InputSelectOne.tsx:170
+#: packages/web-util/src/forms/fields/InputSelectOne.tsx:173
msgid "Toggle choices"
msgstr ""
-#: packages/web-util/src/forms/fields/InputSelectOne.tsx:193
-#: packages/web-util/src/forms/fields/InputSelectMultiple.tsx:132
+#: packages/web-util/src/forms/fields/InputSelectOne.tsx:201
+#: packages/web-util/src/forms/fields/InputSelectMultiple.tsx:133
msgid "No element found"
msgstr ""
@@ -1737,10 +1806,13 @@ msgid "seconds"
msgstr ""
#: packages/web-util/src/forms/fields/InputDuration.tsx:339
-#: packages/web-util/src/forms/fields/InputDurationText.tsx:94
msgid "No expiration"
msgstr ""
+#: packages/web-util/src/forms/fields/InputDurationText.tsx:94
+msgid "Forever"
+msgstr ""
+
#: packages/web-util/src/forms/fields/InputFile.tsx:46
msgid "The selected file is too large."
msgstr ""
@@ -1749,23 +1821,23 @@ msgstr ""
msgid "The selected file could not be read."
msgstr ""
-#: packages/web-util/src/forms/fields/InputFile.tsx:99
+#: packages/web-util/src/forms/fields/InputFile.tsx:100
msgid "Upload a file"
msgstr ""
-#: packages/web-util/src/forms/fields/InputFile.tsx:153
+#: packages/web-util/src/forms/fields/InputFile.tsx:154
msgid "Clear"
msgstr ""
-#: packages/web-util/src/forms/fields/InputFile.tsx:162
+#: packages/web-util/src/forms/fields/InputFile.tsx:163
msgid "Download a copy."
msgstr ""
-#: packages/web-util/src/forms/fields/InputSelectMultiple.tsx:193
+#: packages/web-util/src/forms/fields/InputSelectMultiple.tsx:194
msgid "Remove"
msgstr ""
-#: packages/web-util/src/forms/forms-ui.tsx:344
+#: packages/web-util/src/forms/forms-ui.tsx:357
msgid "List of fields with errors"
msgstr ""
@@ -1790,7 +1862,7 @@ msgid "Delete"
msgstr ""
#: packages/web-util/src/forms/fields/InputArray.tsx:129
-#: packages/web-util/src/forms/fields/InputArray.tsx:315
+#: packages/web-util/src/forms/fields/InputArray.tsx:316
msgid "Add item"
msgstr ""
@@ -1803,19 +1875,35 @@ msgstr ""
msgid "Item %1$s"
msgstr ""
-#: packages/web-util/src/forms/fields/InputArray.tsx:282
+#: packages/web-util/src/forms/fields/InputArray.tsx:283
msgid "Edit %1$s"
msgstr ""
-#: packages/web-util/src/forms/fields/InputArray.tsx:289
+#: packages/web-util/src/forms/fields/InputArray.tsx:290
msgid "Edit"
msgstr ""
-#: packages/web-util/src/forms/index.ts:83
+#: packages/web-util/src/forms/index.ts:84
msgid "Simple comment"
msgstr ""
-#: packages/web-util/src/forms/index.ts:95
+#: packages/web-util/src/forms/index.ts:101
+msgid "Terms URL"
+msgstr ""
+
+#: packages/web-util/src/forms/index.ts:107
+msgid "Terms version"
+msgstr ""
+
+#: packages/web-util/src/forms/index.ts:113
+msgid "Provider name"
+msgstr ""
+
+#: packages/web-util/src/forms/index.ts:118
+msgid "Only show the external link"
+msgstr ""
+
+#: packages/web-util/src/forms/index.ts:124
msgid "Name and birthdate"
msgstr ""
@@ -1882,4 +1970,3 @@ msgstr ""
#: packages/web-util/src/components/NotificationBanner.test.tsx:113
msgid "Try again."
msgstr ""
-
diff --git a/packages/web-util/src/utils/buildPaginatedResult.test.tsx b/packages/web-util/src/utils/buildPaginatedResult.test.tsx
@@ -0,0 +1,59 @@
+/*
+ This file is part of GNU Taler
+ (C) 2026 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.
+*/
+
+import assert from "node:assert/strict";
+import test from "node:test";
+import { Window } from "happy-dom";
+import { h, render } from "preact";
+import { act } from "preact/test-utils";
+import { ListPointer, useListPointer } from "./buildPaginatedResult.js";
+
+test("list pointers track the current page", () => {
+ const window = new Window({ url: "https://pagination.example/" });
+ Object.defineProperty(globalThis, "window", {
+ configurable: true,
+ value: window,
+ });
+ Object.defineProperty(globalThis, "document", {
+ configurable: true,
+ value: window.document,
+ });
+ const container = document.createElement("div");
+ document.body.append(container);
+ let pointer: ListPointer | undefined;
+ let move:
+ | ((row: { id: string } | undefined, order: "asc" | "dec") => void)
+ | undefined;
+
+ function Harness() {
+ [pointer, move] = useListPointer((row: { id: string }) => row.id);
+ return <span>{pointer.page}</span>;
+ }
+
+ try {
+ act(() => render(<Harness />, container));
+ assert.equal(pointer?.page, 1);
+
+ act(() => move?.({ id: "20" }, "dec"));
+ assert.equal(pointer?.page, 2);
+
+ act(() => move?.({ id: "40" }, "dec"));
+ assert.equal(pointer?.page, 3);
+
+ act(() => move?.({ id: "21" }, "asc"));
+ assert.equal(pointer?.page, 2);
+
+ act(() => move?.(undefined, "dec"));
+ assert.equal(pointer?.page, 1);
+ } finally {
+ render(null, container);
+ container.remove();
+ window.close();
+ }
+});
diff --git a/packages/web-util/src/utils/buildPaginatedResult.ts b/packages/web-util/src/utils/buildPaginatedResult.ts
@@ -1,7 +1,8 @@
import { assertUnreachable, OperationOk } from "@gnu-taler/taler-util";
-import { useCallback, useState } from "preact/hooks";
+import { useCallback, useEffect, useState } from "preact/hooks";
export type PaginationControl = {
+ currentPage: number;
loadNext?(): void;
loadPrev?(): void;
loadFirst?(): void;
@@ -34,6 +35,7 @@ export function buildPaginatedResult<R>(
case: "ok",
body,
response: {} as any,
+ currentPage: offset.page,
loadNext: isLastPage
? undefined
: () => {
@@ -101,8 +103,12 @@ function __compute_for_ui<R>(data: Array<R>, offset: ListPointer, max: number) {
*
* If id is not set then assume the top most entry point.
*/
-export type ListPointer = { id?: string; order: "asc" | "dec" };
-const INITIAL_LIST_POINTER: ListPointer = { order: "dec" };
+export type ListPointer = {
+ id?: string;
+ order: "asc" | "dec";
+ page: number;
+};
+const INITIAL_LIST_POINTER: ListPointer = { order: "dec", page: 1 };
/**
*
@@ -111,14 +117,23 @@ const INITIAL_LIST_POINTER: ListPointer = { order: "dec" };
*/
export function useListPointer<T>(
getId: (d: T) => string,
+ queryIdentity?: string,
): [ListPointer, (p: T | undefined, order: ListPointer["order"]) => void] {
const [pointer, setPointer] = useState<ListPointer>(INITIAL_LIST_POINTER);
+ useEffect(() => {
+ setPointer(INITIAL_LIST_POINTER);
+ }, [queryIdentity]);
const movePointer = useCallback(
(d: T | undefined, order: ListPointer["order"]) => {
if (!d) {
setPointer(INITIAL_LIST_POINTER);
} else {
- setPointer({ order, id: getId(d) });
+ setPointer((current) => ({
+ order,
+ id: getId(d),
+ page:
+ order === "dec" ? current.page + 1 : Math.max(1, current.page - 1),
+ }));
}
},
[getId],
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
@@ -371,9 +371,6 @@ importers:
date-fns:
specifier: 2.29.3
version: 2.29.3
- history:
- specifier: 4.10.1
- version: 4.10.1
jed:
specifier: 1.1.1
version: 1.1.1
@@ -383,6 +380,9 @@ importers:
swr:
specifier: 2.2.2
version: 2.2.2(react@18.3.1)
+ wouter-preact:
+ specifier: ^3.7.1
+ version: 3.10.0(preact@10.11.3)
devDependencies:
'@gnu-taler/pogen':
specifier: workspace:*
@@ -393,9 +393,6 @@ importers:
'@types/chai':
specifier: ^4.3.0
version: 4.3.3
- '@types/history':
- specifier: ^4.7.8
- version: 4.7.11
'@types/node':
specifier: ^20.19.41
version: 20.19.41
@@ -408,6 +405,9 @@ importers:
esbuild:
specifier: ^0.28.0
version: 0.28.0
+ happy-dom:
+ specifier: 20.11.1
+ version: 20.11.1
postcss:
specifier: ^8.4.23
version: 8.4.49
@@ -7686,6 +7686,12 @@ snapshots:
word-wrap@1.2.5: {}
+ wouter-preact@3.10.0(preact@10.11.3):
+ dependencies:
+ mitt: 3.0.1
+ preact: 10.11.3
+ regexparam: 3.0.0
+
wouter-preact@3.10.0(preact@10.29.8):
dependencies:
mitt: 3.0.1