diff --git a/src/renderer/components/Sidebar.test.tsx b/src/renderer/components/Sidebar.test.tsx
index 92f076c27..a091c6130 100644
--- a/src/renderer/components/Sidebar.test.tsx
+++ b/src/renderer/components/Sidebar.test.tsx
@@ -271,6 +271,41 @@ describe('Sidebar', () => {
expect(screen.queryByText('0')).not.toBeInTheDocument();
});
+ it('caps Remote pending-offer badge at 99+ with matching aria', () => {
+ render(
+ ,
+ );
+ expect(screen.getByText('99+')).toBeInTheDocument();
+ expect(
+ screen.getByRole('tab', { name: '99+ pending inbound file offers' }),
+ ).toBeInTheDocument();
+ });
+
+ it('has no axe violations when Remote pending-offer badge shows', async () => {
+ render(
+ ,
+ );
+ const badge = screen.getByText('2');
+ hydrateAxeThemeColors(badge);
+ expect(await axe(badge)).toHaveNoViolations();
+ });
+
it('hides RRC unread badge when rrcUnread is 0', () => {
const onChange = vi.fn();
render(
diff --git a/src/renderer/components/Sidebar.tsx b/src/renderer/components/Sidebar.tsx
index f509aa838..c723c2408 100644
--- a/src/renderer/components/Sidebar.tsx
+++ b/src/renderer/components/Sidebar.tsx
@@ -80,9 +80,9 @@ export default function Sidebar({
const showBadge = showChatBadge || showRoomsBadge || showRrcBadge || showRemoteBadge;
const tabAriaLabel = showBadge
? showRemoteBadge
- ? t('reticulumRemote.transfer.pendingOffersBadgeAria', {
- count: badgeCount > 99 ? 99 : badgeCount,
- })
+ ? badgeCount > 99
+ ? t('reticulumRemote.transfer.pendingOffersBadgeAriaCapped')
+ : t('reticulumRemote.transfer.pendingOffersBadgeAria', { count: badgeCount })
: t('aria.tabWithUnread', {
label: displayLabel,
count: badgeCount > 99 ? '99+' : badgeCount,
@@ -120,7 +120,7 @@ export default function Sidebar({
{showBadge && (
{badgeCount > 99 ? '99+' : badgeCount}
diff --git a/src/renderer/components/remote/ChatDmRncpOfferBanner.test.tsx b/src/renderer/components/remote/ChatDmRncpOfferBanner.test.tsx
index a3118cf8d..2cd80bc98 100644
--- a/src/renderer/components/remote/ChatDmRncpOfferBanner.test.tsx
+++ b/src/renderer/components/remote/ChatDmRncpOfferBanner.test.tsx
@@ -1,7 +1,9 @@
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { beforeEach, describe, expect, it, vi } from 'vitest';
+import { axe } from 'vitest-axe';
+import { hydrateAxeThemeColors } from '@/renderer/lib/a11yTestHelpers';
import { useReticulumIdentityActivityStore } from '@/renderer/stores/reticulumIdentityActivityStore';
import { useRncpTransferStore } from '@/renderer/stores/rncpTransferStore';
@@ -52,11 +54,13 @@ describe('ChatDmRncpOfferBanner', () => {
});
const user = userEvent.setup();
- render();
+ const { container } = render();
expect(screen.getByText('Incoming file offers')).toBeInTheDocument();
expect(screen.getByText('photo.jpg')).toBeInTheDocument();
expect(screen.queryByText('other.txt')).not.toBeInTheDocument();
+ hydrateAxeThemeColors(container);
+ expect(await axe(container)).toHaveNoViolations();
await user.click(screen.getByRole('button', { name: 'Accept photo.jpg' }));
expect(window.electronAPI.reticulum.rncp.accept).toHaveBeenCalledWith({ transfer_id: 't1' });
diff --git a/src/renderer/components/remote/RemoteTransferSection.test.tsx b/src/renderer/components/remote/RemoteTransferSection.test.tsx
index 2ba7e731b..a0ef17439 100644
--- a/src/renderer/components/remote/RemoteTransferSection.test.tsx
+++ b/src/renderer/components/remote/RemoteTransferSection.test.tsx
@@ -273,6 +273,10 @@ describe('RemoteTransferSection', () => {
expect(window.electronAPI.reticulum.rncp.send).not.toHaveBeenCalled();
expect(sendRncpRequestEnable).not.toHaveBeenCalled();
expect(useRncpTransferStore.getState().transfers.get('failed-2')?.retryCount).toBe(0);
+ expect(addToast).toHaveBeenCalledWith(
+ 'No path to their file receive destination; file receiving may be off. Ask them to enable rncp receive and send their hash, then try again.',
+ 'error',
+ );
});
it('sends when the receive dest is reachable', async () => {
diff --git a/src/renderer/components/remote/RemoteTransferSection.tsx b/src/renderer/components/remote/RemoteTransferSection.tsx
index aca29b31a..2e85b9cc0 100644
--- a/src/renderer/components/remote/RemoteTransferSection.tsx
+++ b/src/renderer/components/remote/RemoteTransferSection.tsx
@@ -106,8 +106,12 @@ export function RemoteTransferSection({
lxmfPeerHash: resolveLxmfPeerHash(destinationHash),
});
if (reach.status === 'reachable') return true;
- if (reach.status === 'listenerLikelyOff' && opts.promptEnable) {
- setEnableRequestConfirmOpen(true);
+ if (reach.status === 'listenerLikelyOff') {
+ if (opts.promptEnable) {
+ setEnableRequestConfirmOpen(true);
+ } else {
+ addToast(t('reticulumRemote.transfer.listenerLikelyOffToast'), 'error');
+ }
return false;
}
addToast(t('reticulumRemote.transfer.peerUnreachable'), 'error');
diff --git a/src/renderer/components/remote/RncpEnableRequestModal.test.tsx b/src/renderer/components/remote/RncpEnableRequestModal.test.tsx
index 5a1a73ca5..cc83e1937 100644
--- a/src/renderer/components/remote/RncpEnableRequestModal.test.tsx
+++ b/src/renderer/components/remote/RncpEnableRequestModal.test.tsx
@@ -14,6 +14,10 @@ vi.mock('@/renderer/components/Toast', () => ({
useToast: () => ({ addToast }),
}));
+vi.mock('@/renderer/lib/reticulum/reticulumSidecarReads', () => ({
+ probeReticulumPeer: vi.fn().mockResolvedValue({ ok: false }),
+}));
+
describe('RncpEnableRequestModal', () => {
beforeEach(() => {
addToast.mockReset();
@@ -108,4 +112,67 @@ describe('RncpEnableRequestModal', () => {
});
expect(useRncpEnableRequestStore.getState().prompts).toHaveLength(0);
});
+
+ it('auto-dismisses a repeat enable-request while already listening', async () => {
+ vi.mocked(window.electronAPI.reticulum.rncp.getListener).mockResolvedValue({
+ enabled: true,
+ inbound_mode: 'ask',
+ allowed: [],
+ blocked: [],
+ });
+ const { rerender } = render();
+ await waitFor(() => {
+ expect(useRncpEnableRequestStore.getState().prompts).toHaveLength(0);
+ });
+
+ useRncpEnableRequestStore.getState().enqueue({
+ peerHash: 'a'.repeat(32),
+ peerLabel: 'Alice',
+ receivedAt: Date.now(),
+ });
+ rerender();
+ await waitFor(() => {
+ expect(useRncpEnableRequestStore.getState().prompts).toHaveLength(0);
+ });
+ expect(
+ vi.mocked(window.electronAPI.reticulum.proxyPost).mock.calls.length,
+ ).toBeGreaterThanOrEqual(2);
+ });
+
+ it('enables Ask and still shares when Always allow cannot resolve identity', async () => {
+ vi.mocked(window.electronAPI.reticulum.rncp.getListener)
+ .mockResolvedValueOnce({
+ enabled: false,
+ inbound_mode: 'off',
+ allowed: [],
+ blocked: [],
+ })
+ .mockResolvedValue({
+ enabled: true,
+ inbound_mode: 'ask',
+ allowed: [],
+ blocked: [],
+ });
+ const user = userEvent.setup();
+ render();
+ await user.click(
+ screen.getByRole('button', {
+ name: 'Enable inbound file offers and allow this sender',
+ }),
+ );
+ await waitFor(() => {
+ expect(addToast).toHaveBeenCalledWith('File receiving is enabled.', 'success');
+ });
+ expect(addToast).toHaveBeenCalledWith(
+ expect.stringContaining('identity hash is not known yet'),
+ 'info',
+ );
+ await waitFor(() => {
+ expect(window.electronAPI.reticulum.proxyPost).toHaveBeenCalledWith('/api/v1/lxmf/send', {
+ destination_hash: 'a'.repeat(32),
+ text: expect.stringContaining(`${RNCP_RECEIVE_DEST_SHARE_PREFIX}${'c'.repeat(32)}`),
+ });
+ });
+ expect(useRncpEnableRequestStore.getState().prompts).toHaveLength(0);
+ });
});
diff --git a/src/renderer/components/remote/RncpEnableRequestModal.tsx b/src/renderer/components/remote/RncpEnableRequestModal.tsx
index d110bae6a..49b809776 100644
--- a/src/renderer/components/remote/RncpEnableRequestModal.tsx
+++ b/src/renderer/components/remote/RncpEnableRequestModal.tsx
@@ -1,12 +1,14 @@
-import { useCallback, useEffect, useRef } from 'react';
+import { useCallback, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { useToast } from '@/renderer/components/Toast';
import { errLikeToLogString } from '@/renderer/lib/errLikeToLogString';
import { rememberRncpListenerDirs } from '@/renderer/lib/pushRncpListenerPolicy';
+import { probeReticulumPeer } from '@/renderer/lib/reticulum/reticulumSidecarReads';
import { policiesToRncpLists } from '@/renderer/lib/rncpInboundPolicyLists';
import { useReticulumIdentityActivityStore } from '@/renderer/stores/reticulumIdentityActivityStore';
import { useReticulumInboundPolicyStore } from '@/renderer/stores/reticulumInboundPolicyStore';
+import { useReticulumRemoteAddressStore } from '@/renderer/stores/reticulumRemoteAddressStore';
import { useRncpEnableRequestStore } from '@/renderer/stores/rncpEnableRequestStore';
import { useRncpTransferStore } from '@/renderer/stores/rncpTransferStore';
import { canonicalizeReticulumDestinationHash } from '@/shared/reticulumDestinationHash';
@@ -16,19 +18,40 @@ import { buildRncpReceiveDestShareBody } from '@/shared/rncpRequestEnable';
* Resolve a Reticulum **identity** hash for an LXMF delivery destination hash.
* rncp LinkIdentify gates on identity_hash, which is not the LXMF sender dest.
*/
-async function resolveIdentityHashForLxmfPeer(peerDestHash: string): Promise {
+export async function resolveIdentityHashForLxmfPeer(peerDestHash: string): Promise {
const dest = canonicalizeReticulumDestinationHash(peerDestHash);
if (!dest) return null;
+
+ const fromRows = (rows: { identity_hash?: string | null }[]): string | null => {
+ for (const row of rows) {
+ const id = row.identity_hash ? canonicalizeReticulumDestinationHash(row.identity_hash) : null;
+ if (id) return id;
+ }
+ return null;
+ };
+
const store = useReticulumIdentityActivityStore.getState();
let rows = store.getActivity(dest);
if (rows.length === 0) {
rows = await store.loadForDestination(dest);
}
- for (const row of rows) {
- const id = row.identity_hash ? canonicalizeReticulumDestinationHash(row.identity_hash) : null;
+ const fromActivity = fromRows(rows);
+ if (fromActivity) return fromActivity;
+
+ const saved = useReticulumRemoteAddressStore.getState().findByLxmfPeer(dest);
+ if (saved?.identity_hash) {
+ const id = canonicalizeReticulumDestinationHash(saved.identity_hash);
if (id) return id;
}
- return null;
+
+ // Path/probe can surface announce identity for peers we have only chatted with.
+ try {
+ await probeReticulumPeer(dest);
+ } catch {
+ // catch-no-log-ok probe is best-effort before allow-list upsert
+ }
+ rows = await store.loadForDestination(dest);
+ return fromRows(rows);
}
/**
@@ -92,14 +115,12 @@ export function RncpEnableRequestModal() {
const setListener = useRncpTransferStore((s) => s.setListener);
const current = prompts[0] ?? null;
- const autoSharedPeerRef = useRef(null);
- // If inbound rncp is already enabled, re-share our receive dest immediately so the
- // requester does not stay empty when the peer thinks they are "already enabled".
+ // Already listening: re-share dest and clear the prompt so repeat enable-requests
+ // from the same peer do not leave a sticky modal (do not latch a one-shot peer ref).
useEffect(() => {
if (!current) return;
const peerHash = current.peerHash;
- if (autoSharedPeerRef.current === peerHash) return;
let cancelled = false;
void (async () => {
try {
@@ -107,18 +128,20 @@ export function RncpEnableRequestModal() {
if (cancelled) return;
setListener(status);
if (!status?.enabled) return;
- autoSharedPeerRef.current = peerHash;
- const shareResult = await shareRncpReceiveDestWithPeer(
+ await shareRncpReceiveDestWithPeer(
peerHash,
t('reticulumRemote.enableRequest.lxmfShareBody'),
);
- if (!cancelled && shareResult === 'shared') {
+ if (!cancelled) {
dismiss(peerHash, false);
}
} catch (e) {
console.debug(
'[RncpEnableRequestModal] already-enabled auto-share ' + errLikeToLogString(e),
);
+ if (!cancelled) {
+ dismiss(peerHash, false);
+ }
}
})();
return () => {
@@ -139,9 +162,7 @@ export function RncpEnableRequestModal() {
let identityHash: string | null = null;
if (allowIdentity) {
identityHash = await resolveIdentityHashForLxmfPeer(current.peerHash);
- if (!identityHash) {
- addToast(t('reticulumRemote.enableRequest.identityUnknown'), 'info');
- } else {
+ if (identityHash) {
await upsertPolicy({
identity_hash: identityHash,
decision: 'allow',
@@ -177,6 +198,9 @@ export function RncpEnableRequestModal() {
const listener = await window.electronAPI.reticulum.rncp.getListener();
useRncpTransferStore.getState().setListener(listener);
addToast(t('reticulumRemote.enableRequest.enabled'), 'success');
+ if (allowIdentity && !identityHash) {
+ addToast(t('reticulumRemote.enableRequest.identityUnknown'), 'info');
+ }
const peerHash = current.peerHash;
dismiss(peerHash, false);
// Best-effort: tell the requester our rncp.receive dest so they can autofill.
diff --git a/src/renderer/lib/sendRncpRequestEnable.test.ts b/src/renderer/lib/sendRncpRequestEnable.test.ts
index 067efcf1b..68acc7de4 100644
--- a/src/renderer/lib/sendRncpRequestEnable.test.ts
+++ b/src/renderer/lib/sendRncpRequestEnable.test.ts
@@ -26,12 +26,12 @@ describe('sendRncpRequestEnable', () => {
expect(window.electronAPI.reticulum.proxyPost).not.toHaveBeenCalled();
});
- it('posts destination_hash and text (sidecar field name) with sentinel', async () => {
+ it('posts destination_hash and text with human body plus sentinel', async () => {
const hash = 'ab'.repeat(16);
await expect(sendRncpRequestEnable(hash)).resolves.toEqual({ ok: true });
expect(window.electronAPI.reticulum.proxyPost).toHaveBeenCalledWith('/api/v1/lxmf/send', {
destination_hash: hash,
- text: expect.stringContaining(RNCP_REQUEST_ENABLE_SENTINEL),
+ text: `reticulumRemote.enableRequest.lxmfBody\n\n${RNCP_REQUEST_ENABLE_SENTINEL}`,
});
});
diff --git a/src/renderer/locales/cs/translation.json b/src/renderer/locales/cs/translation.json
index b91b65396..37c03e7b9 100644
--- a/src/renderer/locales/cs/translation.json
+++ b/src/renderer/locales/cs/translation.json
@@ -4886,8 +4886,10 @@
"peerUnreachable": "Žádná cesta k tomuto cíli. Partner může být offline.",
"checkingReachability": "Kontrola dosažitelnosti…",
"listenerLikelyOffTitle": "Příjem souborů může být vypnutý",
- "listenerLikelyOffBody": "Žádná cesta k cílovému umístění jejich souboru, ale hledají online chat. Požádejte je, aby povolili příjem souborů (Vzdálené → Nastavení → Nabídky příchozích souborů), a zkuste to znovu.",
- "listenerLikelyOffConfirm": "Odeslat požadavek na povolení"
+ "listenerLikelyOffConfirm": "Odeslat požadavek na povolení",
+ "pendingOffersBadgeAriaCapped": "99+ čekajících nabídek příchozích souborů",
+ "listenerLikelyOffBody": "Žádná cesta k cílovému umístění jejich souboru, ale hledají online chat. Požádejte je, aby povolili příjem souborů rncp a odeslali svůj hash pro příjem rncp, pak to zkuste znovu.",
+ "listenerLikelyOffToast": "Žádná cesta k cíli příjmu jejich souboru; příjem souborů může být vypnutý. Požádejte je, aby povolili rncp přijímat a odesílat svůj hash, a zkuste to znovu."
},
"enableRequest": {
"title": "Povolit příjem souborů?",
@@ -4903,10 +4905,10 @@
"enabled": "Příjem souboru je povolen.",
"enableFailed": "Nelze povolit příjem souboru: {{error}}",
"saveDirRequired": "Chcete-li povolit příjem, vyberte složku pro uložení.",
- "identityUnknown": "Hash identity tohoto peera se zatím nepodařilo zjistit — příchozí dotazování je povoleno, ale peer nebyl přidán na seznam povolených. Zkuste to znovu, až dorazí cesta nebo oznámení.",
- "lxmfShareBody": "Příjem souborů je povolen. Zde je můj rncp receive destination (mesh-client jej pro vás uloží).",
"shareDestWarning": "Pokud povolíte, mesh-client odešle váš cíl příjmu rncp tomuto partnerovi, aby mohl automaticky vyplnit soubor.",
- "lxmfBody": "Povolte příjem rncp (Vzdálené → Nastavení → Nabídky příchozích souborů) a pošlete mi svůj hash pro příjem rncp."
+ "lxmfBody": "Povolte příjem souboru rncp a odpovězte pomocí cílového hash pro příjem rncp.",
+ "lxmfShareBody": "Příjem souborů je povolen. Můj rncp přijímá cílový hash:",
+ "identityUnknown": "Příchozí dotaz je zapnutý, ale hash identity tohoto partnera zatím není znám, takže nebyl přidán do Vždy povolit. Před každým souborem budete stále dotázáni; zkuste Vždy znovu povolit po příchodu cesty nebo oznámení."
},
"saved": {
"labelPlaceholder": "Označení",
diff --git a/src/renderer/locales/de/translation.json b/src/renderer/locales/de/translation.json
index 126dd4d34..eafa1a885 100644
--- a/src/renderer/locales/de/translation.json
+++ b/src/renderer/locales/de/translation.json
@@ -4884,8 +4884,10 @@
"peerUnreachable": "Kein Weg zu diesem Ziel. Der Peer ist möglicherweise offline.",
"checkingReachability": "Erreichbarkeit prüfen…",
"listenerLikelyOffTitle": "Möglicherweise ist der Dateiempfang deaktiviert",
- "listenerLikelyOffBody": "Kein Pfad zu ihrem Dateiempfangsziel, aber sie suchen online nach Chat. Bitten Sie sie, den Dateiempfang zu aktivieren (Remote → Einstellungen → Angebote für eingehende Dateien) und versuchen Sie es dann erneut.",
- "listenerLikelyOffConfirm": "Aktivierungsanfrage senden"
+ "listenerLikelyOffConfirm": "Aktivierungsanfrage senden",
+ "pendingOffersBadgeAriaCapped": "Über 99 ausstehende Angebote für eingehende Dateien",
+ "listenerLikelyOffBody": "Kein Pfad zu ihrem Dateiempfangsziel, aber sie suchen online nach Chat. Bitten Sie sie, den Empfang von RNCP-Dateien zu aktivieren und ihren RNCP-Empfangs-Hash zu senden, und versuchen Sie es dann erneut.",
+ "listenerLikelyOffToast": "Kein Pfad zu ihrem Dateiempfangsziel; Der Dateiempfang ist möglicherweise deaktiviert. Bitten Sie sie, den RNCP-Empfang und das Senden ihres Hashs zu aktivieren, und versuchen Sie es dann erneut."
},
"enableRequest": {
"title": "Dateiempfang aktivieren?",
@@ -4901,10 +4903,10 @@
"enabled": "Der Dateiempfang ist aktiviert.",
"enableFailed": "Dateiempfang konnte nicht aktiviert werden: {{error}}",
"saveDirRequired": "Wählen Sie einen Speicherordner aus, um den Empfang zu aktivieren.",
- "identityUnknown": "Der Identitäts-Hash dieses Peers konnte noch nicht aufgelöst werden — eingehendes Nachfragen ist aktiviert, aber der Peer wurde nicht zur Erlaubnisliste hinzugefügt. Versuche es erneut, sobald ein Pfad oder ein Announce eintrifft.",
- "lxmfShareBody": "Dateiempfang ist aktiviert. Hier ist mein rncp-Empfangsziel (mesh-client speichert es für Sie).",
"shareDestWarning": "Wenn Sie diese Option aktivieren, sendet der Mesh-Client Ihr RNCP-Empfangsziel an diesen Peer, damit dieser den Dateiversand automatisch ausfüllen kann.",
- "lxmfBody": "Bitte aktivieren Sie den rncp-Empfang (Remote → Einstellungen → Angebote für eingehende Dateien) und senden Sie mir Ihren rncp-Empfangs-Hash."
+ "lxmfBody": "Bitte aktivieren Sie den Empfang von RNCP-Dateien und antworten Sie mit Ihrem RNCP-Empfangsziel-Hash.",
+ "lxmfShareBody": "Der Dateiempfang ist aktiviert. Mein RNCP-Empfangsziel-Hash:",
+ "identityUnknown": "„Eingehende Anfragen“ ist aktiviert, aber der Identitäts-Hash dieses Peers ist noch nicht bekannt, sodass er nicht zu „Immer zulassen“ hinzugefügt wurde. Sie werden weiterhin vor jeder Datei gefragt; Versuchen Sie „Immer zulassen“ erneut, nachdem ein Pfad oder eine Ankündigung eintrifft."
},
"saved": {
"labelPlaceholder": "Etikett",
diff --git a/src/renderer/locales/en/translation.json b/src/renderer/locales/en/translation.json
index 344af3718..24287d448 100644
--- a/src/renderer/locales/en/translation.json
+++ b/src/renderer/locales/en/translation.json
@@ -4685,6 +4685,7 @@
"pendingOffersTitle": "Pending inbound files",
"pendingOffersBadgeAria_one": "{{count}} pending inbound file offer",
"pendingOffersBadgeAria_other": "{{count}} pending inbound file offers",
+ "pendingOffersBadgeAriaCapped": "99+ pending inbound file offers",
"offerLabel": "{{file}} ({{bytes}})",
"acceptAria": "Accept {{file}}",
"accept": "Accept",
@@ -4744,8 +4745,9 @@
"peerUnreachable": "No path to that destination. The peer may be offline.",
"checkingReachability": "Checking reachability…",
"listenerLikelyOffTitle": "File receiving may be off",
- "listenerLikelyOffBody": "No path to their file receive destination, but they look online for chat. Ask them to enable file receiving (Remote → Settings → Inbound file offers), then try again.",
+ "listenerLikelyOffBody": "No path to their file receive destination, but they look online for chat. Ask them to enable rncp file receiving and send their rncp receive hash, then try again.",
"listenerLikelyOffConfirm": "Send enable request",
+ "listenerLikelyOffToast": "No path to their file receive destination; file receiving may be off. Ask them to enable rncp receive and send their hash, then try again.",
"offerToast": "Incoming file offer: {{file}}",
"copyInstructionsAria": "Copy instructions for enabling file receive",
"copyInstructions": "Copy instructions",
@@ -4768,9 +4770,9 @@
"enabled": "File receiving is enabled.",
"enableFailed": "Could not enable file receiving: {{error}}",
"saveDirRequired": "Choose a save folder to enable receiving.",
- "identityUnknown": "Could not resolve this peer's identity hash yet — inbound Ask is enabled, but they were not added to the allow list. Try again after a path or announce arrives.",
- "lxmfBody": "Please enable rncp receive (Remote → Settings → Inbound file offers) and send me your rncp receive hash.",
- "lxmfShareBody": "File receiving is enabled. Here is my rncp receive destination (mesh-client will save it for you)."
+ "identityUnknown": "Inbound Ask is on, but this peer's identity hash is not known yet so they were not added to Always allow. You will still be asked before each file; try Always allow again after a path or announce arrives.",
+ "lxmfBody": "Please enable rncp file receiving and reply with your rncp receive destination hash.",
+ "lxmfShareBody": "File receiving is enabled. My rncp receive destination hash:"
},
"saved": {
"labelPlaceholder": "Label",
diff --git a/src/renderer/locales/es/translation.json b/src/renderer/locales/es/translation.json
index a7f2958f7..caebb1ea1 100644
--- a/src/renderer/locales/es/translation.json
+++ b/src/renderer/locales/es/translation.json
@@ -4884,8 +4884,10 @@
"peerUnreachable": "No hay camino hacia ese destino. Es posible que el interlocutor esté desconectado.",
"checkingReachability": "Comprobando accesibilidad...",
"listenerLikelyOffTitle": "La recepción de archivos puede estar desactivada",
- "listenerLikelyOffBody": "No hay ruta al destino de recepción de su archivo, pero buscan chat en línea. Pídales que habiliten la recepción de archivos (Remoto → Configuración → Ofertas de archivos entrantes) y luego vuelva a intentarlo.",
- "listenerLikelyOffConfirm": "Enviar solicitud de habilitación"
+ "listenerLikelyOffConfirm": "Enviar solicitud de habilitación",
+ "pendingOffersBadgeAriaCapped": "Más de 99 ofertas de archivos entrantes pendientes",
+ "listenerLikelyOffBody": "No hay ruta al destino de recepción de su archivo, pero buscan chat en línea. Pídales que habiliten la recepción de archivos rncp y envíen su hash de recepción rncp, luego vuelva a intentarlo.",
+ "listenerLikelyOffToast": "No hay ruta al destino de recepción de su archivo; La recepción de archivos puede estar desactivada. Pídales que habiliten rncp para recibir y enviar su hash, luego intente nuevamente."
},
"enableRequest": {
"title": "¿Habilitar la recepción de archivos?",
@@ -4901,10 +4903,10 @@
"enabled": "La recepción de archivos está habilitada.",
"enableFailed": "No se ha podido habilitar la recepción de archivos: {{error}}",
"saveDirRequired": "Elija una carpeta de guardado para habilitar la recepción.",
- "identityUnknown": "Aún no se pudo resolver el hash de identidad de este par — el modo Preguntar está activado, pero no se añadió a la lista de permitidos. Inténtalo de nuevo cuando llegue una ruta o un anuncio.",
- "lxmfShareBody": "La recepción de archivos está habilitada. Aquí está mi destino de recepción rncp (mesh-client lo guardará para usted).",
"shareDestWarning": "Si lo habilita, mesh-client enviará su destino de recepción rncp a este par para que pueda completar automáticamente el envío del archivo.",
- "lxmfBody": "Habilite la recepción de rncp (Remoto → Configuración → Ofertas de archivos entrantes) y envíeme su hash de recepción de rncp."
+ "lxmfBody": "Habilite la recepción de archivos rncp y responda con su hash de destino de recepción rncp.",
+ "lxmfShareBody": "La recepción de archivos está habilitada. Mi rncp recibe el hash de destino:",
+ "identityUnknown": "La pregunta entrante está activada, pero aún no se conoce el hash de identidad de este par, por lo que no se agregaron a Permitir siempre. Aún se le preguntará antes de cada archivo; Intente Permitir siempre nuevamente después de que llegue una ruta o un anuncio."
},
"saved": {
"labelPlaceholder": "Designación",
diff --git a/src/renderer/locales/fr/translation.json b/src/renderer/locales/fr/translation.json
index 5354a5413..91cdd051f 100644
--- a/src/renderer/locales/fr/translation.json
+++ b/src/renderer/locales/fr/translation.json
@@ -4884,8 +4884,10 @@
"peerUnreachable": "Aucun chemin vers cette destination. L'homologue est peut-être hors ligne.",
"checkingReachability": "Vérification de l'accessibilité…",
"listenerLikelyOffTitle": "La réception de fichiers est peut-être désactivée",
- "listenerLikelyOffBody": "Aucun chemin vers la destination de réception de leur fichier, mais ils recherchent en ligne pour discuter. Demandez-leur d'activer la réception de fichiers (À distance → Paramètres → Offres de fichiers entrants), puis réessayez.",
- "listenerLikelyOffConfirm": "Envoyer une demande d'activation"
+ "listenerLikelyOffConfirm": "Envoyer une demande d'activation",
+ "pendingOffersBadgeAriaCapped": "Plus de 99 offres de fichiers entrants en attente",
+ "listenerLikelyOffBody": "Aucun chemin vers la destination de réception de leur fichier, mais ils recherchent en ligne pour discuter. Demandez-leur d'activer la réception de fichiers rncp et d'envoyer leur hachage de réception rncp, puis réessayez.",
+ "listenerLikelyOffToast": "Aucun chemin vers leur destination de réception de fichier ; la réception du fichier est peut-être désactivée. Demandez-leur d'activer la réception et l'envoi de leur hachage par RNCP, puis réessayez."
},
"enableRequest": {
"title": "Activer la réception de fichiers ?",
@@ -4901,10 +4903,10 @@
"enabled": "La réception de fichiers est activée.",
"enableFailed": "Impossible d'activer la réception du fichier : {{error}}",
"saveDirRequired": "Choisissez un dossier de sauvegarde pour activer la réception.",
- "identityUnknown": "Impossible de résoudre le hachage d'identité de ce pair pour le moment — le mode Demander est activé, mais il n'a pas été ajouté à la liste d'autorisation. Réessayez après l'arrivée d'un chemin ou d'une annonce.",
- "lxmfShareBody": "La réception de fichiers est activée. Voici ma destination de réception rncp (mesh-client l'enregistrera pour vous).",
"shareDestWarning": "Si vous l'activez, mesh-client enverra votre destination de réception rncp à cet homologue afin qu'il puisse remplir automatiquement l'envoi de fichiers.",
- "lxmfBody": "Veuillez activer la réception rncp (À distance → Paramètres → Offres de fichiers entrants) et envoyez-moi votre hachage de réception rncp."
+ "lxmfBody": "Veuillez activer la réception de fichiers RNCP et répondre avec votre hachage de destination de réception RNCP.",
+ "lxmfShareBody": "La réception de fichiers est activée. Mon rncp reçoit le hachage de destination :",
+ "identityUnknown": "La demande entrante est activée, mais le hachage d'identité de cet homologue n'est pas encore connu et n'a donc pas été ajouté à Toujours autoriser. Il vous sera toujours demandé avant chaque dossier ; essayez Toujours autoriser à nouveau après l'arrivée d'un chemin ou d'une annonce."
},
"saved": {
"labelPlaceholder": "Dénomination",
diff --git a/src/renderer/locales/id/translation.json b/src/renderer/locales/id/translation.json
index 66640ee78..91304c0df 100644
--- a/src/renderer/locales/id/translation.json
+++ b/src/renderer/locales/id/translation.json
@@ -4884,8 +4884,10 @@
"peerUnreachable": "Tidak ada jalan menuju tujuan itu. Rekan tersebut mungkin sedang offline.",
"checkingReachability": "Memeriksa jangkauan…",
"listenerLikelyOffTitle": "Penerimaan file mungkin tidak aktif",
- "listenerLikelyOffBody": "Tidak ada jalur ke tujuan penerimaan file mereka, tetapi mereka mencari obrolan online. Minta mereka untuk mengaktifkan penerimaan file (Jarak Jauh → Pengaturan → Penawaran file masuk), lalu coba lagi.",
- "listenerLikelyOffConfirm": "Kirim permintaan pengaktifan"
+ "listenerLikelyOffConfirm": "Kirim permintaan pengaktifan",
+ "pendingOffersBadgeAriaCapped": "99+ penawaran file masuk yang tertunda",
+ "listenerLikelyOffBody": "Tidak ada jalur ke tujuan penerimaan file mereka, tetapi mereka mencari obrolan online. Minta mereka untuk mengaktifkan penerimaan file rncp dan mengirimkan hash penerimaan rncp mereka, lalu coba lagi.",
+ "listenerLikelyOffToast": "Tidak ada jalur ke tujuan penerimaan file mereka; penerimaan file mungkin tidak aktif. Minta mereka untuk mengaktifkan rncp menerima dan mengirim hash mereka, lalu coba lagi."
},
"enableRequest": {
"title": "Aktifkan penerimaan file?",
@@ -4901,10 +4903,10 @@
"enabled": "Penerimaan file diaktifkan.",
"enableFailed": "Tidak dapat mengaktifkan penerimaan file: {{error}}",
"saveDirRequired": "Pilih folder penyimpanan untuk mengaktifkan penerimaan.",
- "identityUnknown": "Hash identitas peer ini belum dapat ditentukan — mode Tanya untuk file masuk sudah aktif, tetapi peer belum ditambahkan ke daftar izin. Coba lagi setelah jalur atau pengumuman diterima.",
- "lxmfShareBody": "Penerimaan file diaktifkan. Ini tujuan penerimaan rncp saya (mesh-client akan menyimpannya untuk Anda).",
"shareDestWarning": "Jika Anda mengaktifkannya, mesh-client akan mengirimkan tujuan penerimaan rncp Anda ke rekan ini sehingga mereka dapat mengisi otomatis pengiriman file.",
- "lxmfBody": "Harap aktifkan penerimaan rncp (Jarak Jauh → Pengaturan → Penawaran file masuk) dan kirimkan saya hash penerimaan rncp Anda."
+ "lxmfBody": "Harap aktifkan penerimaan file rncp dan balas dengan hash tujuan penerimaan rncp Anda.",
+ "lxmfShareBody": "Penerimaan file diaktifkan. Rncp saya menerima hash tujuan:",
+ "identityUnknown": "Tanya Masuk aktif, namun hash identitas rekan ini belum diketahui sehingga tidak ditambahkan ke Selalu izinkan. Anda masih akan ditanya sebelum setiap file; coba Selalu izinkan lagi setelah jalur atau pengumuman tiba."
},
"saved": {
"labelPlaceholder": "Label",
diff --git a/src/renderer/locales/it/translation.json b/src/renderer/locales/it/translation.json
index 80cdecb37..d24f63d03 100644
--- a/src/renderer/locales/it/translation.json
+++ b/src/renderer/locales/it/translation.json
@@ -4884,8 +4884,10 @@
"peerUnreachable": "Nessun percorso per quella destinazione. Il peer potrebbe essere offline.",
"checkingReachability": "Verifica della raggiungibilità…",
"listenerLikelyOffTitle": "La ricezione dei file potrebbe essere disattivata",
- "listenerLikelyOffBody": "Nessun percorso verso la destinazione di ricezione del file, ma cercano online la chat. Chiedi loro di abilitare la ricezione dei file (Telecomando → Impostazioni → Offerte di file in entrata), quindi riprova.",
- "listenerLikelyOffConfirm": "Invia richiesta di abilitazione"
+ "listenerLikelyOffConfirm": "Invia richiesta di abilitazione",
+ "pendingOffersBadgeAriaCapped": "Oltre 99 offerte di file in entrata in sospeso",
+ "listenerLikelyOffBody": "Nessun percorso verso la destinazione di ricezione del file, ma cercano online la chat. Chiedi loro di abilitare la ricezione di file rncp e di inviare l'hash di ricezione rncp, quindi riprova.",
+ "listenerLikelyOffToast": "Nessun percorso per la destinazione di ricezione del file; la ricezione dei file potrebbe essere disattivata. Chiedi loro di abilitare la ricezione rncp e di inviare il loro hash, quindi riprova."
},
"enableRequest": {
"title": "Abilitare la ricezione dei file?",
@@ -4901,10 +4903,10 @@
"enabled": "La ricezione dei file è abilitata.",
"enableFailed": "Impossibile abilitare la ricezione dei file: {{error}}",
"saveDirRequired": "Scegli una cartella di salvataggio per abilitare la ricezione.",
- "identityUnknown": "Non è stato ancora possibile risolvere l'hash di identità di questo peer — la modalità Chiedi è attiva, ma il peer non è stato aggiunto alla lista dei consentiti. Riprova dopo l'arrivo di un percorso o di un annuncio.",
- "lxmfShareBody": "La ricezione file è abilitata. Ecco la mia destinazione di ricezione rncp (mesh-client la salverà per te).",
"shareDestWarning": "Se abiliti, mesh-client invierà la destinazione di ricezione rncp a questo peer in modo che possa compilare automaticamente l'invio del file.",
- "lxmfBody": "Abilita la ricezione rncp (Telecomando → Impostazioni → Offerte file in entrata) e inviami il tuo hash di ricezione rncp."
+ "lxmfBody": "Abilita la ricezione di file rncp e rispondi con l'hash di destinazione di ricezione rncp.",
+ "lxmfShareBody": "La ricezione dei file è abilitata. Il mio rncp riceve l'hash di destinazione:",
+ "identityUnknown": "La richiesta in entrata è attiva, ma l'hash dell'identità di questo peer non è ancora noto, quindi non è stato aggiunto a Consenti sempre. Ti verrà comunque chiesto prima di ogni file; prova Consenti sempre di nuovo dopo l'arrivo di un percorso o di un annuncio."
},
"saved": {
"labelPlaceholder": "Label",
diff --git a/src/renderer/locales/ja/translation.json b/src/renderer/locales/ja/translation.json
index 7dbf02808..42aa62cb8 100644
--- a/src/renderer/locales/ja/translation.json
+++ b/src/renderer/locales/ja/translation.json
@@ -4884,8 +4884,10 @@
"peerUnreachable": "その目的地への道はありません。ピアがオフラインである可能性があります。",
"checkingReachability": "到達可能性を確認しています…",
"listenerLikelyOffTitle": "ファイル受信がオフになっている可能性があります",
- "listenerLikelyOffBody": "ファイルの受信先へのパスはありませんが、オンラインでチャットを探しています。ファイル受信を有効にするよう依頼して (リモート → 設定 → 受信ファイル オファー)、もう一度試してください。",
- "listenerLikelyOffConfirm": "有効化リクエストを送信する"
+ "listenerLikelyOffConfirm": "有効化リクエストを送信する",
+ "pendingOffersBadgeAriaCapped": "99 件以上の保留中の受信ファイル オファー",
+ "listenerLikelyOffBody": "ファイルの受信先へのパスはありませんが、オンラインでチャットを探しています。 rncp ファイル受信を有効にし、rncp 受信ハッシュを送信してから、再試行するように依頼してください。",
+ "listenerLikelyOffToast": "ファイルの受信先へのパスがありません。ファイル受信がオフになっている可能性があります。 rncp のハッシュの送受信を有効にするよう依頼してから、再試行してください。"
},
"enableRequest": {
"title": "ファイル受信を有効にしますか?",
@@ -4901,10 +4903,10 @@
"enabled": "ファイル受信が有効になっています。",
"enableFailed": "ファイル受信を有効にできませんでした: {{error}}",
"saveDirRequired": "受信を有効にする保存フォルダを選択します。",
- "identityUnknown": "このピアのIDハッシュをまだ解決できませんでした。受信時の確認は有効になりましたが、許可リストには追加されていません。パスまたはアナウンスの到着後にもう一度お試しください。",
- "lxmfShareBody": "ファイル受信が有効です。これが私の rncp 受信先です(mesh-client が保存します)。",
"shareDestWarning": "有効にすると、mesh-client は rncp 受信宛先をこのピアに送信し、ファイル送信を自動入力できるようになります。",
- "lxmfBody": "rncp 受信を有効にして (リモート → 設定 → インバウンド ファイル オファー)、rncp 受信ハッシュを送信してください。"
+ "lxmfBody": "rncp ファイル受信を有効にし、rncp 受信宛先ハッシュを返信してください。",
+ "lxmfShareBody": "ファイル受信が有効になっています。私のrncp受信宛先ハッシュ:",
+ "identityUnknown": "Inbound Ask はオンですが、このピアの ID ハッシュがまだ不明であるため、常に許可には追加されませんでした。各ファイルの前に引き続き質問されます。 try パスまたはアナウンスが到着した後は、常に再度許可します。"
},
"saved": {
"labelPlaceholder": "ラベル",
diff --git a/src/renderer/locales/ko/translation.json b/src/renderer/locales/ko/translation.json
index c16711198..95decf1ce 100644
--- a/src/renderer/locales/ko/translation.json
+++ b/src/renderer/locales/ko/translation.json
@@ -4884,8 +4884,10 @@
"peerUnreachable": "해당 목적지까지의 경로가 없습니다. 피어가 오프라인일 수 있습니다.",
"checkingReachability": "연결 가능성 확인 중…",
"listenerLikelyOffTitle": "파일 수신이 꺼져 있을 수 있습니다.",
- "listenerLikelyOffBody": "파일 수신 대상에 대한 경로가 없지만 온라인에서 채팅을 찾습니다. 파일 수신 활성화(원격 → 설정 → 인바운드 파일 제공)를 요청한 후 다시 시도하세요.",
- "listenerLikelyOffConfirm": "활성화 요청 보내기"
+ "listenerLikelyOffConfirm": "활성화 요청 보내기",
+ "pendingOffersBadgeAriaCapped": "99개 이상의 대기 중인 인바운드 파일 제안",
+ "listenerLikelyOffBody": "파일 수신 대상에 대한 경로가 없지만 온라인에서 채팅을 찾습니다. rncp 파일 수신을 활성화하고 rncp 수신 해시를 보낸 후 다시 시도하세요.",
+ "listenerLikelyOffToast": "파일 수신 대상에 대한 경로가 없습니다. 파일 수신이 꺼져 있을 수 있습니다. rncp 수신 및 해시 전송을 활성화하도록 요청한 후 다시 시도하세요."
},
"enableRequest": {
"title": "파일 수신을 활성화하시겠습니까?",
@@ -4901,10 +4903,10 @@
"enabled": "파일 수신이 활성화되었습니다.",
"enableFailed": "파일 수신을 활성화할 수 없습니다: {{error}}",
"saveDirRequired": "수신을 활성화하려면 저장 폴더를 선택하세요.",
- "identityUnknown": "이 피어의 신원 해시를 아직 확인할 수 없습니다 — 수신 확인은 활성화되었지만 허용 목록에는 추가되지 않았습니다. 경로나 알림이 도착한 후 다시 시도하세요.",
- "lxmfShareBody": "파일 수신이 활성화되었습니다. 제 rncp 수신 대상입니다(mesh-client가 저장합니다).",
"shareDestWarning": "활성화하면 mesh-client는 rncp 수신 대상을 이 피어에 보내 파일 보내기를 자동 채울 수 있습니다.",
- "lxmfBody": "rncp 수신을 활성화하고(원격 → 설정 → 인바운드 파일 제공) rncp 수신 해시를 보내주세요."
+ "lxmfBody": "rncp 파일 수신을 활성화하고 rncp 수신 대상 해시로 응답하세요.",
+ "lxmfShareBody": "파일 수신이 활성화되었습니다. 내 rncp 수신 대상 해시:",
+ "identityUnknown": "인바운드 요청이 켜져 있지만 이 피어의 ID 해시가 아직 알려지지 않았기 때문에 항상 허용에 추가되지 않았습니다. 각 파일 앞에는 여전히 질문이 표시됩니다. 경로나 알림이 도착한 후에는 항상 다시 허용해 보세요."
},
"saved": {
"labelPlaceholder": "상표",
diff --git a/src/renderer/locales/nl/translation.json b/src/renderer/locales/nl/translation.json
index 18f7bc39e..75d9e7b0a 100644
--- a/src/renderer/locales/nl/translation.json
+++ b/src/renderer/locales/nl/translation.json
@@ -4884,8 +4884,10 @@
"peerUnreachable": "Geen pad naar die bestemming. De peer is mogelijk offline.",
"checkingReachability": "Bereikbaarheid controleren...",
"listenerLikelyOffTitle": "Het ontvangen van bestanden is mogelijk uitgeschakeld",
- "listenerLikelyOffBody": "Er is geen pad naar de bestemming van hun bestand, maar ze zoeken online naar chat. Vraag hen om het ontvangen van bestanden in te schakelen (Op afstand → Instellingen → Inkomende bestandsaanbiedingen) en probeer het vervolgens opnieuw.",
- "listenerLikelyOffConfirm": "Inschakelverzoek verzenden"
+ "listenerLikelyOffConfirm": "Inschakelverzoek verzenden",
+ "pendingOffersBadgeAriaCapped": "99+ openstaande aanbiedingen voor inkomende bestanden",
+ "listenerLikelyOffBody": "Er is geen pad naar de bestemming van hun bestand, maar ze zoeken online naar chat. Vraag hen om het ontvangen van rncp-bestanden in te schakelen en hun rncp-ontvangst-hash te verzenden, en probeer het vervolgens opnieuw.",
+ "listenerLikelyOffToast": "Geen pad naar hun bestandsontvangstbestemming; Het ontvangen van bestanden is mogelijk uitgeschakeld. Vraag hen om rncp het ontvangen en verzenden van hun hash in te schakelen en probeer het vervolgens opnieuw."
},
"enableRequest": {
"title": "Bestandsontvangst inschakelen?",
@@ -4901,10 +4903,10 @@
"enabled": "Bestandsontvangst is ingeschakeld.",
"enableFailed": "Kon het ontvangen van bestanden niet inschakelen: {{error}}",
"saveDirRequired": "Kies een opslagmap om ontvangst in te schakelen.",
- "identityUnknown": "De identiteitshash van deze peer kon nog niet worden bepaald — inkomend vragen is ingeschakeld, maar de peer is niet aan de toestaanlijst toegevoegd. Probeer het opnieuw nadat een pad of aankondiging is ontvangen.",
- "lxmfShareBody": "Bestandsontvangst is ingeschakeld. Dit is mijn rncp-ontvangstbestemming (mesh-client bewaart dit voor u).",
"shareDestWarning": "Als u dit inschakelt, zal mesh-client uw rncp-ontvangstbestemming naar deze peer sturen, zodat zij het verzenden van bestanden automatisch kunnen aanvullen.",
- "lxmfBody": "Schakel rncp-ontvangst in (Op afstand → Instellingen → Inkomende bestandsaanbiedingen) en stuur mij uw rncp-ontvangst-hash."
+ "lxmfBody": "Schakel het ontvangen van rncp-bestanden in en antwoord met de hash van uw rncp-ontvangstbestemming.",
+ "lxmfShareBody": "Bestandsontvangst is ingeschakeld. Mijn rncp ontvangt bestemmingshash:",
+ "identityUnknown": "Inkomend vragen is ingeschakeld, maar de identiteitshash van deze peer is nog niet bekend, dus deze is niet toegevoegd aan Altijd toestaan. U wordt nog steeds vóór elk bestand gevraagd; probeer Altijd opnieuw toestaan nadat een pad of aankondiging binnenkomt."
},
"saved": {
"labelPlaceholder": "Label",
diff --git a/src/renderer/locales/pl/translation.json b/src/renderer/locales/pl/translation.json
index 13d8ce3b3..ce1abe4da 100644
--- a/src/renderer/locales/pl/translation.json
+++ b/src/renderer/locales/pl/translation.json
@@ -4888,8 +4888,10 @@
"peerUnreachable": "Żadnej drogi do tego celu. Partner może być offline.",
"checkingReachability": "Sprawdzam osiągalność…",
"listenerLikelyOffTitle": "Odbieranie plików może być wyłączone",
- "listenerLikelyOffBody": "Brak ścieżki do miejsca docelowego odbioru pliku, ale szukają czatu w Internecie. Poproś o włączenie odbierania plików (Zdalne → Ustawienia → Oferty plików przychodzących), a następnie spróbuj ponownie.",
- "listenerLikelyOffConfirm": "Wyślij prośbę o włączenie"
+ "listenerLikelyOffConfirm": "Wyślij prośbę o włączenie",
+ "pendingOffersBadgeAriaCapped": "Ponad 99 oczekujących ofert plików przychodzących",
+ "listenerLikelyOffBody": "Brak ścieżki do miejsca docelowego odbioru pliku, ale szukają czatu w Internecie. Poproś ich o włączenie odbierania plików rncp i wysłanie skrótu odbioru rncp, a następnie spróbuj ponownie.",
+ "listenerLikelyOffToast": "Brak ścieżki do miejsca docelowego odbioru pliku; odbieranie plików może być wyłączone. Poproś ich, aby umożliwili rncp odbieranie i wysyłanie skrótu, a następnie spróbuj ponownie."
},
"enableRequest": {
"title": "Włączyć odbiór plików?",
@@ -4905,10 +4907,10 @@
"enabled": "Odbiór plików jest włączony.",
"enableFailed": "Nie można włączyć odbierania plików: {{error}}",
"saveDirRequired": "Wybierz folder zapisu, aby włączyć odbiór.",
- "identityUnknown": "Nie udało się jeszcze ustalić skrótu tożsamości tego peera — tryb pytania jest włączony, ale nie dodano go do listy dozwolonych. Spróbuj ponownie, gdy nadejdzie ścieżka lub ogłoszenie.",
- "lxmfShareBody": "Odbieranie plików jest włączone. Oto moje miejsce docelowe odbioru rncp (mesh-client zapisze je dla Ciebie).",
"shareDestWarning": "Jeśli włączysz, mesh-client wyśle miejsce docelowe odbioru rncp do tego partnera, aby mógł automatycznie wypełnić wysyłanie pliku.",
- "lxmfBody": "Włącz odbieranie rncp (Zdalne → Ustawienia → Oferty plików przychodzących) i wyślij mi swój skrót odbierania rncp."
+ "lxmfBody": "Włącz odbieranie pliku rncp i odpowiedz, podając hash miejsca docelowego odbioru rncp.",
+ "lxmfShareBody": "Odbieranie plików jest włączone. Mój rncp odbiera docelowy skrót:",
+ "identityUnknown": "Zapytanie przychodzące jest włączone, ale skrót tożsamości tego partnera nie jest jeszcze znany, dlatego nie został on dodany do opcji Zawsze zezwalaj. Nadal będziesz pytany przed każdym plikiem; spróbuj Zawsze zezwalaj ponownie po nadejściu ścieżki lub ogłoszenia."
},
"saved": {
"labelPlaceholder": "Oznaczenie",
diff --git a/src/renderer/locales/pt-BR/translation.json b/src/renderer/locales/pt-BR/translation.json
index ebb1870f7..536a5f59d 100644
--- a/src/renderer/locales/pt-BR/translation.json
+++ b/src/renderer/locales/pt-BR/translation.json
@@ -4884,8 +4884,10 @@
"peerUnreachable": "Nenhum caminho para esse destino. O par pode estar offline.",
"checkingReachability": "Verificando acessibilidade…",
"listenerLikelyOffTitle": "O recebimento de arquivos pode estar desativado",
- "listenerLikelyOffBody": "Nenhum caminho para o destino de recebimento do arquivo, mas eles procuram bate-papo on-line. Peça-lhes para ativar o recebimento de arquivos (Remoto → Configurações → Ofertas de arquivos de entrada) e tente novamente.",
- "listenerLikelyOffConfirm": "Enviar solicitação de ativação"
+ "listenerLikelyOffConfirm": "Enviar solicitação de ativação",
+ "pendingOffersBadgeAriaCapped": "Mais de 99 ofertas pendentes de arquivos de entrada",
+ "listenerLikelyOffBody": "Nenhum caminho para o destino de recebimento do arquivo, mas eles procuram bate-papo on-line. Peça-lhes para ativar o recebimento do arquivo rncp e enviar o hash de recebimento do rncp e, em seguida, tente novamente.",
+ "listenerLikelyOffToast": "Nenhum caminho para o destino de recebimento do arquivo; o recebimento de arquivos pode estar desativado. Peça-lhes para ativar o recebimento e envio do rncp e tente novamente."
},
"enableRequest": {
"title": "Habilitar recebimento de arquivos?",
@@ -4901,10 +4903,10 @@
"enabled": "O recebimento de arquivos está ativado.",
"enableFailed": "Não foi possível ativar o recebimento de arquivos: {{error}}",
"saveDirRequired": "Escolha uma pasta de salvamento para ativar o recebimento.",
- "identityUnknown": "Ainda não foi possível resolver o hash de identidade deste par — o modo Perguntar foi ativado, mas ele não foi adicionado à lista de permitidos. Tente novamente quando um caminho ou anúncio chegar.",
- "lxmfShareBody": "O recebimento de arquivos está ativado. Aqui está meu destino de recebimento rncp (mesh-client salvará para você).",
"shareDestWarning": "Se você ativar, o mesh-client enviará seu destino de recebimento rncp para esse par para que eles possam preencher automaticamente o envio do arquivo.",
- "lxmfBody": "Ative o recebimento do rncp (Remoto → Configurações → Ofertas de arquivos de entrada) e envie-me seu hash de recebimento do rncp."
+ "lxmfBody": "Ative o recebimento do arquivo rncp e responda com seu hash de destino de recebimento do rncp.",
+ "lxmfShareBody": "O recebimento de arquivos está habilitado. Meu rncp recebe hash de destino:",
+ "identityUnknown": "A solicitação de entrada está ativada, mas o hash de identidade desse peer ainda não é conhecido, portanto, eles não foram adicionados a Sempre permitir. Você ainda será questionado antes de cada arquivo; tente Sempre permitir novamente após a chegada de um caminho ou anúncio."
},
"saved": {
"labelPlaceholder": "Etiqueta",
diff --git a/src/renderer/locales/ru/translation.json b/src/renderer/locales/ru/translation.json
index f9578c1aa..dcca8baaa 100644
--- a/src/renderer/locales/ru/translation.json
+++ b/src/renderer/locales/ru/translation.json
@@ -4886,8 +4886,10 @@
"peerUnreachable": "Нет пути к этому месту назначения. Узел может быть отключен от сети.",
"checkingReachability": "Проверка доступности…",
"listenerLikelyOffTitle": "Прием файлов может быть отключен",
- "listenerLikelyOffBody": "Нет пути к месту назначения их файла, но они ищут чат в Интернете. Попросите их включить получение файлов (Удаленное управление → Настройки → Предложения входящих файлов), а затем повторите попытку.",
- "listenerLikelyOffConfirm": "Отправить запрос на включение"
+ "listenerLikelyOffConfirm": "Отправить запрос на включение",
+ "pendingOffersBadgeAriaCapped": "Более 99 ожидающих предложений по входящим файлам",
+ "listenerLikelyOffBody": "Нет пути к месту назначения их файла, но они ищут чат в Интернете. Попросите их включить получение файлов rncp и отправить хэш получения rncp, а затем повторите попытку.",
+ "listenerLikelyOffToast": "Нет пути к месту назначения файла; прием файлов может быть отключен. Попросите их включить получение и отправку хэша по rncp, а затем повторите попытку."
},
"enableRequest": {
"title": "Включить получение файлов?",
@@ -4903,10 +4905,10 @@
"enabled": "Получение файлов включено.",
"enableFailed": "Не удалось включить получение файлов: {{error}}",
"saveDirRequired": "Выберите папку сохранения, чтобы включить получение.",
- "identityUnknown": "Пока не удалось определить хеш личности этого пира — режим «Спрашивать» включён, но пир не добавлен в список разрешённых. Повторите попытку после получения пути или анонса.",
- "lxmfShareBody": "Приём файлов включён. Вот моё rncp-назначение приёма (mesh-client сохранит его для вас).",
"shareDestWarning": "Если вы включите этот параметр, mesh-client отправит пункт назначения получения rncp этому узлу, чтобы он мог автоматически заполнить файл для отправки.",
- "lxmfBody": "Пожалуйста, включите получение rncp (Удаленное управление → Настройки → Предложения входящих файлов) и пришлите мне хэш получения rncp."
+ "lxmfBody": "Пожалуйста, включите получение файлов rncp и ответьте, указав хэш получателя rncp.",
+ "lxmfShareBody": "Прием файлов включен. Мой rncp получает хеш назначения:",
+ "identityUnknown": "Входящий запрос включен, но хэш идентификатора этого узла еще не известен, поэтому он не был добавлен в список «Всегда разрешать». Вас по-прежнему будут спрашивать перед каждым файлом; попробуйте Всегда разрешать снова после поступления пути или объявления."
},
"saved": {
"labelPlaceholder": "Ярлык",
diff --git a/src/renderer/locales/tr/translation.json b/src/renderer/locales/tr/translation.json
index 89b6e06e1..1edf7fb49 100644
--- a/src/renderer/locales/tr/translation.json
+++ b/src/renderer/locales/tr/translation.json
@@ -4884,8 +4884,10 @@
"peerUnreachable": "O hedefe giden yol yok. Eş çevrimdışı olabilir.",
"checkingReachability": "Erişilebilirlik kontrol ediliyor…",
"listenerLikelyOffTitle": "Dosya alma kapalı olabilir",
- "listenerLikelyOffBody": "Dosyalarının varış noktasına giden yolu yok, ancak sohbet için çevrimiçi görünüyorlar. Dosya almayı etkinleştirmelerini isteyin (Uzak → Ayarlar → Gelen dosya teklifleri), ardından tekrar deneyin.",
- "listenerLikelyOffConfirm": "Etkinleştirme isteği gönder"
+ "listenerLikelyOffConfirm": "Etkinleştirme isteği gönder",
+ "pendingOffersBadgeAriaCapped": "99'dan fazla bekleyen gelen dosya teklifi",
+ "listenerLikelyOffBody": "Dosyalarının varış noktasına giden yolu yok, ancak sohbet için çevrimiçi görünüyorlar. Onlardan rncp dosyası almayı etkinleştirmelerini ve rncp alma karmalarını göndermelerini isteyin, ardından tekrar deneyin.",
+ "listenerLikelyOffToast": "Dosya alma hedefine giden yol yok; dosya alma kapalı olabilir. Onlardan rncp'nin karmalarını almasını ve göndermesini etkinleştirmelerini isteyin, ardından tekrar deneyin."
},
"enableRequest": {
"title": "Dosya alımı etkinleştirilsin mi?",
@@ -4901,10 +4903,10 @@
"enabled": "Dosya alma etkinleştirildi.",
"enableFailed": "Dosya alımı etkinleştirilemedi: {{error}}",
"saveDirRequired": "Alımı etkinleştirmek için bir kaydetme klasörü seçin.",
- "identityUnknown": "Bu eşin kimlik karması henüz çözülemedi — gelen Sor modu etkinleştirildi ancak eş izin listesine eklenmedi. Bir yol veya duyuru geldikten sonra tekrar deneyin.",
- "lxmfShareBody": "Dosya alma etkinleştirildi. İşte rncp alma hedefim (mesh-client sizin için kaydedecek).",
"shareDestWarning": "Etkinleştirirseniz mesh-client, dosya gönderimini otomatik olarak doldurabilmeleri için rncp alma hedefinizi bu eşe gönderecektir.",
- "lxmfBody": "Lütfen rncp alımını etkinleştirin (Uzak → Ayarlar → Gelen dosya teklifleri) ve bana rncp alma karmanızı gönderin."
+ "lxmfBody": "Lütfen rncp dosya alımını etkinleştirin ve rncp alma hedefi karmanızla yanıtlayın.",
+ "lxmfShareBody": "Dosya alma etkinleştirildi. Benim rncp alma hedefi karması:",
+ "identityUnknown": "Gelen Sor açık ancak bu eşin kimlik karması henüz bilinmediğinden Her zaman izin ver'e eklenmedi. Yine de her dosyadan önce size sorulacaktır; Bir yol veya duyuru geldiğinde Her zaman izin ver'i tekrar deneyin."
},
"saved": {
"labelPlaceholder": "Etiket",
diff --git a/src/renderer/locales/uk/translation.json b/src/renderer/locales/uk/translation.json
index 55c736d56..79a42b9eb 100644
--- a/src/renderer/locales/uk/translation.json
+++ b/src/renderer/locales/uk/translation.json
@@ -4886,8 +4886,10 @@
"peerUnreachable": "Немає шляху до цього пункту призначення. Одноранговий пристрій може бути офлайн.",
"checkingReachability": "Перевірка доступності…",
"listenerLikelyOffTitle": "Отримання файлів може бути вимкнено",
- "listenerLikelyOffBody": "Немає шляху до пункту призначення файлу, але вони шукають онлайн-чат. Попросіть їх увімкнути отримання файлів (Віддалене → Налаштування → Пропозиції вхідних файлів), а потім повторіть спробу.",
- "listenerLikelyOffConfirm": "Надіслати запит на ввімкнення"
+ "listenerLikelyOffConfirm": "Надіслати запит на ввімкнення",
+ "pendingOffersBadgeAriaCapped": "99+ пропозицій щодо вхідних файлів, що очікують на розгляд",
+ "listenerLikelyOffBody": "Немає шляху до пункту призначення файлу, але вони шукають онлайн-чат. Попросіть їх увімкнути отримання файлів rncp і надіслати свій хеш отримання rncp, а потім повторіть спробу.",
+ "listenerLikelyOffToast": "Немає шляху до місця призначення файлу; отримання файлів може бути вимкнено. Попросіть їх увімкнути rncp отримувати та надсилати свій хеш, а потім повторіть спробу."
},
"enableRequest": {
"title": "Увімкнути прийом файлів?",
@@ -4903,10 +4905,10 @@
"enabled": "Отримання файлів увімкнено.",
"enableFailed": "Не вдалося увімкнути отримання файлу: {{error}}",
"saveDirRequired": "Виберіть папку збереження, щоб увімкнути отримання.",
- "identityUnknown": "Поки не вдалося визначити хеш особи цього піра — режим «Запитувати» увімкнено, але піра не додано до списку дозволених. Спробуйте ще раз після надходження шляху або анонсу.",
- "lxmfShareBody": "Прийом файлів увімкнено. Ось мій rncp destination прийому (mesh-client збереже його для вас).",
"shareDestWarning": "Якщо ввімкнути, mesh-client надсилатиме ваш адресат отримання rncp цьому вузлу, щоб він міг автоматично заповнювати надсилання файлів.",
- "lxmfBody": "Будь ласка, увімкніть отримання rncp (Віддалений → Налаштування → Пропозиції вхідних файлів) і надішліть мені свій хеш отримання rncp."
+ "lxmfBody": "Будь ласка, увімкніть отримання файлу rncp і надішліть відповідь, вказавши свій хеш призначення rncp.",
+ "lxmfShareBody": "Отримання файлів увімкнено. Мій rncp отримує хеш призначення:",
+ "identityUnknown": "Вхідний запит увімкнено, але хеш-ідентифікатор цього однорангового вузла ще невідомий, тому його не було додано до Завжди дозволяти. Вас все одно запитуватимуть перед кожним файлом; спробуйте Завжди дозволяти знову після надходження шляху або оголошення."
},
"saved": {
"labelPlaceholder": "Мітка",
diff --git a/src/renderer/locales/zh/translation.json b/src/renderer/locales/zh/translation.json
index 4dc9bfee8..7f1e5960c 100644
--- a/src/renderer/locales/zh/translation.json
+++ b/src/renderer/locales/zh/translation.json
@@ -4884,8 +4884,10 @@
"peerUnreachable": "没有通往那个目的地的路。对等方可能离线。",
"checkingReachability": "检查可达性...",
"listenerLikelyOffTitle": "文件接收可能已关闭",
- "listenerLikelyOffBody": "没有通往文件接收目的地的路径,但他们在网上查找聊天内容。要求他们启用文件接收(远程 → 设置 → 入站文件提供),然后重试。",
- "listenerLikelyOffConfirm": "发送启用请求"
+ "listenerLikelyOffConfirm": "发送启用请求",
+ "pendingOffersBadgeAriaCapped": "超过 99 个待处理的入站文件优惠",
+ "listenerLikelyOffBody": "没有通往文件接收目的地的路径,但他们在网上查找聊天内容。要求他们启用 rncp 文件接收并发送其 rncp 接收哈希,然后重试。",
+ "listenerLikelyOffToast": "没有文件接收目的地的路径;文件接收可能已关闭。要求他们启用 rncp 接收和发送哈希值,然后重试。"
},
"enableRequest": {
"title": "启用文件接收?",
@@ -4901,10 +4903,10 @@
"enabled": "文件接收已启用。",
"enableFailed": "无法启用文件接收: {{error}}",
"saveDirRequired": "选择一个保存文件夹以启用接收。",
- "identityUnknown": "暂时无法解析此对等节点的身份哈希 — 已启用来件询问,但未将其加入允许列表。等路径或公告到达后再试一次。",
- "lxmfShareBody": "文件接收已启用。这是我的 rncp 接收目的地(mesh-client 将为您保存)。",
"shareDestWarning": "如果启用,mesh-client 会将您的 rncp 接收目标发送到该对等方,以便他们可以自动填充文件发送。",
- "lxmfBody": "请启用 rncp 接收(远程 → 设置 → 入站文件提供)并向我发送您的 rncp 接收哈希值。"
+ "lxmfBody": "请启用 rncp 文件接收并回复您的 rncp 接收目标哈希。",
+ "lxmfShareBody": "文件接收已启用。我的 rncp 接收目标哈希值:",
+ "identityUnknown": "入站询问已打开,但该对等方的身份哈希尚不清楚,因此它们未添加到始终允许中。每个文件之前仍会询问您;尝试在路径或公告到达后再次始终允许。"
},
"saved": {
"labelPlaceholder": "标号",
diff --git a/src/shared/rncpRequestEnable.test.ts b/src/shared/rncpRequestEnable.test.ts
index f3dbed0ab..e34528f98 100644
--- a/src/shared/rncpRequestEnable.test.ts
+++ b/src/shared/rncpRequestEnable.test.ts
@@ -10,10 +10,9 @@ import {
} from './rncpRequestEnable';
describe('rncpRequestEnable', () => {
- it('embeds sentinel after human instructions', () => {
+ it('appends mesh-client sentinel after human instructions for receiver automation', () => {
const body = buildRncpRequestEnableMessageBody('Please enable file receiving.');
- expect(body).toContain('Please enable file receiving.');
- expect(body).toContain(RNCP_REQUEST_ENABLE_SENTINEL);
+ expect(body).toBe(`Please enable file receiving.\n\n${RNCP_REQUEST_ENABLE_SENTINEL}`);
});
it('detects sentinel in inbound body', () => {
@@ -22,9 +21,10 @@ describe('rncpRequestEnable', () => {
expect(lxmfBodyContainsRncpRequestEnable(null)).toBe(false);
});
- it('builds and parses receive-dest share bodies', () => {
+ it('builds and parses receive-dest share bodies with a plain hash line', () => {
const hash = 'ab'.repeat(16);
const body = buildRncpReceiveDestShareBody('Here is my rncp receive destination.', hash);
+ expect(body).toContain(`Here is my rncp receive destination.\n${hash}`);
expect(body).toContain(RNCP_RECEIVE_DEST_SHARE_PREFIX + hash);
expect(parseRncpReceiveDestShare(body)).toBe(hash);
});
diff --git a/src/shared/rncpRequestEnable.ts b/src/shared/rncpRequestEnable.ts
index 7797def23..fc51c1669 100644
--- a/src/shared/rncpRequestEnable.ts
+++ b/src/shared/rncpRequestEnable.ts
@@ -1,7 +1,8 @@
/**
* LXMF control sentinels for mesh-client rncp receive enable / dest sharing.
- * Ordinary LXMF DM bodies always include human-readable instructions; mesh-client
- * peers additionally parse these sentinels for UI automation.
+ * Human-readable LXMF bodies must stay app-agnostic (Sideband, Nomad, etc.).
+ * mesh-client peers additionally parse these sentinels for UI automation
+ * (enable-request modal + receive-dest autofill).
*/
export const RNCP_REQUEST_ENABLE_SENTINEL = 'mesh-client:request-rncp-receive:v1';
@@ -14,6 +15,11 @@ export const RNCP_REQUEST_ENABLE_COOLDOWN_MS = 10 * 60 * 1000;
const DEST_HASH_RE = /^[0-9a-f]{32}$/;
+/**
+ * Enable-request LXMF body: app-agnostic human instructions, then the mesh-client
+ * sentinel so receiving mesh-client builds can open the enable/share modal.
+ * Other LXMF apps show the sentinel as an extra line they can ignore.
+ */
export function buildRncpRequestEnableMessageBody(instructions: string): string {
const trimmed = instructions.trim();
return `${trimmed}\n\n${RNCP_REQUEST_ENABLE_SENTINEL}`;
@@ -26,7 +32,7 @@ export function lxmfBodyContainsRncpRequestEnable(body: string | null | undefine
/**
* Build an LXMF body that shares this client's rncp.receive destination with a peer
- * who requested enable (human line + machine-readable sentinel).
+ * who requested enable (plain hash for any LXMF client + mesh-client sentinel).
*/
export function buildRncpReceiveDestShareBody(instructions: string, receiveHash: string): string {
const hash = receiveHash.replace(/[^0-9a-f]/gi, '').toLowerCase();
@@ -34,7 +40,7 @@ export function buildRncpReceiveDestShareBody(instructions: string, receiveHash:
throw new Error('invalid_rncp_receive_hash');
}
const trimmed = instructions.trim();
- return `${trimmed}\n\n${RNCP_RECEIVE_DEST_SHARE_PREFIX}${hash}`;
+ return `${trimmed}\n${hash}\n\n${RNCP_RECEIVE_DEST_SHARE_PREFIX}${hash}`;
}
/**