diff options
| author | Adam Soltys <[email protected]> | 2026-10-03 08:47:20 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-10-03 08:47:20 -0700 |
| commit | 4444c9ce12cc9c1ed3eca9470e0c1080f80d8027 (patch) | |
| tree | e7678a59cc3de7e50f102ded24ea6e45e24427d1 /src | |
| parent | a6a0e1a4c86d9081ee386071bf5921608edb224b (diff) | |
| download | coinosv3-4444c9ce12cc9c1ed3eca9470e0c1080f80d8027.tar.gz coinosv3-4444c9ce12cc9c1ed3eca9470e0c1080f80d8027.zip | |
Settings → Nostr: manage your relays
A Relays card edits the two relay lists other Nostr apps go by: the
NIP-65 list (each relay Read, Write or both) and the NIP-17 DM inbox.
Each relay shows whether it answers (a dot; 'unreachable' spelled out).
Both lists are replaceable events other clients write too, so the card
edits only a copy it looked up across the index and archive relays, looks
again just before publishing, and backs off (reloading the newer copy) if
another app saved since. Only a list that changed is republished, to the
relays it names, the ones it used to name, and the indexers.
Saving updates our own idea of where we write (outbox lookups and wallet
sync relays) and resubscribes the DM inbox at once.
tools/relays-settings-test.js
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01ULQZS9MQa6iAsXnrJUD9Du
Diffstat (limited to 'src')
| -rw-r--r-- | src/features/messages.js | 188 | ||||
| -rw-r--r-- | src/i18n.js | 18 | ||||
| -rw-r--r-- | src/locales/ar.json | 20 | ||||
| -rw-r--r-- | src/locales/bn.json | 20 | ||||
| -rw-r--r-- | src/locales/de.json | 20 | ||||
| -rw-r--r-- | src/locales/es.json | 20 | ||||
| -rw-r--r-- | src/locales/fr.json | 20 | ||||
| -rw-r--r-- | src/locales/hi.json | 20 | ||||
| -rw-r--r-- | src/locales/id.json | 20 | ||||
| -rw-r--r-- | src/locales/ja.json | 20 | ||||
| -rw-r--r-- | src/locales/ko.json | 20 | ||||
| -rw-r--r-- | src/locales/mr.json | 20 | ||||
| -rw-r--r-- | src/locales/pt.json | 20 | ||||
| -rw-r--r-- | src/locales/ru.json | 20 | ||||
| -rw-r--r-- | src/locales/sw.json | 20 | ||||
| -rw-r--r-- | src/locales/ta.json | 20 | ||||
| -rw-r--r-- | src/locales/te.json | 20 | ||||
| -rw-r--r-- | src/locales/tr.json | 20 | ||||
| -rw-r--r-- | src/locales/ur.json | 20 | ||||
| -rw-r--r-- | src/locales/vi.json | 20 | ||||
| -rw-r--r-- | src/locales/zh.json | 20 |
21 files changed, 565 insertions, 21 deletions
diff --git a/src/features/messages.js b/src/features/messages.js index 0a1d5f2..7165dfc 100644 --- a/src/features/messages.js +++ b/src/features/messages.js @@ -15,7 +15,7 @@ import { subscribeOn, publishOn, queryOn, queryStreamOn, fetchInboxRelays, relayAlive, liveRelayList, resetRelay, npubOf, neventOf, parseNostrPubkey, parseNostrRef, generateSecretKey, getPublicKey, finalizeEvent, nip44, - PROFILE_RELAYS, openWrapsOffthread, unwrapDMsOffthread, verifyEventsAsync, + PROFILE_RELAYS, openWrapsOffthread, unwrapDMsOffthread, verifyEventsAsync, setSyncConfig, DEFAULT_SYNC_RELAYS, } from '../nostr.js'; import { channelKey, channelStream, channelEpoch, channelIsPrivate, controlKey, guestbookKey, openWrap, wrapRumor, rumorWithId, @@ -7611,6 +7611,190 @@ export function messagesFeature(ctx) { : h('div', { class: 'small faint' }, t('followHistNone'))); } + // ---- relay management: your NIP-65 list and your DM inbox (NIP-17) ------- + // Both are replaceable events other clients write too, so the card only + // ever edits a copy it looked for far and wide first (the follow list was + // once overwritten from a two-relay lookup), and checks again just before + // publishing that nobody saved a newer one meanwhile. + const RELAY_LOOKUP = () => [...new Set([...PROFILE_RELAYS, ...PROFILE_INDEX_RELAYS, ...DM_RELAYS, + ...PROFILE_ARCHIVE_RELAYS, ...FOLLOW_HISTORY_RELAYS])]; + async function fetchOwnRelayLists(me) { + const evs = await queryOn(RELAY_LOOKUP(), { kinds: [10002, 10050], authors: [me] }, 6000).catch(() => []); + const newest = (k) => (evs || []).filter((e) => e.pubkey === me && e.kind === k).sort((a, b) => b.created_at - a.created_at)[0] || null; + return { r: newest(10002), dm: newest(10050) }; + } + const rowsOf10002 = (e) => { + const out = new Map(); + for (const x of (e && e.tags) || []) { + if (x[0] !== 'r') continue; + const url = normRelay(x[1]); + if (!url) continue; + const row = out.get(url) || { url, read: false, write: false }; + if (!x[2] || x[2] === 'read') row.read = true; + if (!x[2] || x[2] === 'write') row.write = true; + out.set(url, row); + } + return [...out.values()]; + }; + const urlsOf10050 = (e) => [...new Set(((e && e.tags) || []).filter((x) => x[0] === 'relay').map((x) => normRelay(x[1])).filter(Boolean))]; + const tagsOfRows = (rows) => rows.filter((r) => r.read || r.write) + .map((r) => (r.read && r.write ? ['r', r.url] : ['r', r.url, r.read ? 'read' : 'write'])); + const sameTags = (a, b) => JSON.stringify(a) === JSON.stringify(b); + + // How long a relay takes to open a socket, measured once per card visit. + function probeRelayLatency(url) { + const rm = ui.relayMgr; + if (!rm || rm.probe[url]) return; + rm.probe[url] = { state: 'wait' }; + const done = (state, ms) => { + if (rm.probe[url].state !== 'wait') return; + rm.probe[url] = { state, ms }; + try { ws.close(); } catch {} + if (ui.relayMgr === rm) render(); + }; + const t0 = performance.now(); + let ws; + try { ws = new WebSocket(url); } catch { done('bad'); return; } + ws.onopen = () => done('ok', Math.round(performance.now() - t0)); + ws.onerror = () => done('bad'); + setTimeout(() => done('bad'), 6000); + } + + function loadRelayMgr(me, inRender = false) { + const rm = ui.relayMgr = { me, loading: true, probe: {}, add: '', addDm: '' }; + if (!inRender) render(); + fetchOwnRelayLists(me).then((base) => { + if (ui.relayMgr !== rm) return; + rm.base = base; + rm.rows = base.r ? rowsOf10002(base.r) : PROFILE_RELAYS.map((url) => ({ url, read: true, write: true })); + rm.dm = base.dm ? urlsOf10050(base.dm) : [...DM_RELAYS]; + rm.loading = false; + render(); + }); + } + + async function saveRelayMgr() { + const rm = ui.relayMgr; + if (!rm || rm.saving || rm.loading) return; + const tags = tagsOfRows(rm.rows); + const dmTags = rm.dm.map((u) => ['relay', u]); + if (!tags.some((x) => !x[2] || x[2] === 'write') || !tags.some((x) => !x[2] || x[2] === 'read')) { toast(t('relaysNeedBoth')); return; } + if (!dmTags.length) { toast(t('relaysNeedDm')); return; } + const rChanged = !rm.base.r || !sameTags(tags, tagsOfRows(rowsOf10002(rm.base.r))); + const dmChanged = !rm.base.dm || !sameTags(rm.dm, urlsOf10050(rm.base.dm)); + if (!rChanged && !dmChanged) { toast(t('relaysUnchanged')); return; } + if (typeof navigator !== 'undefined' && navigator.onLine === false) { toast(t('msgSendFailed')); return; } + rm.saving = true; + render(); + try { + const id = await requireIdentity(); + if (id.pubkey !== rm.me) throw new Error(t('relaysWrongIdentity')); + // someone else's client may have saved since this card loaded + const now = await fetchOwnRelayLists(rm.me); + const newer = (a, b) => a && (!b || a.created_at > b.created_at); + if ((rChanged && newer(now.r, rm.base.r)) || (dmChanged && newer(now.dm, rm.base.dm))) { + toast(t('relaysChangedElsewhere')); + loadRelayMgr(rm.me); + return; + } + const sign = (partial) => (id.signer instanceof Uint8Array ? finalizeEvent(partial, id.signer) : id.signer.signEvent(partial)); + const stamp = (old) => Math.max(Math.floor(Date.now() / 1000), old ? old.created_at + 1 : 0); + const writes = tags.filter((x) => !x[2] || x[2] === 'write').map((x) => x[1]); + // the new list goes to the relays it names, the old ones (so they drop + // the stale copy) and the indexers other clients look lists up on + const everywhere = [...new Set([...PROFILE_RELAYS, ...PROFILE_INDEX_RELAYS, + ...rowsOf10002(rm.base.r).map((r) => r.url), ...tags.map((x) => x[1])])]; + if (rChanged) { + const evt = await sign({ kind: 10002, content: '', created_at: stamp(rm.base.r), tags }); + if (!(await publishOn(everywhere, evt))) throw new Error(t('msgSendFailed')); + rm.base.r = evt; + relayListCache.set(rm.me, Promise.resolve(writes.slice(0, 4))); + relayListsNow().set(rm.me, { r: writes, t: Date.now() }); + saveRelayLists(); + // wallet sync rides the same write relays (adoptSyncRelays) + setSyncConfig({ enabled: true, relays: [...new Set([...writes.slice(0, 4), ...DEFAULT_SYNC_RELAYS])].slice(0, 5) }); + } + if (dmChanged) { + const evt = await sign({ kind: 10050, content: '', created_at: stamp(rm.base.dm), tags: dmTags }); + const to = [...new Set([...everywhere, ...urlsOf10050(rm.base.dm), ...rm.dm, ...DM_RELAYS])]; + if (!(await publishOn(to, evt))) throw new Error(t('msgSendFailed')); + rm.base.dm = evt; + resubscribeStreams(); // read the inbox from the new list now + } + toast(t('relaysSaved')); + } catch (e) { + if (!(e instanceof NoIdentity)) toast(e.message || String(e)); + } finally { + rm.saving = false; + render(); + } + } + + function relaysCard() { + const me = mePk(); + if (!me) return null; + if (!ui.relayMgr || ui.relayMgr.me !== me) loadRelayMgr(me, true); + const rm = ui.relayMgr; + const head = [h('h3', {}, t('relaysTitle')), h('p', { class: 'small muted', style: 'margin:0' }, t('relaysDesc'))]; + if (rm.loading) { + return h('div', { class: 'card col relays-card', style: 'gap:10px' }, ...head, + h('div', { class: 'row', style: 'justify-content:center;padding:6px' }, h('span', { class: 'spinner sm' }))); + } + const dot = (url) => { + probeRelayLatency(url); + const p = rm.probe[url] || {}; + const color = p.state === 'ok' ? 'var(--green,#2e9d5b)' : p.state === 'bad' ? 'var(--red,#c0392b)' : 'var(--line)'; + return h('span', { title: p.state === 'ok' ? p.ms + ' ms' : p.state === 'bad' ? t('relaysDown') : '', + style: `flex:0 0 auto;width:8px;height:8px;border-radius:50%;background:${color}` }); + }; + const status = (url) => { + const p = rm.probe[url] || {}; + // a green dot says it's up (the ms are its tooltip); only trouble is spelled out + return p.state === 'bad' ? h('span', { class: 'small faint', style: 'white-space:nowrap' }, t('relaysDown')) : null; + }; + const name = (url) => h('span', { class: 'grow mono', style: 'min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px' }, + url.replace(/^wss:\/\//, '')); + const x = (onClick) => h('button', { class: 'linklike', type: 'button', 'aria-label': t('remove'), style: 'padding:0 4px', onClick }, '×'); + const flag = (row, k, label) => h('button', { + class: 'feed-chip' + (row[k] ? ' on' : ''), type: 'button', style: 'padding:3px 9px;font-size:12px', + onClick: () => { row[k] = !row[k]; if (!row.read && !row.write) row[k === 'read' ? 'write' : 'read'] = true; render(); }, + }, label); + const adder = (key, cls, onAdd) => { + const go = (ev) => { + const url = normRelay(rm[key]); + if (!url || !/^[a-z0-9.-]+(:\d+)?$/i.test(new URL(url).host)) { if (rm[key].trim()) toast(t('relaysBadUrl')); return; } + rm[key] = ''; + const box = ev && ev.currentTarget && ev.currentTarget.parentNode.querySelector('input'); + if (box) box.value = ''; + onAdd(url); + render(); + }; + return h('div', { class: 'row gap6' }, + h('input', { type: 'text', class: 'grow ' + cls, placeholder: 'wss://relay.example.com', value: rm[key], + autocapitalize: 'none', autocomplete: 'off', spellcheck: 'false', + onInput: (ev) => { rm[key] = ev.target.value; }, + onKeydown: (ev) => { if (ev.key === 'Enter') { ev.preventDefault(); go(ev); } } }), + h('button', { class: 'btn-sm', type: 'button', onClick: go }, t('modAdd'))); + }; + return h('div', { class: 'card col relays-card', style: 'gap:10px' }, ...head, + h('div', { class: 'small muted' }, t('relaysPublic')), + rm.base.r ? null : h('div', { class: 'small faint' }, t('relaysNoneYet')), + h('div', { class: 'col', style: 'gap:8px' }, ...rm.rows.map((row) => h('div', { class: 'row gap6 relay-row', style: 'align-items:center' }, + dot(row.url), name(row.url), status(row.url), + flag(row, 'read', t('relaysRead')), flag(row, 'write', t('relaysWrite')), + x(() => { rm.rows = rm.rows.filter((r) => r !== row); render(); })))), + adder('add', 'relay-add', (url) => { if (!rm.rows.some((r) => r.url === url)) rm.rows.push({ url, read: true, write: true }); }), + h('div', { class: 'small muted', style: 'margin-top:6px' }, t('relaysInbox')), + rm.base.dm ? null : h('div', { class: 'small faint' }, t('relaysNoneYet')), + h('div', { class: 'col', style: 'gap:8px' }, ...rm.dm.map((url) => h('div', { class: 'row gap6 relay-dm-row', style: 'align-items:center' }, + dot(url), name(url), status(url), + x(() => { rm.dm = rm.dm.filter((u) => u !== url); render(); })))), + adder('addDm', 'relay-dm-add', (url) => { if (!rm.dm.includes(url)) rm.dm.push(url); }), + h('div', { class: 'row gap6', style: 'margin-top:4px' }, + h('button', { class: 'grow relays-save', disabled: rm.saving, onClick: () => saveRelayMgr() }, rm.saving ? t('relaysSaving') : t('relaysSave')), + h('button', { class: 'btn-ghost', disabled: rm.saving, onClick: () => loadRelayMgr(me) }, t('relaysReload')))); + } + function moderationCard() { const m = mutesNow(); const e = ui.modEdit || (ui.modEdit = { word: '' }); @@ -11054,7 +11238,7 @@ export function messagesFeature(ctx) { id: 'messages', // group-chat state is device state in IndexedDB: it goes with the account wipeCache(bases) { import('../marmot-store.js').then((m) => { for (const b of bases) m.wipeMarmot(b); }).catch(() => {}); }, - nostrSettingsCards() { return [followHistoryCard(), moderationCard()]; }, + nostrSettingsCards() { return [relaysCard(), followHistoryCard(), moderationCard()]; }, // The app came back after being backgrounded. A phone freezes a hidden // tab: the relay sockets are cut and every post made in the meantime is // simply missing, which is why the feed used to sit there looking stale diff --git a/src/i18n.js b/src/i18n.js index c2a6aca..cb0e752 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -111,6 +111,24 @@ const STR = { followHistPeople: '{n} people', followHistRestore: 'Restore {n}', followHistNone: 'No older copy has anyone your list is missing.', + relaysTitle: "Relays", + relaysDesc: "Where your posts go and where other apps look for you. The lists are signed with your key, so every Nostr app you use follows them.", + relaysPublic: "Posts and profile. Read: where replies and mentions reach you. Write: where your posts are published.", + relaysInbox: "Direct message inbox: where people send you private messages.", + relaysRead: "Read", + relaysWrite: "Write", + relaysNoneYet: "Not published yet. These are the defaults; save to publish them.", + relaysDown: "unreachable", + relaysBadUrl: "That isn’t a relay address (wss://…).", + relaysNeedBoth: "Keep at least one read relay and one write relay.", + relaysNeedDm: "Keep at least one inbox relay.", + relaysUnchanged: "Nothing changed.", + relaysWrongIdentity: "Your signer belongs to a different account. Switch to it and try again.", + relaysChangedElsewhere: "Another app just updated your relay lists. They’ve been reloaded; make your changes again.", + relaysSaved: "Relay lists saved", + relaysSave: "Save", + relaysSaving: "Saving…", + relaysReload: "Reload", followHistNothing: 'Everyone in that copy is already in your list.', followHistRestored: 'Restored {n} follows.', profFollowing: 'Following', diff --git a/src/locales/ar.json b/src/locales/ar.json index d18d11d..57324ca 100644 --- a/src/locales/ar.json +++ b/src/locales/ar.json @@ -885,5 +885,23 @@ "feedRelaysFormHelp": "اقرأ هذه الخلاصة من هذه المرحّلات فقط. اتركها فارغة لاستخدام المعتاد.", "feedAllToggle": "كل منشور على هذه المرحّلات (تدفق كامل)", "feedAllCurated": "المنشورات الرائجة فقط: إخفاء الروبوتات والمنشورات بلا تفاعل", - "feedAllNeedsRelays": "اذكر المرحّلات التي تقرأ منها كل شيء." + "feedAllNeedsRelays": "اذكر المرحّلات التي تقرأ منها كل شيء.", + "relaysTitle": "المرحّلات", + "relaysDesc": "إلى أين تذهب منشوراتك وأين تبحث عنك التطبيقات الأخرى. القوائم موقّعة بمفتاحك، فتتبعها كل تطبيقات Nostr التي تستخدمها.", + "relaysPublic": "المنشورات والملف الشخصي. القراءة: حيث تصلك الردود والإشارات. الكتابة: حيث تُنشر منشوراتك.", + "relaysInbox": "صندوق الرسائل المباشرة: حيث يرسل إليك الناس رسائل خاصة.", + "relaysRead": "قراءة", + "relaysWrite": "كتابة", + "relaysNoneYet": "لم تُنشر بعد. هذه هي القيم الافتراضية؛ احفظ لنشرها.", + "relaysDown": "غير متاح", + "relaysBadUrl": "هذا ليس عنوان مرحّل (wss://…).", + "relaysNeedBoth": "أبقِ مرحّل قراءة واحدًا ومرحّل كتابة واحدًا على الأقل.", + "relaysNeedDm": "أبقِ مرحّلًا واحدًا على الأقل لصندوق الوارد.", + "relaysUnchanged": "لم يتغير شيء.", + "relaysWrongIdentity": "الموقّع لديك يخص حسابًا آخر. انتقل إليه وحاول مجددًا.", + "relaysChangedElsewhere": "غيّر تطبيق آخر قوائم المرحّلات للتو. أُعيد تحميلها؛ أجرِ تغييراتك مرة أخرى.", + "relaysSaved": "حُفظت قوائم المرحّلات", + "relaysSave": "حفظ", + "relaysSaving": "جارٍ الحفظ…", + "relaysReload": "إعادة تحميل" } diff --git a/src/locales/bn.json b/src/locales/bn.json index ca1ad9d..cf1a830 100644 --- a/src/locales/bn.json +++ b/src/locales/bn.json @@ -885,5 +885,23 @@ "feedRelaysFormHelp": "শুধু এই রিলেগুলো থেকে এই ফিড পড়ুন। সাধারণগুলোর জন্য খালি রাখুন।", "feedAllToggle": "এই রিলেগুলোর প্রতিটি পোস্ট (ফায়ারহোস)", "feedAllCurated": "শুধু জনপ্রিয় পোস্ট: বট ও প্রতিক্রিয়াহীন পোস্ট লুকান", - "feedAllNeedsRelays": "কোন রিলে থেকে সব পড়বেন তা লিখুন।" + "feedAllNeedsRelays": "কোন রিলে থেকে সব পড়বেন তা লিখুন।", + "relaysTitle": "রিলে", + "relaysDesc": "আপনার পোস্ট কোথায় যায় এবং অন্য অ্যাপ আপনাকে কোথায় খোঁজে। তালিকাগুলি আপনার কী দিয়ে স্বাক্ষরিত, তাই আপনার সব Nostr অ্যাপ এগুলো মানে।", + "relaysPublic": "পোস্ট ও প্রোফাইল। পড়া: যেখানে উত্তর ও উল্লেখ আপনার কাছে আসে। লেখা: যেখানে আপনার পোস্ট প্রকাশিত হয়।", + "relaysInbox": "সরাসরি বার্তার ইনবক্স: যেখানে লোকে আপনাকে ব্যক্তিগত বার্তা পাঠায়।", + "relaysRead": "পড়া", + "relaysWrite": "লেখা", + "relaysNoneYet": "এখনও প্রকাশিত হয়নি। এগুলো ডিফল্ট; প্রকাশ করতে সংরক্ষণ করুন।", + "relaysDown": "অপ্রাপ্য", + "relaysBadUrl": "এটি রিলে ঠিকানা নয় (wss://…)।", + "relaysNeedBoth": "অন্তত একটি পড়ার ও একটি লেখার রিলে রাখুন।", + "relaysNeedDm": "অন্তত একটি ইনবক্স রিলে রাখুন।", + "relaysUnchanged": "কিছুই বদলায়নি।", + "relaysWrongIdentity": "আপনার সাইনার অন্য অ্যাকাউন্টের। সেটিতে গিয়ে আবার চেষ্টা করুন।", + "relaysChangedElsewhere": "অন্য একটি অ্যাপ এইমাত্র আপনার রিলে তালিকা বদলেছে। আবার লোড করা হয়েছে; আপনার পরিবর্তনগুলো আবার করুন।", + "relaysSaved": "রিলে তালিকা সংরক্ষিত", + "relaysSave": "সংরক্ষণ", + "relaysSaving": "সংরক্ষণ হচ্ছে…", + "relaysReload": "আবার লোড" } diff --git a/src/locales/de.json b/src/locales/de.json index 9e2a615..d5f3d70 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -885,5 +885,23 @@ "feedRelaysFormHelp": "Diesen Feed nur von diesen Relays lesen. Leer lassen für die üblichen.", "feedAllToggle": "Jeder Beitrag auf diesen Relays (Firehose)", "feedAllCurated": "Nur beliebte Beiträge: Bots und Beiträge ohne Reaktionen ausblenden", - "feedAllNeedsRelays": "Nenne die Relays, von denen alles gelesen werden soll." + "feedAllNeedsRelays": "Nenne die Relays, von denen alles gelesen werden soll.", + "relaysTitle": "Relays", + "relaysDesc": "Wohin deine Beiträge gehen und wo andere Apps dich finden. Die Listen sind mit deinem Schlüssel signiert, jede Nostr-App folgt ihnen.", + "relaysPublic": "Beiträge und Profil. Lesen: wo dich Antworten und Erwähnungen erreichen. Schreiben: wo deine Beiträge veröffentlicht werden.", + "relaysInbox": "Posteingang für Direktnachrichten: wohin dir andere private Nachrichten schicken.", + "relaysRead": "Lesen", + "relaysWrite": "Schreiben", + "relaysNoneYet": "Noch nicht veröffentlicht. Das sind die Standardwerte; speichern, um sie zu veröffentlichen.", + "relaysDown": "nicht erreichbar", + "relaysBadUrl": "Das ist keine Relay-Adresse (wss://…).", + "relaysNeedBoth": "Behalte mindestens ein Lese- und ein Schreib-Relay.", + "relaysNeedDm": "Behalte mindestens ein Posteingangs-Relay.", + "relaysUnchanged": "Nichts geändert.", + "relaysWrongIdentity": "Dein Signer gehört zu einem anderen Konto. Wechsle dorthin und versuche es erneut.", + "relaysChangedElsewhere": "Eine andere App hat gerade deine Relay-Listen geändert. Sie wurden neu geladen; nimm deine Änderungen erneut vor.", + "relaysSaved": "Relay-Listen gespeichert", + "relaysSave": "Speichern", + "relaysSaving": "Speichern…", + "relaysReload": "Neu laden" } diff --git a/src/locales/es.json b/src/locales/es.json index 7340995..604a528 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -885,5 +885,23 @@ "feedRelaysFormHelp": "Lee este feed solo de estos relays. Déjalo vacío para usar los habituales.", "feedAllToggle": "Todas las publicaciones de estos relays (firehose)", "feedAllCurated": "Solo publicaciones populares: oculta bots y publicaciones sin reacciones", - "feedAllNeedsRelays": "Indica los relays de los que leerlo todo." + "feedAllNeedsRelays": "Indica los relays de los que leerlo todo.", + "relaysTitle": "Relés", + "relaysDesc": "Adónde van tus publicaciones y dónde te buscan otras apps. Las listas van firmadas con tu clave, así que todas tus apps de Nostr las siguen.", + "relaysPublic": "Publicaciones y perfil. Leer: donde te llegan respuestas y menciones. Escribir: donde se publican tus posts.", + "relaysInbox": "Bandeja de mensajes directos: donde te envían mensajes privados.", + "relaysRead": "Leer", + "relaysWrite": "Escribir", + "relaysNoneYet": "Aún no publicada. Son los valores por defecto; guarda para publicarlos.", + "relaysDown": "inaccesible", + "relaysBadUrl": "Eso no es una dirección de relé (wss://…).", + "relaysNeedBoth": "Deja al menos un relé de lectura y uno de escritura.", + "relaysNeedDm": "Deja al menos un relé de bandeja de entrada.", + "relaysUnchanged": "No hay cambios.", + "relaysWrongIdentity": "Tu firmante pertenece a otra cuenta. Cambia a ella e inténtalo de nuevo.", + "relaysChangedElsewhere": "Otra app acaba de cambiar tus listas de relés. Se recargaron; vuelve a hacer tus cambios.", + "relaysSaved": "Listas de relés guardadas", + "relaysSave": "Guardar", + "relaysSaving": "Guardando…", + "relaysReload": "Recargar" } diff --git a/src/locales/fr.json b/src/locales/fr.json index d6f90e8..22b41ed 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -885,5 +885,23 @@ "feedRelaysFormHelp": "Lire ce fil uniquement depuis ces relais. Laisser vide pour les relais habituels.", "feedAllToggle": "Toutes les publications de ces relais (firehose)", "feedAllCurated": "Seulement les publications populaires : masquer les bots et les publications sans réaction", - "feedAllNeedsRelays": "Indiquez les relais dont tout lire." + "feedAllNeedsRelays": "Indiquez les relais dont tout lire.", + "relaysTitle": "Relais", + "relaysDesc": "Où vont vos publications et où les autres applis vous trouvent. Les listes sont signées avec votre clé : toutes vos applis Nostr les suivent.", + "relaysPublic": "Publications et profil. Lecture : où vous parviennent réponses et mentions. Écriture : où vos publications sont envoyées.", + "relaysInbox": "Boîte de messages privés : où l’on vous envoie des messages directs.", + "relaysRead": "Lecture", + "relaysWrite": "Écriture", + "relaysNoneYet": "Pas encore publiée. Ce sont les valeurs par défaut ; enregistrez pour les publier.", + "relaysDown": "injoignable", + "relaysBadUrl": "Ce n’est pas une adresse de relais (wss://…).", + "relaysNeedBoth": "Gardez au moins un relais de lecture et un d’écriture.", + "relaysNeedDm": "Gardez au moins un relais de boîte de réception.", + "relaysUnchanged": "Rien n’a changé.", + "relaysWrongIdentity": "Votre signataire appartient à un autre compte. Passez-y et réessayez.", + "relaysChangedElsewhere": "Une autre appli vient de modifier vos listes de relais. Elles ont été rechargées ; refaites vos changements.", + "relaysSaved": "Listes de relais enregistrées", + "relaysSave": "Enregistrer", + "relaysSaving": "Enregistrement…", + "relaysReload": "Recharger" } diff --git a/src/locales/hi.json b/src/locales/hi.json index c619d57..bc7f7a8 100644 --- a/src/locales/hi.json +++ b/src/locales/hi.json @@ -885,5 +885,23 @@ "feedRelaysFormHelp": "यह फ़ीड सिर्फ़ इन रिले से पढ़ें। सामान्य रिले के लिए खाली छोड़ें।", "feedAllToggle": "इन रिले की हर पोस्ट (फ़ायरहोज़)", "feedAllCurated": "सिर्फ़ लोकप्रिय पोस्ट: बॉट और बिना प्रतिक्रिया वाली पोस्ट छिपाएँ", - "feedAllNeedsRelays": "वे रिले बताएँ जिनसे सब कुछ पढ़ना है।" + "feedAllNeedsRelays": "वे रिले बताएँ जिनसे सब कुछ पढ़ना है।", + "relaysTitle": "रिले", + "relaysDesc": "आपकी पोस्ट कहाँ जाती हैं और दूसरे ऐप आपको कहाँ ढूँढते हैं। सूचियाँ आपकी कुंजी से हस्ताक्षरित हैं, इसलिए आपके सभी Nostr ऐप इन्हें मानते हैं।", + "relaysPublic": "पोस्ट और प्रोफ़ाइल। पढ़ना: जहाँ जवाब और उल्लेख आप तक पहुँचते हैं। लिखना: जहाँ आपकी पोस्ट प्रकाशित होती हैं।", + "relaysInbox": "डायरेक्ट मैसेज इनबॉक्स: जहाँ लोग आपको निजी संदेश भेजते हैं।", + "relaysRead": "पढ़ना", + "relaysWrite": "लिखना", + "relaysNoneYet": "अभी प्रकाशित नहीं। ये डिफ़ॉल्ट हैं; प्रकाशित करने के लिए सहेजें।", + "relaysDown": "पहुँच से बाहर", + "relaysBadUrl": "यह रिले पता नहीं है (wss://…)।", + "relaysNeedBoth": "कम से कम एक पढ़ने और एक लिखने वाला रिले रखें।", + "relaysNeedDm": "कम से कम एक इनबॉक्स रिले रखें।", + "relaysUnchanged": "कुछ नहीं बदला।", + "relaysWrongIdentity": "आपका साइनर किसी दूसरे खाते का है। उस पर जाएँ और फिर कोशिश करें।", + "relaysChangedElsewhere": "किसी दूसरे ऐप ने अभी आपकी रिले सूचियाँ बदलीं। उन्हें फिर से लोड किया गया है; अपने बदलाव दोबारा करें।", + "relaysSaved": "रिले सूचियाँ सहेजी गईं", + "relaysSave": "सहेजें", + "relaysSaving": "सहेजा जा रहा है…", + "relaysReload": "फिर से लोड करें" } diff --git a/src/locales/id.json b/src/locales/id.json index 82c8e30..9318205 100644 --- a/src/locales/id.json +++ b/src/locales/id.json @@ -221,5 +221,23 @@ "feedRelaysFormHelp": "Baca feed ini hanya dari relay ini. Kosongkan untuk relay biasa.", "feedAllToggle": "Setiap postingan di relay ini (firehose)", "feedAllCurated": "Hanya postingan populer: sembunyikan bot dan postingan tanpa reaksi", - "feedAllNeedsRelays": "Sebutkan relay untuk membaca semuanya." + "feedAllNeedsRelays": "Sebutkan relay untuk membaca semuanya.", + "relaysTitle": "Relay", + "relaysDesc": "Ke mana postinganmu dikirim dan di mana aplikasi lain mencarimu. Daftar ini ditandatangani dengan kuncimu, jadi semua aplikasi Nostr mengikutinya.", + "relaysPublic": "Postingan dan profil. Baca: tempat balasan dan sebutan sampai kepadamu. Tulis: tempat postinganmu diterbitkan.", + "relaysInbox": "Kotak masuk pesan langsung: tempat orang mengirimimu pesan pribadi.", + "relaysRead": "Baca", + "relaysWrite": "Tulis", + "relaysNoneYet": "Belum diterbitkan. Ini nilai bawaan; simpan untuk menerbitkannya.", + "relaysDown": "tak terjangkau", + "relaysBadUrl": "Itu bukan alamat relay (wss://…).", + "relaysNeedBoth": "Sisakan setidaknya satu relay baca dan satu relay tulis.", + "relaysNeedDm": "Sisakan setidaknya satu relay kotak masuk.", + "relaysUnchanged": "Tidak ada perubahan.", + "relaysWrongIdentity": "Penandatanganmu milik akun lain. Beralih ke akun itu lalu coba lagi.", + "relaysChangedElsewhere": "Aplikasi lain baru saja mengubah daftar relaymu. Sudah dimuat ulang; ulangi perubahanmu.", + "relaysSaved": "Daftar relay disimpan", + "relaysSave": "Simpan", + "relaysSaving": "Menyimpan…", + "relaysReload": "Muat ulang" } diff --git a/src/locales/ja.json b/src/locales/ja.json index fed32fe..9e0e66a 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -885,5 +885,23 @@ "feedRelaysFormHelp": "このフィードはこれらのリレーからだけ読み込みます。空欄ならいつものリレーです。", "feedAllToggle": "これらのリレーのすべての投稿(ファイアホース)", "feedAllCurated": "人気の投稿のみ:ボットと反応のない投稿を隠す", - "feedAllNeedsRelays": "すべてを読み込むリレーを指定してください。" + "feedAllNeedsRelays": "すべてを読み込むリレーを指定してください。", + "relaysTitle": "リレー", + "relaysDesc": "投稿の送り先と、他のアプリがあなたを探す場所です。リストはあなたの鍵で署名されるので、使っているすべてのNostrアプリが従います。", + "relaysPublic": "投稿とプロフィール。読み取り:返信やメンションが届く場所。書き込み:投稿が公開される場所。", + "relaysInbox": "DMの受信箱:プライベートメッセージが送られてくる場所。", + "relaysRead": "読み取り", + "relaysWrite": "書き込み", + "relaysNoneYet": "まだ公開されていません。これは既定値です。保存すると公開されます。", + "relaysDown": "接続できません", + "relaysBadUrl": "リレーのアドレスではありません(wss://…)。", + "relaysNeedBoth": "読み取りと書き込みのリレーを少なくとも1つずつ残してください。", + "relaysNeedDm": "受信箱のリレーを少なくとも1つ残してください。", + "relaysUnchanged": "変更はありません。", + "relaysWrongIdentity": "署名者は別のアカウントのものです。そのアカウントに切り替えてやり直してください。", + "relaysChangedElsewhere": "別のアプリがリレーリストを更新しました。再読み込みしたので、もう一度変更してください。", + "relaysSaved": "リレーリストを保存しました", + "relaysSave": "保存", + "relaysSaving": "保存中…", + "relaysReload": "再読み込み" } diff --git a/src/locales/ko.json b/src/locales/ko.json index fd34ed5..cd7606b 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -884,5 +884,23 @@ "feedRelaysFormHelp": "이 피드를 이 릴레이에서만 읽습니다. 비워 두면 평소 릴레이를 씁니다.", "feedAllToggle": "이 릴레이의 모든 게시물 (파이어호스)", "feedAllCurated": "인기 게시물만: 봇과 반응 없는 게시물 숨기기", - "feedAllNeedsRelays": "모두 읽어 올 릴레이를 지정하세요." + "feedAllNeedsRelays": "모두 읽어 올 릴레이를 지정하세요.", + "relaysTitle": "릴레이", + "relaysDesc": "게시물이 가는 곳이자 다른 앱이 당신을 찾는 곳입니다. 목록은 당신의 키로 서명되어 모든 Nostr 앱이 따릅니다.", + "relaysPublic": "게시물과 프로필. 읽기: 답글과 멘션이 도착하는 곳. 쓰기: 게시물이 발행되는 곳.", + "relaysInbox": "DM 받은편지함: 사람들이 개인 메시지를 보내는 곳.", + "relaysRead": "읽기", + "relaysWrite": "쓰기", + "relaysNoneYet": "아직 발행되지 않았습니다. 기본값이며, 저장하면 발행됩니다.", + "relaysDown": "연결 불가", + "relaysBadUrl": "릴레이 주소가 아닙니다 (wss://…).", + "relaysNeedBoth": "읽기 릴레이와 쓰기 릴레이를 하나씩은 남겨 두세요.", + "relaysNeedDm": "받은편지함 릴레이를 하나 이상 남겨 두세요.", + "relaysUnchanged": "변경 사항이 없습니다.", + "relaysWrongIdentity": "서명자가 다른 계정의 것입니다. 해당 계정으로 전환한 뒤 다시 시도하세요.", + "relaysChangedElsewhere": "다른 앱이 방금 릴레이 목록을 바꿨습니다. 다시 불러왔으니 변경을 다시 해 주세요.", + "relaysSaved": "릴레이 목록 저장됨", + "relaysSave": "저장", + "relaysSaving": "저장 중…", + "relaysReload": "새로고침" } diff --git a/src/locales/mr.json b/src/locales/mr.json index 8fdb6db..38a9b86 100644 --- a/src/locales/mr.json +++ b/src/locales/mr.json @@ -221,5 +221,23 @@ "feedRelaysFormHelp": "ही फीड फक्त या रिलेवरून वाचा. नेहमीच्या रिलेसाठी रिकामे ठेवा.", "feedAllToggle": "या रिलेवरील प्रत्येक पोस्ट (फायरहोज)", "feedAllCurated": "फक्त लोकप्रिय पोस्ट: बॉट्स आणि प्रतिसाद नसलेल्या पोस्ट लपवा", - "feedAllNeedsRelays": "सर्व काही कोणत्या रिलेवरून वाचायचे ते सांगा." + "feedAllNeedsRelays": "सर्व काही कोणत्या रिलेवरून वाचायचे ते सांगा.", + "relaysTitle": "रिले", + "relaysDesc": "तुमच्या पोस्ट कुठे जातात आणि इतर अॅप्स तुम्हाला कुठे शोधतात. याद्या तुमच्या कीने स्वाक्षरीत असल्याने तुमची सर्व Nostr अॅप्स त्या पाळतात.", + "relaysPublic": "पोस्ट आणि प्रोफाइल. वाचन: जिथे उत्तरे आणि उल्लेख तुमच्यापर्यंत पोहोचतात. लेखन: जिथे तुमच्या पोस्ट प्रकाशित होतात.", + "relaysInbox": "थेट संदेश इनबॉक्स: जिथे लोक तुम्हाला खाजगी संदेश पाठवतात.", + "relaysRead": "वाचन", + "relaysWrite": "लेखन", + "relaysNoneYet": "अजून प्रकाशित नाही. हे डीफॉल्ट आहेत; प्रकाशित करण्यासाठी जतन करा.", + "relaysDown": "पोहोचता येत नाही", + "relaysBadUrl": "हा रिले पत्ता नाही (wss://…).", + "relaysNeedBoth": "किमान एक वाचन आणि एक लेखन रिले ठेवा.", + "relaysNeedDm": "किमान एक इनबॉक्स रिले ठेवा.", + "relaysUnchanged": "काहीही बदलले नाही.", + "relaysWrongIdentity": "तुमचा सायनर दुसऱ्या खात्याचा आहे. त्यावर जा आणि पुन्हा प्रयत्न करा.", + "relaysChangedElsewhere": "दुसऱ्या अॅपने आत्ताच तुमच्या रिले याद्या बदलल्या. त्या पुन्हा लोड केल्या; तुमचे बदल पुन्हा करा.", + "relaysSaved": "रिले याद्या जतन केल्या", + "relaysSave": "जतन करा", + "relaysSaving": "जतन होत आहे…", + "relaysReload": "पुन्हा लोड करा" } diff --git a/src/locales/pt.json b/src/locales/pt.json index 84fa205..aaa25a5 100644 --- a/src/locales/pt.json +++ b/src/locales/pt.json @@ -885,5 +885,23 @@ "feedRelaysFormHelp": "Ler este feed só destes relays. Deixe em branco para os habituais.", "feedAllToggle": "Todas as publicações destes relays (firehose)", "feedAllCurated": "Só publicações populares: ocultar bots e publicações sem reações", - "feedAllNeedsRelays": "Indique os relays de onde ler tudo." + "feedAllNeedsRelays": "Indique os relays de onde ler tudo.", + "relaysTitle": "Relays", + "relaysDesc": "Para onde vão suas publicações e onde outros apps procuram você. As listas são assinadas com sua chave, então todo app Nostr que você usa as segue.", + "relaysPublic": "Publicações e perfil. Ler: onde respostas e menções chegam a você. Escrever: onde suas publicações são enviadas.", + "relaysInbox": "Caixa de mensagens diretas: para onde enviam suas mensagens privadas.", + "relaysRead": "Ler", + "relaysWrite": "Escrever", + "relaysNoneYet": "Ainda não publicada. Estes são os padrões; salve para publicá-los.", + "relaysDown": "inacessível", + "relaysBadUrl": "Isso não é um endereço de relay (wss://…).", + "relaysNeedBoth": "Mantenha pelo menos um relay de leitura e um de escrita.", + "relaysNeedDm": "Mantenha pelo menos um relay de caixa de entrada.", + "relaysUnchanged": "Nada mudou.", + "relaysWrongIdentity": "Seu assinante pertence a outra conta. Mude para ela e tente de novo.", + "relaysChangedElsewhere": "Outro app acabou de alterar suas listas de relays. Elas foram recarregadas; refaça suas alterações.", + "relaysSaved": "Listas de relays salvas", + "relaysSave": "Salvar", + "relaysSaving": "Salvando…", + "relaysReload": "Recarregar" } diff --git a/src/locales/ru.json b/src/locales/ru.json index e8c0155..c8af847 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -885,5 +885,23 @@ "feedRelaysFormHelp": "Читать эту ленту только с этих реле. Оставьте пустым для обычных.", "feedAllToggle": "Все посты на этих реле (поток)", "feedAllCurated": "Только популярные: скрыть ботов и посты без реакций", - "feedAllNeedsRelays": "Укажите реле, с которых читать всё." + "feedAllNeedsRelays": "Укажите реле, с которых читать всё.", + "relaysTitle": "Реле", + "relaysDesc": "Куда уходят ваши посты и где другие приложения вас ищут. Списки подписаны вашим ключом, поэтому им следуют все ваши Nostr-приложения.", + "relaysPublic": "Посты и профиль. Чтение: куда приходят ответы и упоминания. Запись: куда публикуются ваши посты.", + "relaysInbox": "Входящие личных сообщений: куда вам пишут лично.", + "relaysRead": "Чтение", + "relaysWrite": "Запись", + "relaysNoneYet": "Ещё не опубликован. Это значения по умолчанию; сохраните, чтобы опубликовать.", + "relaysDown": "недоступно", + "relaysBadUrl": "Это не адрес реле (wss://…).", + "relaysNeedBoth": "Оставьте хотя бы одно реле для чтения и одно для записи.", + "relaysNeedDm": "Оставьте хотя бы одно реле для входящих.", + "relaysUnchanged": "Ничего не изменилось.", + "relaysWrongIdentity": "Ваш подписант принадлежит другому аккаунту. Переключитесь на него и попробуйте снова.", + "relaysChangedElsewhere": "Другое приложение только что изменило ваши списки реле. Они перезагружены; внесите изменения заново.", + "relaysSaved": "Списки реле сохранены", + "relaysSave": "Сохранить", + "relaysSaving": "Сохранение…", + "relaysReload": "Обновить" } diff --git a/src/locales/sw.json b/src/locales/sw.json index 57ff264..4a5267c 100644 --- a/src/locales/sw.json +++ b/src/locales/sw.json @@ -221,5 +221,23 @@ "feedRelaysFormHelp": "Soma mlisho huu kutoka relay hizi tu. Acha tupu kwa zile za kawaida.", "feedAllToggle": "Kila chapisho kwenye relay hizi (firehose)", "feedAllCurated": "Machapisho maarufu tu: ficha boti na machapisho yasiyo na majibu", - "feedAllNeedsRelays": "Taja relay za kusoma kila kitu." + "feedAllNeedsRelays": "Taja relay za kusoma kila kitu.", + "relaysTitle": "Relei", + "relaysDesc": "Machapisho yako yanakoenda na mahali programu nyingine zinapokutafuta. Orodha zimesainiwa kwa ufunguo wako, hivyo kila programu ya Nostr inazifuata.", + "relaysPublic": "Machapisho na wasifu. Kusoma: majibu na kutajwa kunapokufikia. Kuandika: machapisho yako yanapochapishwa.", + "relaysInbox": "Kikasha cha jumbe za moja kwa moja: watu wanapokutumia jumbe za faragha.", + "relaysRead": "Soma", + "relaysWrite": "Andika", + "relaysNoneYet": "Bado haijachapishwa. Hizi ni chaguo-msingi; hifadhi ili kuzichapisha.", + "relaysDown": "haifikiki", + "relaysBadUrl": "Hiyo si anwani ya relei (wss://…).", + "relaysNeedBoth": "Acha angalau relei moja ya kusoma na moja ya kuandika.", + "relaysNeedDm": "Acha angalau relei moja ya kikasha.", + "relaysUnchanged": "Hakuna kilichobadilika.", + "relaysWrongIdentity": "Kitia-sahihi chako ni cha akaunti nyingine. Badili kwenda huko kisha ujaribu tena.", + "relaysChangedElsewhere": "Programu nyingine imebadilisha orodha zako za relei sasa hivi. Zimepakiwa upya; fanya mabadiliko yako tena.", + "relaysSaved": "Orodha za relei zimehifadhiwa", + "relaysSave": "Hifadhi", + "relaysSaving": "Inahifadhi…", + "relaysReload": "Pakia upya" } diff --git a/src/locales/ta.json b/src/locales/ta.json index 0cb5244..cf032ac 100644 --- a/src/locales/ta.json +++ b/src/locales/ta.json @@ -221,5 +221,23 @@ "feedRelaysFormHelp": "இந்த ஊட்டத்தை இந்த ரிலேக்களிலிருந்து மட்டும் படிக்கவும். வழக்கமானவற்றுக்கு காலியாக விடவும்.", "feedAllToggle": "இந்த ரிலேக்களில் உள்ள ஒவ்வொரு பதிவும் (ஃபயர்ஹோஸ்)", "feedAllCurated": "பிரபல பதிவுகள் மட்டும்: பாட்களையும் எதிர்வினையற்ற பதிவுகளையும் மறை", - "feedAllNeedsRelays": "அனைத்தையும் படிக்க வேண்டிய ரிலேக்களைக் குறிப்பிடவும்." + "feedAllNeedsRelays": "அனைத்தையும் படிக்க வேண்டிய ரிலேக்களைக் குறிப்பிடவும்.", + "relaysTitle": "ரிலேக்கள்", + "relaysDesc": "உங்கள் இடுகைகள் எங்கு செல்கின்றன, பிற செயலிகள் உங்களை எங்கு தேடுகின்றன. பட்டியல்கள் உங்கள் சாவியால் கையொப்பமிடப்படுவதால் எல்லா Nostr செயலிகளும் அவற்றைப் பின்பற்றும்.", + "relaysPublic": "இடுகைகள் மற்றும் சுயவிவரம். படித்தல்: பதில்களும் குறிப்புகளும் உங்களை அடையும் இடம். எழுதுதல்: உங்கள் இடுகைகள் வெளியிடப்படும் இடம்.", + "relaysInbox": "நேரடி செய்தி இன்பாக்ஸ்: மக்கள் உங்களுக்குத் தனிப்பட்ட செய்திகள் அனுப்பும் இடம்.", + "relaysRead": "படித்தல்", + "relaysWrite": "எழுதுதல்", + "relaysNoneYet": "இன்னும் வெளியிடப்படவில்லை. இவை இயல்புநிலைகள்; வெளியிடச் சேமிக்கவும்.", + "relaysDown": "அணுக முடியவில்லை", + "relaysBadUrl": "இது ரிலே முகவரி அல்ல (wss://…).", + "relaysNeedBoth": "குறைந்தது ஒரு படிக்கும் ரிலேவும் ஒரு எழுதும் ரிலேவும் வைத்திருங்கள்.", + "relaysNeedDm": "குறைந்தது ஒரு இன்பாக்ஸ் ரிலே வைத்திருங்கள்.", + "relaysUnchanged": "எதுவும் மாறவில்லை.", + "relaysWrongIdentity": "உங்கள் கையொப்பமிடுபவர் வேறொரு கணக்கைச் சேர்ந்தது. அதற்கு மாறி மீண்டும் முயலவும்.", + "relaysChangedElsewhere": "வேறொரு செயலி இப்போது உங்கள் ரிலே பட்டியல்களை மாற்றியது. மீண்டும் ஏற்றப்பட்டது; உங்கள் மாற்றங்களை மீண்டும் செய்யவும்.", + "relaysSaved": "ரிலே பட்டியல்கள் சேமிக்கப்பட்டன", + "relaysSave": "சேமி", + "relaysSaving": "சேமிக்கிறது…", + "relaysReload": "மீண்டும் ஏற்று" } diff --git a/src/locales/te.json b/src/locales/te.json index 9f468e6..f45ad3e 100644 --- a/src/locales/te.json +++ b/src/locales/te.json @@ -219,5 +219,23 @@ "feedRelaysFormHelp": "ఈ ఫీడ్ను ఈ రిలేల నుంచి మాత్రమే చదవండి. సాధారణ వాటికి ఖాళీగా ఉంచండి.", "feedAllToggle": "ఈ రిలేలలోని ప్రతి పోస్ట్ (ఫైర్హోస్)", "feedAllCurated": "జనాదరణ పొందిన పోస్ట్లు మాత్రమే: బాట్లు, స్పందన లేని పోస్ట్లను దాచు", - "feedAllNeedsRelays": "అన్నీ చదవాల్సిన రిలేలను పేర్కొనండి." + "feedAllNeedsRelays": "అన్నీ చదవాల్సిన రిలేలను పేర్కొనండి.", + "relaysTitle": "రిలేలు", + "relaysDesc": "మీ పోస్ట్లు ఎక్కడికి వెళ్తాయి, ఇతర యాప్లు మిమ్మల్ని ఎక్కడ వెతుకుతాయి. జాబితాలు మీ కీతో సంతకం చేయబడతాయి, కాబట్టి మీ అన్ని Nostr యాప్లు వాటిని అనుసరిస్తాయి.", + "relaysPublic": "పోస్ట్లు మరియు ప్రొఫైల్. చదవడం: జవాబులు, ప్రస్తావనలు మీకు చేరే చోటు. రాయడం: మీ పోస్ట్లు ప్రచురించబడే చోటు.", + "relaysInbox": "నేరుగా సందేశాల ఇన్బాక్స్: ప్రజలు మీకు ప్రైవేట్ సందేశాలు పంపే చోటు.", + "relaysRead": "చదవడం", + "relaysWrite": "రాయడం", + "relaysNoneYet": "ఇంకా ప్రచురించలేదు. ఇవి డిఫాల్ట్లు; ప్రచురించడానికి సేవ్ చేయండి.", + "relaysDown": "చేరుకోలేము", + "relaysBadUrl": "ఇది రిలే చిరునామా కాదు (wss://…).", + "relaysNeedBoth": "కనీసం ఒక చదివే రిలే, ఒక రాసే రిలే ఉంచండి.", + "relaysNeedDm": "కనీసం ఒక ఇన్బాక్స్ రిలే ఉంచండి.", + "relaysUnchanged": "ఏమీ మారలేదు.", + "relaysWrongIdentity": "మీ సైనర్ వేరే ఖాతాది. దానికి మారి మళ్లీ ప్రయత్నించండి.", + "relaysChangedElsewhere": "వేరే యాప్ ఇప్పుడే మీ రిలే జాబితాలను మార్చింది. మళ్లీ లోడ్ చేశాం; మీ మార్పులు మళ్లీ చేయండి.", + "relaysSaved": "రిలే జాబితాలు సేవ్ అయ్యాయి", + "relaysSave": "సేవ్", + "relaysSaving": "సేవ్ అవుతోంది…", + "relaysReload": "మళ్లీ లోడ్" } diff --git a/src/locales/tr.json b/src/locales/tr.json index a26da16..b779157 100644 --- a/src/locales/tr.json +++ b/src/locales/tr.json @@ -884,5 +884,23 @@ "feedRelaysFormHelp": "Bu akışı yalnızca bu rölelerden oku. Her zamankiler için boş bırak.", "feedAllToggle": "Bu rölelerdeki her gönderi (firehose)", "feedAllCurated": "Yalnızca popüler gönderiler: botları ve tepki almamış gönderileri gizle", - "feedAllNeedsRelays": "Her şeyin okunacağı röleleri yaz." + "feedAllNeedsRelays": "Her şeyin okunacağı röleleri yaz.", + "relaysTitle": "Röleler", + "relaysDesc": "Gönderilerinin gittiği ve diğer uygulamaların seni aradığı yer. Listeler anahtarınla imzalanır, kullandığın her Nostr uygulaması onlara uyar.", + "relaysPublic": "Gönderiler ve profil. Okuma: yanıtların ve bahsetmelerin sana ulaştığı yer. Yazma: gönderilerinin yayımlandığı yer.", + "relaysInbox": "Doğrudan mesaj kutusu: insanların sana özel mesaj gönderdiği yer.", + "relaysRead": "Okuma", + "relaysWrite": "Yazma", + "relaysNoneYet": "Henüz yayımlanmadı. Bunlar varsayılanlar; yayımlamak için kaydet.", + "relaysDown": "ulaşılamıyor", + "relaysBadUrl": "Bu bir röle adresi değil (wss://…).", + "relaysNeedBoth": "En az bir okuma ve bir yazma rölesi bırak.", + "relaysNeedDm": "En az bir gelen kutusu rölesi bırak.", + "relaysUnchanged": "Değişiklik yok.", + "relaysWrongIdentity": "İmzalayıcın başka bir hesaba ait. O hesaba geçip tekrar dene.", + "relaysChangedElsewhere": "Başka bir uygulama röle listelerini az önce değiştirdi. Yeniden yüklendi; değişikliklerini tekrar yap.", + "relaysSaved": "Röle listeleri kaydedildi", + "relaysSave": "Kaydet", + "relaysSaving": "Kaydediliyor…", + "relaysReload": "Yenile" } diff --git a/src/locales/ur.json b/src/locales/ur.json index c6a6fe4..ff7f461 100644 --- a/src/locales/ur.json +++ b/src/locales/ur.json @@ -221,5 +221,23 @@ "feedRelaysFormHelp": "یہ فیڈ صرف ان ریلے سے پڑھیں۔ معمول کے ریلے کے لیے خالی چھوڑ دیں۔", "feedAllToggle": "ان ریلے پر ہر پوسٹ (فائر ہوز)", "feedAllCurated": "صرف مقبول پوسٹس: بوٹس اور بغیر ردعمل والی پوسٹس چھپائیں", - "feedAllNeedsRelays": "وہ ریلے بتائیں جن سے سب کچھ پڑھنا ہے۔" + "feedAllNeedsRelays": "وہ ریلے بتائیں جن سے سب کچھ پڑھنا ہے۔", + "relaysTitle": "ریلے", + "relaysDesc": "آپ کی پوسٹس کہاں جاتی ہیں اور دوسری ایپس آپ کو کہاں تلاش کرتی ہیں۔ فہرستیں آپ کی کلید سے دستخط شدہ ہیں، اس لیے آپ کی تمام Nostr ایپس ان کی پیروی کرتی ہیں۔", + "relaysPublic": "پوسٹس اور پروفائل۔ پڑھنا: جہاں جوابات اور تذکرے آپ تک پہنچتے ہیں۔ لکھنا: جہاں آپ کی پوسٹس شائع ہوتی ہیں۔", + "relaysInbox": "براہ راست پیغامات کا ان باکس: جہاں لوگ آپ کو نجی پیغامات بھیجتے ہیں۔", + "relaysRead": "پڑھنا", + "relaysWrite": "لکھنا", + "relaysNoneYet": "ابھی شائع نہیں ہوئی۔ یہ ڈیفالٹ ہیں؛ شائع کرنے کے لیے محفوظ کریں۔", + "relaysDown": "رسائی نہیں", + "relaysBadUrl": "یہ ریلے کا پتا نہیں ہے (wss://…)۔", + "relaysNeedBoth": "کم از کم ایک پڑھنے اور ایک لکھنے والا ریلے رکھیں۔", + "relaysNeedDm": "کم از کم ایک ان باکس ریلے رکھیں۔", + "relaysUnchanged": "کچھ نہیں بدلا۔", + "relaysWrongIdentity": "آپ کا سائنر کسی اور اکاؤنٹ کا ہے۔ اس پر جائیں اور دوبارہ کوشش کریں۔", + "relaysChangedElsewhere": "کسی اور ایپ نے ابھی آپ کی ریلے فہرستیں بدلیں۔ دوبارہ لوڈ کر دی گئیں؛ اپنی تبدیلیاں پھر سے کریں۔", + "relaysSaved": "ریلے فہرستیں محفوظ ہو گئیں", + "relaysSave": "محفوظ کریں", + "relaysSaving": "محفوظ ہو رہا ہے…", + "relaysReload": "دوبارہ لوڈ کریں" } diff --git a/src/locales/vi.json b/src/locales/vi.json index 963aa21..162d73f 100644 --- a/src/locales/vi.json +++ b/src/locales/vi.json @@ -221,5 +221,23 @@ "feedRelaysFormHelp": "Chỉ đọc bảng tin này từ các relay này. Để trống để dùng relay thường dùng.", "feedAllToggle": "Mọi bài đăng trên các relay này (firehose)", "feedAllCurated": "Chỉ bài phổ biến: ẩn bot và bài không ai tương tác", - "feedAllNeedsRelays": "Hãy nêu các relay để đọc mọi thứ." + "feedAllNeedsRelays": "Hãy nêu các relay để đọc mọi thứ.", + "relaysTitle": "Relay", + "relaysDesc": "Nơi bài đăng của bạn được gửi tới và nơi các ứng dụng khác tìm bạn. Danh sách được ký bằng khóa của bạn nên mọi ứng dụng Nostr đều theo.", + "relaysPublic": "Bài đăng và hồ sơ. Đọc: nơi trả lời và lượt nhắc đến bạn. Ghi: nơi bài đăng của bạn được xuất bản.", + "relaysInbox": "Hộp thư tin nhắn riêng: nơi mọi người gửi tin nhắn riêng cho bạn.", + "relaysRead": "Đọc", + "relaysWrite": "Ghi", + "relaysNoneYet": "Chưa xuất bản. Đây là mặc định; lưu để xuất bản.", + "relaysDown": "không kết nối được", + "relaysBadUrl": "Đó không phải địa chỉ relay (wss://…).", + "relaysNeedBoth": "Giữ ít nhất một relay đọc và một relay ghi.", + "relaysNeedDm": "Giữ ít nhất một relay hộp thư.", + "relaysUnchanged": "Không có gì thay đổi.", + "relaysWrongIdentity": "Trình ký của bạn thuộc tài khoản khác. Hãy chuyển sang tài khoản đó rồi thử lại.", + "relaysChangedElsewhere": "Một ứng dụng khác vừa thay đổi danh sách relay của bạn. Đã tải lại; hãy thực hiện lại thay đổi.", + "relaysSaved": "Đã lưu danh sách relay", + "relaysSave": "Lưu", + "relaysSaving": "Đang lưu…", + "relaysReload": "Tải lại" } diff --git a/src/locales/zh.json b/src/locales/zh.json index 3fa5e4d..995575e 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -885,5 +885,23 @@ "feedRelaysFormHelp": "仅从这些中继读取此动态。留空则使用常用中继。", "feedAllToggle": "这些中继上的每一条帖子(全量流)", "feedAllCurated": "仅热门帖子:隐藏机器人和无人互动的帖子", - "feedAllNeedsRelays": "请填写要读取全部内容的中继。" + "feedAllNeedsRelays": "请填写要读取全部内容的中继。", + "relaysTitle": "中继", + "relaysDesc": "你的帖子发往哪里,其他应用到哪里找你。列表由你的密钥签名,你用的所有 Nostr 应用都会遵循。", + "relaysPublic": "帖子和资料。读取:回复和提及到达的地方。写入:你的帖子发布的地方。", + "relaysInbox": "私信收件箱:别人给你发私信的地方。", + "relaysRead": "读取", + "relaysWrite": "写入", + "relaysNoneYet": "尚未发布。这些是默认值,保存即可发布。", + "relaysDown": "无法连接", + "relaysBadUrl": "这不是中继地址(wss://…)。", + "relaysNeedBoth": "请至少保留一个读取中继和一个写入中继。", + "relaysNeedDm": "请至少保留一个收件箱中继。", + "relaysUnchanged": "没有更改。", + "relaysWrongIdentity": "你的签名器属于另一个账户。请切换到该账户后重试。", + "relaysChangedElsewhere": "另一个应用刚刚更新了你的中继列表。已重新加载,请重新修改。", + "relaysSaved": "中继列表已保存", + "relaysSave": "保存", + "relaysSaving": "正在保存…", + "relaysReload": "重新加载" } |
