Merge branch 'main' into vite
continuous-integration/drone/pr Build encountered an error Details

This commit is contained in:
Martti Malmi 2023-11-20 17:15:50 +02:00
commit 4133823b82
38 changed files with 321 additions and 97 deletions

View File

@ -24,7 +24,7 @@ Snort supports the following NIP's:
- [x] NIP-25: Reactions
- [x] NIP-26: Delegated Event Signing (Display delegated signings only)
- [x] NIP-27: Text note references
- [ ] NIP-28: Public Chat
- [x] NIP-28: Public Chat
- [x] NIP-30: Custom Emoji
- [x] NIP-31: Alt tag for unknown events
- [x] NIP-36: Sensitive Content
@ -43,7 +43,7 @@ Snort supports the following NIP's:
- [x] NIP-59: Gift Wrap
- [x] NIP-65: Relay List Metadata
- [x] NIP-75: Zap Goals
- [ ] NIP-78: App specific data
- [x] NIP-78: App specific data
- [ ] NIP-89: App handlers
- [x] NIP-94: File Metadata
- [x] NIP-98: HTTP Auth
@ -58,7 +58,7 @@ To run the application, use
$ yarn start
```
To build the application and nostr package, use
To build the application and system packages, use
```
$ yarn build
@ -73,8 +73,7 @@ Translations are managed on [Crowdin](https://crowdin.com/project/snort)
To extract translations run:
```bash
yarn workspace @snort/app intl-extract
yarn workspace @snort/app intl-compile
yarn pre:commit
```
This will create the source file `packages/app/src/translations/en.json`

View File

@ -20,6 +20,6 @@
"defaultRelays": {
"wss://relay.snort.social/": { "read": true, "write": true },
"wss://nostr.wine/": { "read": true, "write": false },
"wss://nos.lol/": { "read": true, "write": true }
"wss://eden.nostr.land/": { "read": true, "write": false }
}
}

View File

@ -19,6 +19,6 @@
"defaultRelays": {
"wss://relay.snort.social/": { "read": true, "write": true },
"wss://nostr.wine/": { "read": true, "write": false },
"wss://nos.lol/": { "read": true, "write": true }
"wss://eden.nostr.land/": { "read": true, "write": false }
}
}

View File

@ -59,6 +59,11 @@ export const DefaultImgProxy = {
*/
export const DerivationPath = "m/44'/1237'/0'/0/0";
/**
* Blaster relays
*/
export const Blasters = ["wss://nostr.mutinywallet.com"];
/**
* Regex to match email address
*/

View File

@ -14,7 +14,7 @@ export default function Mention({ link }: { link: NostrLink }) {
return (
<>
<ProfileLink pubkey={link.id} user={profile} onClick={e => e.stopPropagation()}>
<ProfileLink pubkey={link.id} link={link} user={profile} onClick={e => e.stopPropagation()}>
<span ref={ref}>
@<DisplayName user={profile} pubkey={link.id} />
</span>

View File

@ -8,6 +8,10 @@ export default function NostrLink({ link, depth }: { link: string; depth?: numbe
const nav = tryParseNostrLink(link);
if (nav?.type === NostrPrefix.PublicKey || nav?.type === NostrPrefix.Profile) {
if (nav.id.startsWith("npub")) {
// eslint-disable-next-line no-debugger
debugger;
}
return <Mention link={nav} />;
} else if (nav?.type === NostrPrefix.Note || nav?.type === NostrPrefix.Event || nav?.type === NostrPrefix.Address) {
if ((depth ?? 0) > 0) {

View File

@ -1,5 +1,4 @@
.relay {
background-color: var(--gray-secondary);
border-radius: 5px;
display: grid;
grid-template-columns: min-content auto;

View File

@ -41,7 +41,7 @@ export default function Relay(props: RelayProps) {
return (
<>
<div className="relay">
<div className="relay bg-dark">
<div className={classNames("flex items-center", state?.connected ? "bg-success" : "bg-error")}>
<RelayFavicon url={props.addr} />
</div>

View File

@ -68,6 +68,16 @@ export interface TranslationResponse {
}>;
}
export interface RelayDistance {
url: string;
distance: number;
users: number;
country?: string;
city?: string;
is_paid?: boolean;
description?: string;
}
export default class SnortApi {
#url: string;
#publisher?: EventPublisher;
@ -121,6 +131,10 @@ export default class SnortApi {
return this.#getJson<TranslationResponse | object>("api/v1/translate", "POST", tx);
}
closeRelays(lat: number, lon: number, count = 5) {
return this.#getJson<Array<RelayDistance>>(`api/v1/relays?count=${count}`, "POST", { lat, lon });
}
async #getJsonAuthd<T>(
path: string,
method?: "GET" | string,

View File

@ -12,13 +12,14 @@ import { unixNowMs } from "@snort/shared";
import * as secp from "@noble/curves/secp256k1";
import * as utils from "@noble/curves/abstract/utils";
import { DefaultRelays, SnortPubKey } from "@/Const";
import { Blasters, SnortPubKey } from "@/Const";
import { LoginStore, UserPreferences, LoginSession, LoginSessionType, SnortAppData, Newest } from "@/Login";
import { generateBip39Entropy, entropyToPrivateKey } from "@/nip6";
import { bech32ToHex, dedupeById, sanitizeRelayUrl, unwrap } from "@/SnortUtils";
import { bech32ToHex, dedupeById, getCountry, sanitizeRelayUrl, unwrap } from "@/SnortUtils";
import { SubscriptionEvent } from "@/Subscription";
import { Chats, FollowsFeed, GiftsCache, Notifications } from "@/Cache";
import { Nip7OsSigner } from "./Nip7OsSigner";
import SnortApi from "@/External/SnortApi";
export function setRelays(state: LoginSession, relays: Record<string, RelaySettings>, createdAt: number) {
if (SINGLE_RELAY) {
@ -92,7 +93,22 @@ export async function generateNewLogin(
const ent = generateBip39Entropy();
const entropy = utils.bytesToHex(ent);
const privateKey = entropyToPrivateKey(ent);
const newRelays = Object.fromEntries(DefaultRelays.entries());
const newRelays = {} as Record<string, RelaySettings>;
// Use current timezone info to determine approx location
// use closest 5 relays
const country = getCountry();
const api = new SnortApi();
const closeRelays = await api.closeRelays(country.lat, country.lon, 20);
for (const cr of closeRelays.sort((a, b) => (a.distance > b.distance ? 1 : -1)).filter(a => !a.is_paid)) {
const rr = sanitizeRelayUrl(cr.url);
if (rr) {
newRelays[rr] = { read: true, write: true };
if (Object.keys(newRelays).length >= 5) {
break;
}
}
}
// connect to new relays
await Promise.all(Object.entries(newRelays).map(([k, v]) => system.ConnectToRelay(k, v)));
@ -107,10 +123,12 @@ export async function generateNewLogin(
// Create relay metadata event
const ev2 = await publisher.relayList(newRelays);
await system.BroadcastEvent(ev2);
await Promise.all(Blasters.map(a => system.WriteOnceToRelay(a, ev2)));
// Publish new profile
const ev3 = await publisher.metadata(profile);
await system.BroadcastEvent(ev3);
await Promise.all(Blasters.map(a => system.WriteOnceToRelay(a, ev3)));
LoginStore.loginWithPrivateKey(await pin(privateKey), entropy, newRelays);
}

View File

@ -11,7 +11,7 @@ import { Bar, BarChart, Tooltip, XAxis, YAxis } from "recharts";
import useLogin from "@/Hooks/useLogin";
import { markNotificationsRead } from "@/Login";
import { Notifications } from "@/Cache";
import { dedupe, findTag, orderAscending, orderDescending, getDisplayName } from "@/SnortUtils";
import { dedupe, orderAscending, orderDescending, getDisplayName } from "@/SnortUtils";
import Icon from "@/Icons/Icon";
import ProfileImage from "@/Element/User/ProfileImage";
import useModeration from "@/Hooks/useModeration";
@ -28,18 +28,17 @@ import { ShowMoreInView } from "@/Element/Event/ShowMore";
function notificationContext(ev: TaggedNostrEvent) {
switch (ev.kind) {
case EventKind.ZapReceipt: {
const aTag = findTag(ev, "a");
const aTag = ev.tags.find(a => a[0] === "a");
if (aTag) {
const [kind, author, d] = aTag.split(":");
return new NostrLink(NostrPrefix.Address, d, Number(kind), author);
return NostrLink.fromTag(aTag);
}
const eTag = findTag(ev, "e");
const eTag = ev.tags.find(a => a[0] === "e");
if (eTag) {
return new NostrLink(CONFIG.eventLinkPrefix, eTag);
return NostrLink.fromTag(eTag);
}
const pTag = ev.tags.filter(a => a[0] === "p").slice(-1)?.[0];
const pTag = ev.tags.find(a => a[0] === "p");
if (pTag) {
return new NostrLink(NostrPrefix.PublicKey, pTag[1]);
return NostrLink.fromTag(pTag);
}
break;
}
@ -47,17 +46,14 @@ function notificationContext(ev: TaggedNostrEvent) {
case EventKind.Reaction: {
const thread = EventExt.extractThread(ev);
const tag = unwrap(thread?.replyTo ?? thread?.root ?? { value: ev.id, key: "e" });
if (tag.key === "e") {
return new NostrLink(CONFIG.eventLinkPrefix, unwrap(tag.value));
} else if (tag.key === "a") {
const [kind, author, d] = unwrap(tag.value).split(":");
return new NostrLink(NostrPrefix.Address, d, Number(kind), author);
if (tag.key === "e" || tag.key === "a") {
return NostrLink.fromThreadTag(tag);
} else {
throw new Error("Unknown thread context");
}
}
case EventKind.TextNote: {
return new NostrLink(NostrPrefix.Note, ev.id);
return NostrLink.fromEvent(ev);
}
}
}

View File

@ -1,6 +1,6 @@
import { useMemo, useState } from "react";
import { useEffect, useMemo, useState } from "react";
import { FormattedMessage } from "react-intl";
import { unixNowMs } from "@snort/shared";
import { unixNowMs, unwrap } from "@snort/shared";
import { EventPublisher, FullRelaySettings, RelaySettings, SystemInterface } from "@snort/system";
import Relay from "@/Element/Relay/Relay";
@ -8,11 +8,13 @@ import useEventPublisher from "@/Hooks/useEventPublisher";
import useLogin from "@/Hooks/useLogin";
import { setRelays } from "@/Login";
import AsyncButton from "@/Element/AsyncButton";
import SnortApi, { RelayDistance } from "@/External/SnortApi";
import { getCountry, getRelayName, sanitizeRelayUrl } from "@/SnortUtils";
import { formatShort } from "@/Number";
import { Blasters } from "@/Const";
import messages from "./messages";
const Blasters = ["wss://nostr.mutinywallet.com"];
export async function saveRelays(
system: SystemInterface,
publisher: EventPublisher | undefined,
@ -88,6 +90,7 @@ const RelaySettingsPage = () => {
<FormattedMessage {...messages.Save} />
</AsyncButton>
{addRelay()}
<CloseRelays />
<h3>
<FormattedMessage defaultMessage="Other Connections" id="LF5kYT" />
</h3>
@ -101,3 +104,89 @@ const RelaySettingsPage = () => {
};
export default RelaySettingsPage;
export function CloseRelays() {
const [relays, setRecommendedRelays] = useState<Array<RelayDistance>>();
const country = getCountry();
const [location, setLocation] = useState<{ lat: number; lon: number }>(country);
const login = useLogin();
const relayUrls = Object.keys(login.relays.item);
async function loadRelays() {
const api = new SnortApi();
setRecommendedRelays(await api.closeRelays(location.lat, location.lon, 10));
}
useEffect(() => {
loadRelays().catch(console.error);
}, [location]);
return (
<>
<h3>
<FormattedMessage defaultMessage="Recommended Relays" id="VL900k" />
</h3>
{"geolocation" in navigator && (
<AsyncButton
onClick={async () => {
try {
const pos = await new Promise<GeolocationPosition>((resolve, reject) => {
navigator.geolocation.getCurrentPosition(resolve, reject);
});
setLocation({
lat: pos.coords.latitude,
lon: pos.coords.longitude,
});
} catch (e) {
console.error(e);
}
}}>
<FormattedMessage defaultMessage="Use Exact Location" id="0HFX0T" />
</AsyncButton>
)}
{relays
?.filter(a => !relayUrls.includes(unwrap(sanitizeRelayUrl(a.url))) && !a.is_paid)
.sort((a, b) => (a.distance > b.distance ? 1 : -1))
.map(a => (
<div className="bg-dark p br flex flex-col g8">
<div className="flex justify-between items-center">
<div className="bold">{getRelayName(a.url)}</div>
<AsyncButton
onClick={async () => {
setRelays(
login,
{
...login.relays.item,
[a.url]: { read: true, write: true },
},
unixNowMs(),
);
}}>
<FormattedMessage defaultMessage="Add" id="2/2yg+" />
</AsyncButton>
</div>
<div className="flex flex-col g8">
<span>{a.description}</span>
<small>
<FormattedMessage
defaultMessage="{n} km - {location}" id="jTrbGf"
values={{
n: (a.distance / 1000).toFixed(0),
location: a.city ? `${a.city}, ${a.country}` : a.country,
}}
/>
</small>
<small>
<FormattedMessage
defaultMessage="{n} users" id="1H4Keq"
values={{
n: formatShort(a.users),
}}
/>
</small>
</div>
</div>
))}
</>
);
}

View File

@ -517,12 +517,15 @@ export function getDisplayNameOrPlaceHolder(user: UserMetadata | undefined, pubk
export function getCountry() {
const tz = Intl.DateTimeFormat().resolvedOptions();
const info = (TZ as Record<string, Array<string> | undefined>)[tz.timeZone];
const [, lat, lon] = info?.[1].split(/[-+]/) ?? ["", "00", "000"];
const pos = info?.[1];
const sep = Number(pos?.slice(1).search(/[-+]/)) + 1;
const [lat, lon] = [pos?.slice(0, sep) ?? "00", pos?.slice(sep) ?? "000"];
return {
zone: tz.timeZone,
country: info?.[0],
lat: Number(lat) / Math.pow(10, lat.length - 2),
lon: Number(lon) / Math.pow(10, lon.length - 3),
lat: Number(lat) / Math.pow(10, lat.length - 3),
lon: Number(lon) / Math.pow(10, lon.length - 4),
info,
};
}

View File

@ -66,6 +66,9 @@
"0BUTMv": {
"defaultMessage": "Search..."
},
"0HFX0T": {
"defaultMessage": "Use Exact Location"
},
"0jOEtS": {
"defaultMessage": "Invalid LNURL"
},
@ -81,6 +84,9 @@
"0yO7wF": {
"defaultMessage": "{n} secs"
},
"1H4Keq": {
"defaultMessage": "{n} users"
},
"1Mo59U": {
"defaultMessage": "Are you sure you want to remove this note from bookmarks?"
},
@ -834,6 +840,9 @@
"UrKTqQ": {
"defaultMessage": "You have an active iris.to account"
},
"VL900k": {
"defaultMessage": "Recommended Relays"
},
"VN0+Fz": {
"defaultMessage": "Balance: {amount} sats"
},
@ -1158,6 +1167,9 @@
"jMzO1S": {
"defaultMessage": "Internal error: {msg}"
},
"jTrbGf": {
"defaultMessage": "{n} km - {location}"
},
"jfV8Wr": {
"defaultMessage": "Back",
"description": "Navigate back button on threads view"

View File

@ -21,11 +21,13 @@
"08zn6O": "مفاتيح التصدير",
"0Azlrb": "إدارة",
"0BUTMv": "بحث...",
"0HFX0T": "Use Exact Location",
"0jOEtS": "عنوان LNURL غير صالح",
"0mch2Y": "الاسم يحتوي على أحرف غير مسموح بها",
"0siT4z": "السياسة",
"0uoY11": "إظهار الحالة",
"0yO7wF": "{n} ثانية",
"1H4Keq": "{n} users",
"1Mo59U": "هل أنت متأكد من حذف هذا المنشور من المنشورات المرجعية؟",
"1R43+L": "أدخل تكوين اتصال محفظة Nostr",
"1c4YST": "متصل بـ: {node}🎉",
@ -274,6 +276,7 @@
"Ub+AGc": "تسجيل الدخول",
"Up5U7K": "حظر",
"UrKTqQ": "لديك حساب iris.to نشط",
"VL900k": "Recommended Relays",
"VN0+Fz": "الرصيد: {amount} ساتوشي",
"VOjC1i": "اختر خدمة التحميل التي تريد رفع المرفقات إليها",
"VR5eHw": "مفتاح عام (npub/nprofile)",
@ -381,6 +384,7 @@
"jAmfGl": "إنتهت صلاحية اشتراكك {site_name}",
"jHa/ko": "تنظيف موجز الويب الخاص بك",
"jMzO1S": "خطأ داخلي: {msg}",
"jTrbGf": "{n} km - {location}",
"jfV8Wr": "الخلف",
"jvo0vs": "حفظ",
"jzgQ2z": "التفاعل {n}",

View File

@ -21,11 +21,13 @@
"08zn6O": "Açarları ixrac edin",
"0Azlrb": "İdarə et",
"0BUTMv": "Axtar...",
"0HFX0T": "Use Exact Location",
"0jOEtS": "Yanlış LNURL",
"0mch2Y": "adda icazə verilməyən simvollar var",
"0siT4z": "Politics",
"0uoY11": "Show Status",
"0yO7wF": "{n} saniyə",
"1H4Keq": "{n} users",
"1Mo59U": "Bu qeydi əlfəcinlərdən silmək istədiyinizə əminsiniz?",
"1R43+L": "Nostr Wallet Connect konfiqurasiyasını daxil edin",
"1c4YST": "Qoşuldu: {node} 🎉",
@ -274,6 +276,7 @@
"Ub+AGc": "Sign In",
"Up5U7K": "Block",
"UrKTqQ": "You have an active iris.to account",
"VL900k": "Recommended Relays",
"VN0+Fz": "Balance: {amount} sats",
"VOjC1i": "Pick which upload service you want to upload attachments to",
"VR5eHw": "Public key (npub/nprofile)",
@ -381,6 +384,7 @@
"jAmfGl": "Your {site_name} subscription is expired",
"jHa/ko": "Clean up your feed",
"jMzO1S": "Internal error: {msg}",
"jTrbGf": "{n} km - {location}",
"jfV8Wr": "Back",
"jvo0vs": "Save",
"jzgQ2z": "{n} Reactions",

View File

@ -21,11 +21,13 @@
"08zn6O": "Schlüssel exportieren",
"0Azlrb": "Verwalten",
"0BUTMv": "Suche...",
"0HFX0T": "Exakten Standort verwenden",
"0jOEtS": "Ungültige LNURL",
"0mch2Y": "Der Name enthält unerlaubte Zeichen",
"0siT4z": "Politik",
"0uoY11": "Status anzeigen",
"0yO7wF": "{n} Sek.",
"1H4Keq": "{n} Benutzer",
"1Mo59U": "Bist du sicher, dass du diese Note aus deinen Lesezeichen entfernen möchtest?",
"1R43+L": "Nostr Wallet Connect Konfiguration eingeben",
"1c4YST": "Verbunden mit: {node}🎉",
@ -274,6 +276,7 @@
"Ub+AGc": "Anmelden",
"Up5U7K": "Blockieren",
"UrKTqQ": "Du hast ein aktives iris.to Konto",
"VL900k": "Empfohlene Relais",
"VN0+Fz": "Guthaben: {amount} Sats",
"VOjC1i": "Wähle einen Upload-Dienst für deine Anhänge",
"VR5eHw": "Öffentlicher Schlüssel (npub/nprofile)",
@ -381,6 +384,7 @@
"jAmfGl": "Dein {site_name} Abonnement ist abgelaufen",
"jHa/ko": "Räume deinen Feed auf",
"jMzO1S": "Interner Fehler: {msg}",
"jTrbGf": "{n} km - {location}",
"jfV8Wr": "Zurück",
"jvo0vs": "Speichern",
"jzgQ2z": "{n} Reaktionen",

View File

@ -21,11 +21,13 @@
"08zn6O": "Export Keys",
"0Azlrb": "Manage",
"0BUTMv": "Search...",
"0HFX0T": "Use Exact Location",
"0jOEtS": "Invalid LNURL",
"0mch2Y": "name has disallowed characters",
"0siT4z": "Politics",
"0uoY11": "Show Status",
"0yO7wF": "{n} secs",
"1H4Keq": "{n} users",
"1Mo59U": "Are you sure you want to remove this note from bookmarks?",
"1R43+L": "Enter Nostr Wallet Connect config",
"1c4YST": "Connected to: {node} 🎉",
@ -274,6 +276,7 @@
"Ub+AGc": "Sign In",
"Up5U7K": "Block",
"UrKTqQ": "You have an active iris.to account",
"VL900k": "Recommended Relays",
"VN0+Fz": "Balance: {amount} sats",
"VOjC1i": "Pick which upload service you want to upload attachments to",
"VR5eHw": "Public key (npub/nprofile)",
@ -381,6 +384,7 @@
"jAmfGl": "Your {site_name} subscription is expired",
"jHa/ko": "Clean up your feed",
"jMzO1S": "Internal error: {msg}",
"jTrbGf": "{n} km - {location}",
"jfV8Wr": "Back",
"jvo0vs": "Save",
"jzgQ2z": "{n} Reactions",

View File

@ -21,11 +21,13 @@
"08zn6O": "Exportar claves",
"0Azlrb": "Gestionar",
"0BUTMv": "Buscar...",
"0HFX0T": "Use Exact Location",
"0jOEtS": "LNURL inválida",
"0mch2Y": "el nombre tiene caracteres inválidos",
"0siT4z": "Política",
"0uoY11": "Mostrar estado",
"0yO7wF": "{n} seg",
"1H4Keq": "{n} users",
"1Mo59U": "¿Estás seguro de que quieres eliminar esta nota de tus favoritos?",
"1R43+L": "Introduzca la configuración de Nostr Wallet Connect",
"1c4YST": "Conectado a: {node}🎉",
@ -274,6 +276,7 @@
"Ub+AGc": "Iniciar sesión",
"Up5U7K": "Bloquear",
"UrKTqQ": "Tienes una cuenta activa en iris.to",
"VL900k": "Recommended Relays",
"VN0+Fz": "Saldo: {amount} sats",
"VOjC1i": "Elige qué servicio de subida de ficheros quieres utilizar",
"VR5eHw": "Clave pública (npub/nprofile)",
@ -381,6 +384,7 @@
"jAmfGl": "Su suscripción a {site_name} ha caducado",
"jHa/ko": "Limpie su alimentación",
"jMzO1S": "Error interno: {msg}",
"jTrbGf": "{n} km - {location}",
"jfV8Wr": "Atrás",
"jvo0vs": "Guardar",
"jzgQ2z": "{n} Reacciones",

View File

@ -21,11 +21,13 @@
"08zn6O": "استخراج کلید",
"0Azlrb": "مدیریت",
"0BUTMv": "جستجو...",
"0HFX0T": "Use Exact Location",
"0jOEtS": "LNURL نامعتبر",
"0mch2Y": "نام دارای کاراکتر غیرمجاز است",
"0siT4z": "سیاست",
"0uoY11": "نمایش وضعیت",
"0yO7wF": "{n} ثانیه",
"1H4Keq": "{n} users",
"1Mo59U": "مطمئنید می خواهید این یادداشت را از نشانک ها خارج کنید؟",
"1R43+L": "پیکربندی اتصال ناستر به کیف پول",
"1c4YST": "متصل به:{node}🎉",
@ -274,6 +276,7 @@
"Ub+AGc": "ورود",
"Up5U7K": "مسدود کردن",
"UrKTqQ": "شما یک حساب کاربری فعال iris.to دارید",
"VL900k": "Recommended Relays",
"VN0+Fz": "تراز: {amount} ساتوشی",
"VOjC1i": "انتخاب کنید درکدام خدمات بارگذاری فایل می خواهید پیوست ها را بارگذاری کنید",
"VR5eHw": "کلید عمومی (npub/nprofile)",
@ -381,6 +384,7 @@
"jAmfGl": "عضویت شما در {site_name} منقضی شده است",
"jHa/ko": "پاک سازی خبرنامه",
"jMzO1S": "خطای داخلی: {msg}",
"jTrbGf": "{n} km - {location}",
"jfV8Wr": "برگشت",
"jvo0vs": "ذخیره",
"jzgQ2z": "{n} واکنش",

View File

@ -21,11 +21,13 @@
"08zn6O": "Vie avaimet",
"0Azlrb": "Hallitse",
"0BUTMv": "Etsi...",
"0HFX0T": "Use Exact Location",
"0jOEtS": "Virheellinen LNURL",
"0mch2Y": "nimi sisältää sallimattomia merkkejä",
"0siT4z": "Politiikka",
"0uoY11": "Näytä tila",
"0yO7wF": "{n} sek",
"1H4Keq": "{n} users",
"1Mo59U": "Haluatko varmasti poistaa tämän viestin kirjanmerkeistä?",
"1R43+L": "Anna Nostr Wallet Connect asetukset",
"1c4YST": "Yhdistetty: {node} 🎉",
@ -274,6 +276,7 @@
"Ub+AGc": "Kirjaudu sisään",
"Up5U7K": "Estä",
"UrKTqQ": "Sinulla on aktiivinen iris.to-tili",
"VL900k": "Recommended Relays",
"VN0+Fz": "Saldo: {amount} satsia",
"VOjC1i": "Valitse palvelu, johon haluat ladata liitteitä",
"VR5eHw": "Julkinen avain (npub/nprofile)",
@ -381,6 +384,7 @@
"jAmfGl": "{site_name} tilauksesi on päättynyt",
"jHa/ko": "Siivoa rehusi",
"jMzO1S": "Sisäinen virhe: {msg}",
"jTrbGf": "{n} km - {location}",
"jfV8Wr": "Takaisin",
"jvo0vs": "Tallenna",
"jzgQ2z": "{n} Reaktiota",

View File

@ -21,11 +21,13 @@
"08zn6O": "Exporter les clés",
"0Azlrb": "Gérer",
"0BUTMv": "Chercher...",
"0HFX0T": "Use Exact Location",
"0jOEtS": "LNURL invalide",
"0mch2Y": "le nom contient des caractères non autorisés",
"0siT4z": "Politique",
"0uoY11": "Afficher l'état",
"0yO7wF": "{n} secondes",
"1H4Keq": "{n} users",
"1Mo59U": "Êtes-vous sûr de vouloir supprimer cette note de vos favoris ?",
"1R43+L": "Accéder à la configuration de Nostr Wallet Connect",
"1c4YST": "Connecté à : {node} 🎉",
@ -274,6 +276,7 @@
"Ub+AGc": "S'inscrire",
"Up5U7K": "Bloquer",
"UrKTqQ": "Vous avez un compte iris.to actif",
"VL900k": "Recommended Relays",
"VN0+Fz": "Solde : {amount} sats",
"VOjC1i": "Choisissez le service d'hébergement vers lequel vous souhaitez héberger les pièces jointes",
"VR5eHw": "Clé publique (npub/nprofile)",
@ -381,6 +384,7 @@
"jAmfGl": "Votre abonnement à {site_name} a expiré",
"jHa/ko": "Nettoyez votre flux",
"jMzO1S": "Erreur interne : {msg}",
"jTrbGf": "{n} km - {location}",
"jfV8Wr": "Retourner",
"jvo0vs": "Sauvegarder",
"jzgQ2z": "{n} Réactions",

View File

@ -21,11 +21,13 @@
"08zn6O": "Izvezi Ključeve",
"0Azlrb": "Upravljaj",
"0BUTMv": "Pretraga...",
"0HFX0T": "Use Exact Location",
"0jOEtS": "Nevažeći LNURL",
"0mch2Y": "ime sadrži nepodržane znakove",
"0siT4z": "Politics",
"0uoY11": "Show Status",
"0yO7wF": "{n} sekundi",
"1H4Keq": "{n} users",
"1Mo59U": "Jeste li sigurni da želite ukloniti ovu bilješku iz trake s oznakama?",
"1R43+L": "Enter Nostr Wallet Connect config",
"1c4YST": "Povezano s: {node} 🎉",
@ -274,6 +276,7 @@
"Ub+AGc": "Sign In",
"Up5U7K": "Blokiraj",
"UrKTqQ": "You have an active iris.to account",
"VL900k": "Recommended Relays",
"VN0+Fz": "Iznos: {amount} sati",
"VOjC1i": "Odaberite kroz koji servis želite učitati privitke",
"VR5eHw": "Javni ključ (npub/nprofile)",
@ -381,6 +384,7 @@
"jAmfGl": "Your {site_name} subscription is expired",
"jHa/ko": "Clean up your feed",
"jMzO1S": "Interna pogreška: {msg}",
"jTrbGf": "{n} km - {location}",
"jfV8Wr": "Natrag",
"jvo0vs": "Spremi",
"jzgQ2z": "{n} Reakcija",

View File

@ -21,11 +21,13 @@
"08zn6O": "Kulcsok exportálása",
"0Azlrb": "Menedzselés",
"0BUTMv": "Keresés...",
"0HFX0T": "Use Exact Location",
"0jOEtS": "Érvénytelen LNURL",
"0mch2Y": "név nem engedélyezett karaktereket tartalmaz",
"0siT4z": "Politika",
"0uoY11": "Státusz megjelenítése",
"0yO7wF": "{n} másodperc",
"1H4Keq": "{n} users",
"1Mo59U": "Biztos hogy a kedvencekből ezt a bejegyzést el akarod távolítani?",
"1R43+L": "Írd be a Nostr Wallet Connect konfigurációt",
"1c4YST": "Kapcsolódás a: {node} 🎉",
@ -274,6 +276,7 @@
"Ub+AGc": "Bejelentkezés",
"Up5U7K": "Tiltás",
"UrKTqQ": "Van aktív iris.to fiókod",
"VL900k": "Recommended Relays",
"VN0+Fz": "Egyenleg: {amount} sats",
"VOjC1i": "Válaszd ki mely szolgáltatóhoz legyenek a fájlok feltöltve",
"VR5eHw": "Publikus kulcs (npub/nprofile)",
@ -381,6 +384,7 @@
"jAmfGl": "{site_name}-előfizetése lejárt",
"jHa/ko": "Tisztítsa meg a takarmányt",
"jMzO1S": "Belső hiba: {msg}",
"jTrbGf": "{n} km - {location}",
"jfV8Wr": "Vissza",
"jvo0vs": "Mentés",
"jzgQ2z": "{n} Reakció",

View File

@ -21,11 +21,13 @@
"08zn6O": "Kunci Ekspor",
"0Azlrb": "Mengelola",
"0BUTMv": "Cari...",
"0HFX0T": "Use Exact Location",
"0jOEtS": "LNURL Tidak valid",
"0mch2Y": "nama memiliki karakter yang tidak diizinkan",
"0siT4z": "Politik",
"0uoY11": "Tampilkan Status",
"0yO7wF": "{n} detik",
"1H4Keq": "{n} users",
"1Mo59U": "Apa Anda yakin Anda ingin memindahkan catatan ini dari penanda buku?",
"1R43+L": "Masukkan konfigurasi Nostr Wallet Connect",
"1c4YST": "Terhubung ke: {node} 🎉",
@ -274,6 +276,7 @@
"Ub+AGc": "Masuk",
"Up5U7K": "Blokir",
"UrKTqQ": "Anda memiliki akun iris.to yang aktif",
"VL900k": "Recommended Relays",
"VN0+Fz": "Saldo: {amount} sats",
"VOjC1i": "Pilih layanan unggah mana yang ingin Anda unggahkan lampirannya",
"VR5eHw": "Kunci publik (npub/nprofile)",
@ -381,6 +384,7 @@
"jAmfGl": "Langganan {site_name} Anda telah kedaluwarsa",
"jHa/ko": "Bersihkan feed Anda",
"jMzO1S": "Kesalahan internal: {msg}",
"jTrbGf": "{n} km - {location}",
"jfV8Wr": "Kembali",
"jvo0vs": "Simpan",
"jzgQ2z": "{n} Reaksi",

View File

@ -21,11 +21,13 @@
"08zn6O": "Esporta Chiavi",
"0Azlrb": "Gestisci",
"0BUTMv": "Cerca...",
"0HFX0T": "Use Exact Location",
"0jOEtS": "LNURL non valido",
"0mch2Y": "il nome ha caratteri non ammessi",
"0siT4z": "Politica",
"0uoY11": "Mostra stato",
"0yO7wF": "{n} sec",
"1H4Keq": "{n} users",
"1Mo59U": "Vuoi davvero rimuovere questa nota dai preferiti?",
"1R43+L": "Inserire la configurazione di Nostr Wallet Connect",
"1c4YST": "Connessione a: {node}🎉",
@ -274,6 +276,7 @@
"Ub+AGc": "Accedi",
"Up5U7K": "Blocca",
"UrKTqQ": "Avete un account iris.to attivo",
"VL900k": "Recommended Relays",
"VN0+Fz": "Saldo: {amount} sats",
"VOjC1i": "Scegli quale servizio vuoi usare per caricare gli allegati",
"VR5eHw": "Chiave pubblica (npub/nprofile)",
@ -381,6 +384,7 @@
"jAmfGl": "L'abbonamento a {site_name} è scaduto",
"jHa/ko": "Pulite il vostro feed",
"jMzO1S": "Errore interno: {msg}",
"jTrbGf": "{n} km - {location}",
"jfV8Wr": "Indietro",
"jvo0vs": "Salva",
"jzgQ2z": "{n} Reazioni",

View File

@ -21,11 +21,13 @@
"08zn6O": "鍵をエクスポート",
"0Azlrb": "管理",
"0BUTMv": "検索する",
"0HFX0T": "Use Exact Location",
"0jOEtS": "無効なLNURL",
"0mch2Y": "名前に使用できない文字が含まれています",
"0siT4z": "政治",
"0uoY11": "ステータス表示",
"0yO7wF": "{n}秒",
"1H4Keq": "{n} users",
"1Mo59U": "本当にこの投稿をブックマークから削除しますか?",
"1R43+L": "Nostr Wallet Connectの設定値を入力",
"1c4YST": "{node}に接続しました🎉",
@ -274,6 +276,7 @@
"Ub+AGc": "サインイン",
"Up5U7K": "ブロック",
"UrKTqQ": "iris.toアカウントをお持ちの方",
"VL900k": "Recommended Relays",
"VN0+Fz": "残高: {amount} sats",
"VOjC1i": "添付ファイルをアップロードするためのサービスを選択してください",
"VR5eHw": "公開鍵 (npub/nprofile)",
@ -381,6 +384,7 @@
"jAmfGl": "{site_name} 、有効期限が切れています。",
"jHa/ko": "フィードをきれいにする",
"jMzO1S": "内部エラー:{msg}",
"jTrbGf": "{n} km - {location}",
"jfV8Wr": "戻る",
"jvo0vs": "保存",
"jzgQ2z": "{n} リアクション",

View File

@ -21,11 +21,13 @@
"08zn6O": "Sleutel exporteren",
"0Azlrb": "Beheren",
"0BUTMv": "Zoeken naar...",
"0HFX0T": "Use Exact Location",
"0jOEtS": "Ongeldig LNURL",
"0mch2Y": "naam heeft verboden tekens",
"0siT4z": "Politiek",
"0uoY11": "Toon status",
"0yO7wF": "{n} seconden",
"1H4Keq": "{n} users",
"1Mo59U": "Weet u zeker dat u deze notitie uit bladwijzers wilt verwijderen?",
"1R43+L": "Voer Nostr Wallet Connect configuratie in",
"1c4YST": "Verbonden met: {node}🎉",
@ -274,6 +276,7 @@
"Ub+AGc": "Aanmelden",
"Up5U7K": "Blokkeren",
"UrKTqQ": "Je hebt een actieve iris.to account",
"VL900k": "Recommended Relays",
"VN0+Fz": "Saldo: {amount} sats",
"VOjC1i": "Kies naar welke service u bijlagen wilt uploaden",
"VR5eHw": "Publieke sleutel (npub/nprofile)",
@ -381,6 +384,7 @@
"jAmfGl": "Uw {site_name} abonnement is verlopen",
"jHa/ko": "Ruim je feed op",
"jMzO1S": "Interne fout: {msg}",
"jTrbGf": "{n} km - {location}",
"jfV8Wr": "Terug",
"jvo0vs": "Opslaan",
"jzgQ2z": "{n} Reacties",

View File

@ -21,11 +21,13 @@
"08zn6O": "Exportar chaves",
"0Azlrb": "Gerenciar",
"0BUTMv": "Pesquisar...",
"0HFX0T": "Use Exact Location",
"0jOEtS": "LNURL inválida",
"0mch2Y": "o nome possui caracteres não permitidos",
"0siT4z": "Política",
"0uoY11": "Mostrar status",
"0yO7wF": "{n} segundos",
"1H4Keq": "{n} users",
"1Mo59U": "Tem certeza que deseja remover esta nota dos favoritos?",
"1R43+L": "Insira a configuração da Nostr Wallet Connect",
"1c4YST": "Conectado em: {node} 🎉",
@ -274,6 +276,7 @@
"Ub+AGc": "Entrar",
"Up5U7K": "Bloquear",
"UrKTqQ": "Você tem uma conta ativa no iris.to",
"VL900k": "Recommended Relays",
"VN0+Fz": "Saldo: {amount} sats",
"VOjC1i": "Escolha para qual serviço fazer upload dos arquivos",
"VR5eHw": "Chave pública (npub/nprofile)",
@ -381,6 +384,7 @@
"jAmfGl": "Sua assinatura do {site_name} expirou",
"jHa/ko": "Limpe seu feed",
"jMzO1S": "Erro interno: {msg}",
"jTrbGf": "{n} km - {location}",
"jfV8Wr": "Voltar",
"jvo0vs": "Salvar",
"jzgQ2z": "{n} Reações",

View File

@ -21,11 +21,13 @@
"08zn6O": "Экспортировать ключи",
"0Azlrb": "Управление",
"0BUTMv": "Поиск...",
"0HFX0T": "Use Exact Location",
"0jOEtS": "Неверный LNURL",
"0mch2Y": "имя содержит запрещенные символы",
"0siT4z": "Политика",
"0uoY11": "Показать статус",
"0yO7wF": "{n} секунд",
"1H4Keq": "{n} users",
"1Mo59U": "Вы уверены, что хотите удалить эту заметку из закладок?",
"1R43+L": "Введите конфигурацию Nostr Wallet Connect",
"1c4YST": "Подключен к: {node} 🎉",
@ -274,6 +276,7 @@
"Ub+AGc": "Войти",
"Up5U7K": "Блок",
"UrKTqQ": "У вас есть активная учетная запись iris.to",
"VL900k": "Recommended Relays",
"VN0+Fz": "Баланс: {amount} сат",
"VOjC1i": "Выберите каким сервисом Вы бы хотели пользоваться для загрузки медиа",
"VR5eHw": "Публичный ключ (npub/nprofile)",
@ -381,6 +384,7 @@
"jAmfGl": "Срок действия вашей подписки {site_name} истек",
"jHa/ko": "Очистка корма",
"jMzO1S": "Ошибка: {msg}",
"jTrbGf": "{n} km - {location}",
"jfV8Wr": "Назад",
"jvo0vs": "Сохранить",
"jzgQ2z": "{n} Реакции",

View File

@ -21,11 +21,13 @@
"08zn6O": "Exportera nycklar",
"0Azlrb": "Hantera",
"0BUTMv": "Sök...",
"0HFX0T": "Use Exact Location",
"0jOEtS": "Ogiltig LNURL",
"0mch2Y": "namnet har otillåtna tecken",
"0siT4z": "Politik",
"0uoY11": "Visa status",
"0yO7wF": "{n} secs",
"1H4Keq": "{n} users",
"1Mo59U": "Är du säker på att du vill ta bort den här anteckningen från bokmärken?",
"1R43+L": "Skriv in Nostr Wallet Connect konfiguration",
"1c4YST": "Ansluten till: {node}🎉",
@ -274,6 +276,7 @@
"Ub+AGc": "Logga in",
"Up5U7K": "Blockera",
"UrKTqQ": "Du har ett aktivt iris.to konto",
"VL900k": "Recommended Relays",
"VN0+Fz": "Saldo: {amount} sats",
"VOjC1i": "Välj vilken uppladdningstjänst du vill ladda upp bilagor till",
"VR5eHw": "Publik nyckel (npub/nprofile)",
@ -381,6 +384,7 @@
"jAmfGl": "Ditt {site_name} abonnemang har löpt ut",
"jHa/ko": "Städa upp i ditt flöde",
"jMzO1S": "Internt fel: {msg}",
"jTrbGf": "{n} km - {location}",
"jfV8Wr": "Tillbaka",
"jvo0vs": "Spara",
"jzgQ2z": "{n} Reaktioner",

View File

@ -21,11 +21,13 @@
"08zn6O": "Tuma Funguo",
"0Azlrb": "Dhibiti",
"0BUTMv": "Tafuta...",
"0HFX0T": "Use Exact Location",
"0jOEtS": "LNURL Batili",
"0mch2Y": "jina limekataza herufi",
"0siT4z": "Politics",
"0uoY11": "Show Status",
"0yO7wF": "{n} sekundi",
"1H4Keq": "{n} users",
"1Mo59U": "Je, una uhakika unataka kuondoa dokezo hili kutoka kwa vialamisho?",
"1R43+L": "Ingiza usanidi wa Nostr Wallet Connect",
"1c4YST": "Imeunganishwa kwa: {node} 🎉",
@ -274,6 +276,7 @@
"Ub+AGc": "Sign In",
"Up5U7K": "Zuia",
"UrKTqQ": "You have an active iris.to account",
"VL900k": "Recommended Relays",
"VN0+Fz": "Salio: {amount} sats",
"VOjC1i": "Chagua ni huduma gani ya upakiaji ungependa kupakia viambatisho",
"VR5eHw": "Ufunguo wa umma (npub/nprofile)",
@ -381,6 +384,7 @@
"jAmfGl": "Your {site_name} subscription is expired",
"jHa/ko": "Clean up your feed",
"jMzO1S": "Hitilafu ya ndani: {msg}",
"jTrbGf": "{n} km - {location}",
"jfV8Wr": "Rudi",
"jvo0vs": "Hifadhi",
"jzgQ2z": "{n} Maoni",

View File

@ -7,9 +7,9 @@
"+vA//S": "உள்நுழைவுகள்",
"+vIQlC": "பிற்காலத்தில் உங்களது கணக்கை நிர்வகிக்க, கீழே உள்ள கடவுச்சொல்லைத் தவறாமல் சேமிக்கவும்",
"+vVZ/G": "இணை",
"+vj0U3": "edit",
"+vj0U3": "தொகு",
"+xliwN": "{name} மறுபதிவு செய்தார்",
"/B8zwF": "Your space the way you want it 😌",
"/B8zwF": "நீங்கள் விரும்பியபடி உங்கள் இடம் 😌",
"/GCoTA": "அழி",
"/JE/X+": "கணக்கு உதவி",
"/PCavi": "பொது",
@ -21,29 +21,31 @@
"08zn6O": "சாவிகளை ஏற்றுமதி செய்யவும்",
"0Azlrb": "நிர்வகி",
"0BUTMv": "தேடு...",
"0HFX0T": "Use Exact Location",
"0jOEtS": "தவறான LNURL",
"0mch2Y": "பெயர் அங்கீகரிக்கப்படாத எழுத்துக்களைக் கொண்டுள்ளது",
"0siT4z": "Politics",
"0siT4z": "அரசியல்",
"0uoY11": "சமுதாய நிலையைக் காட்டு",
"0yO7wF": "{n} வினாடிகள்",
"1H4Keq": "{n} users",
"1Mo59U": "இந்தக் குறிப்பைப் புக்மார்க்குகளிலிருந்து அகற்ற நிச்சயமாக விரும்புகிறீர்களா?",
"1R43+L": "நாஸ்டர் பணப்பை இணைப்புக் கட்டமைப்பை உள்ளிடவும்",
"1c4YST": "{node} உடன் இணைக்கப் பட்டது 🎉",
"1nYUGC": "{n} பின்தொடரப் படுவோர்",
"1o2BgB": "கையெழுத்துக்களை சரிபார்",
"1ozeyg": "Nature",
"1ozeyg": "இயற்கை",
"1udzha": "உரையாடல்கள்",
"2/2yg+": "சேர்",
"25V4l1": "பதாகை",
"25WwxF": "Don't have an account?",
"25WwxF": "கணக்கு இல்லையா?",
"2IFGap": "நன்கொடை அளிக்க",
"2LbrkB": "கடவுச்சொல்லை உள்ளிடுக",
"2O2sfp": "Finish",
"2O2sfp": "முடிக்க",
"2a2YiP": "{n} புத்தகக் குறிகள்",
"2k0Cv+": "விருப்பமின்மைகள் ({n})",
"2ukA4d": "{n} மணித்துளிகள்",
"2zJXeA": "சுயவிவரங்கள்",
"39AHJm": "Sign Up",
"39AHJm": "பதிவு செய்",
"3KNMbJ": "கட்டுரைகள்",
"3cc4Ct": "ஒளி",
"3gOsZq": "மொழிபெயர்ப்பாளர்கள்",
@ -56,7 +58,7 @@
"4IPzdn": "முதன்மை உருவாக்கி",
"4L2vUY": "உங்களது புதிய NIP-05 கணக்கு:",
"4MBtMa": "பெயர் 1 முதல் 32 எழுத்துக்களைக் கொண்டிருக்க வேண்டும்",
"4MjsHk": "Life",
"4MjsHk": "வாழ்க்கை",
"4OB335": "விருப்பமில்லை",
"4Vmpt4": "Nostr Plebs முதல் NIP-05 வழங்குநர்களில் ஒன்றாகும். மேலும், இது நியாயமான விலையில் டொமைன்களின் நல்ல தொகுப்பை வழங்குகிறது",
"4Z3t5i": "படங்களை சுருக்க imgproxy உபயோகிக்கவும்",
@ -69,7 +71,7 @@
"5ykRmX": "ஜாப் அனுப்பு",
"6/SF6e": "<h1>{n}</h1> காஷூ சாட்கள்",
"6/hB3S": "மறு ஓட்டத்தைப் பார்க்கவும்",
"62nsdy": "Retry",
"62nsdy": "மீண்டும் முயற்சிக்கவும்",
"65BmHb": "{host} இல் இருந்து படத்தைப் பதிலி செய்ய முடியவில்லை, நேரடியாகப் பெற இங்கு கிளிக் செய்யவும்",
"6OSOXl": "காரணம்: <i>{reason}</i>",
"6TfgXX": "{site} என்பது ஆர்வமுள்ள மக்கள் தங்கள் ஓய்வு நேரத்தில் உருவாக்கிய திறந்த மூல திட்டம் ஆகும்",
@ -79,31 +81,31 @@
"7+Domh": "குறிப்புகள்",
"712i26": "Proxy uses HODL invoices to forward the payment, which hides the pubkey of your node",
"7BX/yC": "கணக்கு மாற்றி",
"7UOvbT": "Offline",
"7UOvbT": "அகல்நிலை",
"7hp70g": "NIP-05",
"8/vBbP": "மறுபதிவுகள் ({n})",
"89q5wc": "மறுப்பதிவுகளை உறுதி செய்யவும்",
"8ED/4u": "இவருக்கு பதிலளி",
"8QDesP": "{n} ஸாட்கள் ஜாப் செய்",
"8Rkoyb": "பெறுநர்",
"8Y6bZQ": "Invalid zap split: {input}",
"8Y6bZQ": "தவறான zap பிளவு: {input}",
"8g2vyB": "பெயர் மிக நீளமாக உள்ளது",
"8v1NN+": "ஜோடிக்கும் சொற்றொடர்",
"9+Ddtu": "அடுத்து",
"9HU8vw": "பதில்",
"9SvQep": "பின்தொடர்வுகள் {n}",
"9WRlF4": "அனுப்பு",
"9kSari": "Retry publishing",
"9kSari": "வெளியிட மீண்டும் முயற்சிக்கவும்",
"9pMqYs": "நாஸ்டர் முகவரி",
"9wO4wJ": "லைட்னிங் விலைப்பட்டியல்",
"ABAQyo": "அரட்டைகள்",
"ADmfQT": "பெற்றோர்",
"AIgmDy": "Add up to 4 hashtags",
"AIgmDy": "4 ஹேஷ்டேக்குகள் வரை சேர்க்கவும்",
"AN0Z7Q": "முடக்கப்பட்ட வார்த்தைகள்",
"ASRK0S": "இந்தப் பதிவாளர் முடக்கப் பட்டுள்ளார்",
"Ai8VHU": "ஸ்நார்ட் ரிலேயில் வரம்பற்ற குறிப்புகளை வைத்திரு",
"AkCxS/": "காரணம்",
"Am8glJ": "Game",
"Am8glJ": "விளையாட்டு",
"AnLrRC": "ஜாப் அல்லாத",
"AxDOiG": "மாதங்கள்",
"AyGauy": "உள்நுழை",
@ -114,15 +116,15 @@
"BWpuKl": "புதுப்பி",
"BjNwZW": "நாஸ்டர் முகவரி (nip05)",
"C1LjMx": "லைட்னிங் நன்கொடை",
"C7642/": "Quote Repost",
"C7642/": "மேற்கோள் மறுபதிவு",
"C81/uG": "வெளியேறு",
"C8HhVE": "பரிந்துரைக்கப்படும் பயனர்கள்",
"CHTbO3": "விலைப்பட்டியலை பெற முடியவில்லை",
"CVWeJ6": "Trending People",
"CVWeJ6": "டிரெண்டிங் நபர்கள்",
"CmZ9ls": "{n} ஒலியடக்கப்பட்டவை",
"CsCUYo": "{n} sats",
"CsCUYo": "{n} சாட்ஸ்",
"Cu/K85": "{lang} இல் இருந்து மொழிபெயர்க்கப் பட்டது",
"CzHZoc": "Social Graph",
"CzHZoc": "சமூக வரைபடம்",
"D+KzKd": "கிடைக்கும் ஒவ்வொரு குறிப்புகளையும் தானாக ஜாப் செய்யவும்",
"D3idYv": "அமைப்புகள்",
"DBiVK1": "தேக்ககம்",
@ -132,21 +134,21 @@
"Dh3hbq": "தானாக ஜாப்",
"Dn82AL": "நேரலை",
"DtYelJ": "பரிமாற்றம்",
"Dx4ey3": "Toggle all",
"Dx4ey3": "அனைத்தையும் நிலைமாற்று",
"EJbFi7": "குறிப்புகளைத் தேடு",
"ELbg9p": "தரவு வழங்குநர்",
"EQKRE4": "Show badges on profile pages",
"EQKRE4": "சுயவிவரப் பக்கங்களில் பேட்ஜ்களைக் காட்டு",
"EWyQH5": "முழுதளாவிய",
"Ebl/B2": "{lang} இற்கு மொழிபெயர்க்கவும்",
"EcZF24": "Custom Relays",
"EcfIwB": "Username is available",
"EcZF24": "கஸ்டம் ரிலேஸ்",
"EcfIwB": "பயனர் பெயர் இருக்கிறது",
"EcglP9": "சாவி",
"EjFyoR": "On-chain Donation Address",
"EjFyoR": "ஆன்-செயின் நன்கொடை முகவரி",
"EnCOBJ": "வாங்கு",
"F3l7xL": "கணக்கை சேர்",
"FDguSC": "{n} ஜாப்கள்",
"FMfjrl": "Show status messages on profile pages",
"FSYL8G": "Trending Users",
"FMfjrl": "சுயவிவரப் பக்கங்களில் நிலை செய்திகளைக் காட்டு",
"FSYL8G": "பிரபலமான பயனர்கள்",
"FcNSft": "Redirect issues HTTP redirect to the supplied lightning address",
"FdhSU2": "இப்போது உரிமை கோரவும்",
"FfYsOb": "ஓரு பிழை நேர்ந்துவிட்டது!",
@ -155,36 +157,36 @@
"G1BGCg": "பணப்பை தேர்வு",
"GFOoEE": "உப்பு",
"GL8aXW": "புக்மார்க்குகள் ({n})",
"GQPtfk": "Join Stream",
"GSye7T": "Lightning Address",
"GQPtfk": "ஸ்ட்ரீமில் சேரவும்",
"GSye7T": "லைட்னிங் முகவரி",
"GUlSVG": "உங்கள் ஸ்நார்ட் நாஸ்டர் முகவரியைப் பெறவும்",
"Gcn9NQ": "மேக்னெட் இணைப்பு",
"GspYR7": "{n} விருப்பமின்மை",
"Gxcr08": "Broadcast Event",
"Gxcr08": "ஒளிபரப்பு நிகழ்வு",
"H+vHiz": "ஹெக்ஸ் சாவி..",
"H0JBH6": "வெளியேறு",
"H6/kLh": "ஆர்டர் செலுத்தப்பட்டது!",
"HAlOn1": "பெயர்",
"HFls6j": "பெயர் பின்னர் கிடைக்கப் பெறும்",
"HOzFdo": "ஒலியடக்கப்பட்டவை",
"HWbkEK": "Clear cache and reload",
"HWbkEK": "தற்காலிக சேமிப்பை அழித்து மீண்டும் ஏற்றவும்",
"HbefNb": "திறந்த பணப்பை",
"HhcAVH": "You don't follow this person, click here to load media from <i>{link}</i>, or update <a><i>your preferences</i></a> to always load media from everybody.",
"HhcAVH": "நீங்கள் இவரைப் பின்தொடரவில்லை, மீடியாவை ஏற்ற இங்கே கிளிக் செய்யவும் <i>{link}</i>, அல்லது புதுப்பிக்கவும் <a><i>உங்கள் விருப்பங்களை</i></a> எல்லாரிடமிருந்தும் எப்போதும் மீடியாவை ஏற்றுவதற்கு.",
"IEwZvs": "இந்தக் குறிப்பின் நிலையான பொறுத்தத்தை நிச்சயமாக நீக்க விரும்புகிறீர்களா?",
"IKKHqV": "பின்தொடர்வுகள்",
"IVbtTS": "Zap all {n} sats",
"IWz1ta": "Auto Translate",
"Ig9/a1": "Sent {n} sats to {name}",
"IoQq+a": "Click here to load anyway",
"Ix8l+B": "Trending Notes",
"IVbtTS": "{n} சாட்கள் ஜாப் செய்",
"IWz1ta": "தானியங்கு மொழிபெயர்ப்பு",
"Ig9/a1": "{name} க்கு {n} சாட்ஸ் அனுப்பப்பட்டது",
"IoQq+a": "எப்படியும் ஏற்ற இங்கே கிளிக் செய்யவும்",
"Ix8l+B": "பிரபலமான குறிப்புகள்",
"J+dIsA": "சந்தாக்கள்",
"J2HeQ+": "Use commas to separate words e.g. word1, word2, word3",
"J2HeQ+": "சொற்களைப் பிரிக்க காற்புள்ளிகளைப் பயன்படுத்தவும் எ.கா. சொல்1, சொல்2, சொல்3",
"JCIgkj": "பயனர் பெயர்",
"JGrt9q": "Send sats to {name}",
"JGrt9q": "{name} க்கு சாட்களை அனுப்பு",
"JHEHCk": "ஜாப்கள் ({n})",
"JIVWWA": "Sport",
"JPFYIM": "No lightning address",
"JSx7y9": "Subscribe to {site_name} {plan} for {price} and receive the following rewards",
"JIVWWA": "விளையாட்டு",
"JPFYIM": "லைட்னிங் முகவரி இல்லை",
"JSx7y9": "{price} க்கு {site_name} {plan} இல் குழுசேர்ந்து பின்வரும் வெகுமதிகளைப் பெறுங்கள்",
"JeoS4y": "மறுபதிவு",
"JjGgXI": "பயனர்களைத் தேடுக",
"JkLHGw": "வலைத்தளம்",
@ -192,24 +194,24 @@
"K3r6DQ": "நீக்கு",
"K7AkdL": "காண்பி",
"KAhAcM": "LNDHub கட்டமைப்பை உள்ளிடவும்",
"KHK8B9": "Relay",
"KHK8B9": "ரிலே",
"KQvWvD": "நீக்கப்பட்டது",
"KahimY": "அறிந்திராத நிகழ்வு வகை: {kind}",
"KoFlZg": "Enter mint URL",
"KtsyO0": "Enter Pin",
"KoFlZg": "mint URL ஐ உள்ளிடவும்",
"KtsyO0": "பின்னை உள்ளிடவும்",
"LF5kYT": "பிற இணைப்புகள்",
"LR1XjT": "Pin too short",
"LR1XjT": "பின் மிகவும் சிறியது",
"LXxsbk": "பெயரிலா",
"LgbKvU": "கருத்து",
"Lu5/Bj": "Open on Zapstr",
"Lw+I+J": "{n,plural,=0{{name} zapped} other{{name} & {n} others zapped}}",
"LwYmVi": "Zaps on this note will be split to the following users.",
"Lu5/Bj": "Zapstr இல் திறக்கவும்",
"Lw+I+J": "{n,plural,=0{{name} zapped} other{{{name} & {n} others zapped}}",
"LwYmVi": "இந்தக் குறிப்பில் உள்ள Zaps பின்வரும் பயனர்களுக்குப் பிரிக்கப்படும்.",
"M3Oirc": "மெனுக்களை பிழை திருத்தவும்",
"MBAYRO": "ஒவ்வொரு செய்தியிலும் சூழல் மெனுவில் \"IDஐ நகலெடு\" மற்றும் \"நிகழ்வு JSONஐ நகலெடு\" ஆகியவற்றைக் காட்டுகிறது",
"MI2jkA": "கிடைக்கவில்லை:",
"MP54GY": "பணப்பை கடவுச்சொல்",
"MWTx65": "இயல்புநிலை பக்கம்",
"MiMipu": "Set as primary Nostr address (nip05)",
"MiMipu": "முதன்மை Nostr முகவரியாக அமைக்கவும் (nip05)",
"Mrpkot": "சந்தாவுக்கு பணம் செலுத்துங்கள்",
"MuVeKe": "Buy nostr address",
"MzRYWH": "{item} வாங்கப் படுகிறது",
@ -274,6 +276,7 @@
"Ub+AGc": "Sign In",
"Up5U7K": "முடக்கு",
"UrKTqQ": "You have an active iris.to account",
"VL900k": "Recommended Relays",
"VN0+Fz": "இருப்பு: {amount} ஸாட்கள்",
"VOjC1i": "எந்தப் பதிவேற்ற சேவையில் இணைப்புகளைப் பதிவேற்ற விரும்புகிறீர்கள் என்பதைத் தேர்ந்தெடுக்கவும்",
"VR5eHw": "பொது சாவி (npub/nprofile)",
@ -381,6 +384,7 @@
"jAmfGl": "Your {site_name} subscription is expired",
"jHa/ko": "Clean up your feed",
"jMzO1S": "உள் பிழை: {msg}",
"jTrbGf": "{n} km - {location}",
"jfV8Wr": "பின்",
"jvo0vs": "சேமி",
"jzgQ2z": "{n} எதிர்வினைகள்",

View File

@ -21,11 +21,13 @@
"08zn6O": "ส่งออกกุญแจ",
"0Azlrb": "จัดการ",
"0BUTMv": "ค้นหา...",
"0HFX0T": "Use Exact Location",
"0jOEtS": "LNURL ไม่ถูกต้อง",
"0mch2Y": "ชื่อมีอักขระที่ไม่อนุญาตให้ใช้",
"0siT4z": "Politics",
"0uoY11": "Show Status",
"0yO7wF": "{n} วินาที",
"1H4Keq": "{n} users",
"1Mo59U": "คุณแน่ใจหรือว่าต้องการลบโน้ตนี้ออกจากบุ๊คมาร์ค?",
"1R43+L": "ใส่ Nostr Wallet Connect config",
"1c4YST": "เชื่อมต่อกับ: {node} 🎉",
@ -274,6 +276,7 @@
"Ub+AGc": "Sign In",
"Up5U7K": "บล็อก",
"UrKTqQ": "You have an active iris.to account",
"VL900k": "Recommended Relays",
"VN0+Fz": "คงเหลือ: {amount} sats",
"VOjC1i": "เลือกบริการอัปโหลดที่คุณต้องการอัปโหลดไฟล์แนบ",
"VR5eHw": "Public key (npub/nprofile)",
@ -381,6 +384,7 @@
"jAmfGl": "Your {site_name} subscription is expired",
"jHa/ko": "Clean up your feed",
"jMzO1S": "ข้อผิดพลาดภายใน: {msg}",
"jTrbGf": "{n} km - {location}",
"jfV8Wr": "ย้อนกลับ",
"jvo0vs": "บันทึก",
"jzgQ2z": "{n} Reactions",

View File

@ -21,11 +21,13 @@
"08zn6O": "导出密钥",
"0Azlrb": "管理",
"0BUTMv": "搜索...",
"0HFX0T": "Use Exact Location",
"0jOEtS": "LNURL无效",
"0mch2Y": "名称中有禁用字符",
"0siT4z": "政治",
"0uoY11": "显示状态",
"0yO7wF": "{n} 秒",
"1H4Keq": "{n} users",
"1Mo59U": "是否确定要从收藏中移除此条笔记?",
"1R43+L": "输入 Nostr Wallet Connect 配置",
"1c4YST": "已连接到:{node}🎉",
@ -274,6 +276,7 @@
"Ub+AGc": "登录",
"Up5U7K": "屏蔽",
"UrKTqQ": "你有一个活跃的 iris.to 帐户",
"VL900k": "Recommended Relays",
"VN0+Fz": "余额: {amount} 聪",
"VOjC1i": "选择你要将附件上传到哪个上传服务",
"VR5eHw": "公钥 (npub/nprofile)",
@ -381,6 +384,7 @@
"jAmfGl": "你的 {site_name} 订阅已过期",
"jHa/ko": "清理你的订阅",
"jMzO1S": "内部错误: {msg}",
"jTrbGf": "{n} km - {location}",
"jfV8Wr": "返回",
"jvo0vs": "保存",
"jzgQ2z": "{n} 个回应",

View File

@ -21,11 +21,13 @@
"08zn6O": "導出密鑰",
"0Azlrb": "管理",
"0BUTMv": "搜索...",
"0HFX0T": "Use Exact Location",
"0jOEtS": "LNURL 無效",
"0mch2Y": "名稱中有禁用字符",
"0siT4z": "政治",
"0uoY11": "顯示狀態",
"0yO7wF": "{n} 秒",
"1H4Keq": "{n} users",
"1Mo59U": "是否確定要從收藏中移除此條筆記?",
"1R43+L": "輸入 Nostr Wallet Connect 配置",
"1c4YST": "已連接到:{node} 🎉",
@ -274,6 +276,7 @@
"Ub+AGc": "登錄",
"Up5U7K": "屏蔽",
"UrKTqQ": "你有一個活躍的 iris.to 帳戶",
"VL900k": "Recommended Relays",
"VN0+Fz": "餘額:{amount} 聰",
"VOjC1i": "選擇你要將附件上傳到哪個上傳服務",
"VR5eHw": "公鑰npub/nprofile",
@ -381,6 +384,7 @@
"jAmfGl": "你的 {site_name} 訂閱已過期了",
"jHa/ko": "清理你的訂閱",
"jMzO1S": "內部錯誤:{msg}",
"jTrbGf": "{n} km - {location}",
"jfV8Wr": "返回",
"jvo0vs": "保存",
"jzgQ2z": "{n} 個回應",

View File

@ -144,13 +144,9 @@ export function getPublicKey(privKey: string) {
}
export function bech32ToHex(str: string) {
try {
const nKey = bech32.decode(str, 1_000);
const buff = bech32.fromWords(nKey.words);
return utils.bytesToHex(Uint8Array.from(buff));
} catch (e) {
return str;
}
const nKey = bech32.decode(str, 1_000);
const buff = bech32.fromWords(nKey.words);
return utils.bytesToHex(Uint8Array.from(buff));
}
/**
@ -159,13 +155,9 @@ export function bech32ToHex(str: string) {
* @returns
*/
export function bech32ToText(str: string) {
try {
const decoded = bech32.decode(str, 1000);
const buf = bech32.fromWords(decoded.words);
return new TextDecoder().decode(Uint8Array.from(buf));
} catch {
return "";
}
const decoded = bech32.decode(str, 1000);
const buf = bech32.fromWords(decoded.words);
return new TextDecoder().decode(Uint8Array.from(buf));
}
export async function fetchNip05Pubkey(name: string, domain: string, timeout = 2_000): Promise<string | undefined> {

View File

@ -233,11 +233,16 @@ export function tryParseNostrLink(link: string, prefixHint?: NostrPrefix): Nostr
}
}
export function parseNostrLink(link: string, prefixHint?: NostrPrefix): NostrLink {
export function trimNostrLink(link: string) {
let entity = link.startsWith("web+nostr:") || link.startsWith("nostr:") ? link.split(":")[1] : link;
// trim any non-bech32 chars
entity = entity.match(/(n(?:pub|profile|event|ote|addr|req)1[acdefghjklmnpqrstuvwxyz023456789]+)/)?.[0] ?? entity;
return entity;
}
export function parseNostrLink(link: string, prefixHint?: NostrPrefix): NostrLink {
const entity = trimNostrLink(link);
const isPrefix = (prefix: NostrPrefix) => {
return entity.startsWith(prefix);