feat: relay info page

This commit is contained in:
2024-09-11 13:50:45 +01:00
parent 9660c07633
commit 6fafae67aa
14 changed files with 747 additions and 188 deletions

View File

@ -33,10 +33,11 @@ interface CollapsedSectionProps {
title: ReactNode; title: ReactNode;
children: ReactNode; children: ReactNode;
className?: string; className?: string;
startClosed?: boolean;
} }
export const CollapsedSection = ({ title, children, className }: CollapsedSectionProps) => { export const CollapsedSection = ({ title, children, className, startClosed }: CollapsedSectionProps) => {
const [collapsed, setCollapsed] = useState(true); const [collapsed, setCollapsed] = useState(startClosed ?? true);
const icon = ( const icon = (
<div className={classNames("collapse-icon", { flip: !collapsed })}> <div className={classNames("collapse-icon", { flip: !collapsed })}>
<Icon name="arrowFront" /> <Icon name="arrowFront" />

View File

@ -1,6 +1,4 @@
import { RelaySettings } from "@snort/system"; import { Link } from "react-router-dom";
import classNames from "classnames";
import { FormattedMessage } from "react-intl";
import useRelayState from "@/Feed/RelayState"; import useRelayState from "@/Feed/RelayState";
import useLogin from "@/Hooks/useLogin"; import useLogin from "@/Hooks/useLogin";
@ -8,65 +6,30 @@ import RelayUptime from "@/Pages/settings/relays/uptime";
import { getRelayName } from "@/Utils"; import { getRelayName } from "@/Utils";
import Icon from "../Icons/Icon"; import Icon from "../Icons/Icon";
import RelayPermissions from "./permissions";
import RelayStatusLabel from "./status-label";
export interface RelayProps { export interface RelayProps {
addr: string; addr: string;
} }
export default function Relay(props: RelayProps) { export default function Relay(props: RelayProps) {
const { state } = useLogin(s => ({ v: s.state.version, state: s.state }));
const connection = useRelayState(props.addr); const connection = useRelayState(props.addr);
const { state } = useLogin(s => ({ v: s.state.version, state: s.state }));
const settings = state.relays?.find(a => a.url === props.addr)?.settings; if (!connection) return;
if (!connection || !settings) return;
async function configure(o: RelaySettings) {
await state.updateRelay(props.addr, o);
}
const name = connection.info?.name ?? getRelayName(props.addr); const name = connection.info?.name ?? getRelayName(props.addr);
return ( return (
<tr> <tr>
<td className="text-ellipsis" title={props.addr}> <td className="text-ellipsis" title={props.addr}>
{name.length > 20 ? <>{name.slice(0, 20)}...</> : name} <Link to={`/settings/relays/${encodeURIComponent(props.addr)}`}>
{name.length > 20 ? <>{name.slice(0, 20)}...</> : name}
</Link>
</td> </td>
<td> <td>
<div className="flex gap-1 items-center"> <RelayStatusLabel conn={connection} />
<div
className={classNames("rounded-full w-4 h-4", {
"bg-success": connection.isOpen,
"bg-error": !connection.isOpen,
})}></div>
{connection.isOpen ? (
<FormattedMessage defaultMessage="Connected" />
) : (
<FormattedMessage defaultMessage="Offline" />
)}
</div>
</td> </td>
<td> <td>
<div className="flex gap-2 cursor-pointer select-none justify-center"> <RelayPermissions conn={connection} />
<div
className={settings.read ? "" : "text-gray"}
onClick={() =>
configure({
read: !settings.read,
write: settings.write,
})
}>
<FormattedMessage defaultMessage="Read" />
</div>
<div
className={settings.write ? "" : "text-gray"}
onClick={() =>
configure({
read: settings.read,
write: !settings.write,
})
}>
<FormattedMessage defaultMessage="Write" />
</div>
</div>
</td> </td>
<td className="text-center"> <td className="text-center">
<RelayUptime url={props.addr} /> <RelayUptime url={props.addr} />

View File

@ -1,9 +0,0 @@
.favicon {
width: 21px;
height: 21px;
max-width: unset;
}
.relay-active {
color: var(--highlight);
}

View File

@ -1,12 +1,10 @@
import "./RelaysMetadata.css";
import { FullRelaySettings } from "@snort/system"; import { FullRelaySettings } from "@snort/system";
import { useState } from "react"; import { useState } from "react";
import Nostrich from "@/assets/img/nostrich.webp"; import Nostrich from "@/assets/img/nostrich.webp";
import Icon from "@/Components/Icons/Icon"; import Icon from "@/Components/Icons/Icon";
export const RelayFavicon = ({ url }: { url: string }) => { export const RelayFavicon = ({ url, size }: { url: string; size?: number }) => {
const cleanUrl = url const cleanUrl = url
.replace(/^wss:\/\//, "https://") .replace(/^wss:\/\//, "https://")
.replace(/^ws:\/\//, "http://") .replace(/^ws:\/\//, "http://")
@ -14,10 +12,12 @@ export const RelayFavicon = ({ url }: { url: string }) => {
const [faviconUrl, setFaviconUrl] = useState(`${cleanUrl}/favicon.ico`); const [faviconUrl, setFaviconUrl] = useState(`${cleanUrl}/favicon.ico`);
return ( return (
<img <img
className="circle favicon" className="rounded-full object-cover"
src={faviconUrl} src={faviconUrl}
onError={() => setFaviconUrl(Nostrich)} onError={() => setFaviconUrl(Nostrich)}
alt={`favicon for ${url}`} alt={`favicon for ${url}`}
width={size ?? 20}
height={size ?? 20}
/> />
); );
}; };

View File

@ -0,0 +1,17 @@
import { RelayInfo } from "@snort/system";
import classNames from "classnames";
import { FormattedMessage } from "react-intl";
export default function RelayPaymentLabel({ info }: { info: RelayInfo }) {
const isPaid = info?.limitation?.payment_required ?? false;
return (
<div
className={classNames("rounded-full px-2 py-1 font-medium", {
"bg-[var(--pro)] text-black": isPaid,
"bg-[var(--free)]": !isPaid,
})}>
{isPaid && <FormattedMessage defaultMessage="Paid" />}
{!isPaid && <FormattedMessage defaultMessage="Free" />}
</div>
);
}

View File

@ -0,0 +1,33 @@
import { ConnectionType } from "@snort/system/dist/connection-pool";
import { FormattedMessage } from "react-intl";
import useLogin from "@/Hooks/useLogin";
export default function RelayPermissions({ conn }: { conn: ConnectionType }) {
const { state } = useLogin(s => ({ v: s.state.version, state: s.state }));
return (
<div className="flex gap-2 cursor-pointer select-none">
<div
className={conn.settings.read ? "" : "text-gray"}
onClick={async () =>
await state.updateRelay(conn.address, {
read: !conn.settings.read,
write: conn.settings.write,
})
}>
<FormattedMessage defaultMessage="Read" />
</div>
<div
className={conn.settings.write ? "" : "text-gray"}
onClick={async () =>
await state.updateRelay(conn.address, {
read: conn.settings.read,
write: !conn.settings.write,
})
}>
<FormattedMessage defaultMessage="Write" />
</div>
</div>
);
}

View File

@ -0,0 +1,9 @@
import { Link } from "react-router-dom";
export default function RelaySoftware({ software }: { software: string }) {
if (software.includes("git")) {
const u = new URL(software);
return <Link to={software}>{u.pathname.split("/").at(-1)?.replace(".git", "")}</Link>;
}
return software;
}

View File

@ -0,0 +1,16 @@
import { ConnectionType } from "@snort/system/dist/connection-pool";
import classNames from "classnames";
import { FormattedMessage } from "react-intl";
export default function RelayStatusLabel({ conn }: { conn: ConnectionType }) {
return (
<div className="flex gap-1 items-center">
<div
className={classNames("rounded-full w-4 h-4", {
"bg-success": conn.isOpen,
"bg-error": !conn.isOpen,
})}></div>
{conn.isOpen ? <FormattedMessage defaultMessage="Connected" /> : <FormattedMessage defaultMessage="Offline" />}
</div>
);
}

View File

@ -0,0 +1,149 @@
import { FormattedMessage } from "react-intl";
export default function NipDescription({ nip }: { nip: number }) {
switch (nip) {
case 1:
return <FormattedMessage defaultMessage="Basic protocol flow description" />;
case 2:
return <FormattedMessage defaultMessage="Follow List" />;
case 3:
return <FormattedMessage defaultMessage="OpenTimestamps Attestations for Events" />;
case 4:
return <FormattedMessage defaultMessage="Encrypted Direct Message" />;
case 5:
return <FormattedMessage defaultMessage="Mapping Nostr keys to DNS-based internet identifiers" />;
case 6:
return <FormattedMessage defaultMessage="Basic key derivation from mnemonic seed phrase" />;
case 7:
return <FormattedMessage defaultMessage="window.nostr capability for web browsers" />;
case 8:
return <FormattedMessage defaultMessage="Handling Mentions" />;
case 9:
return <FormattedMessage defaultMessage="Event Deletion Request" />;
case 10:
return <FormattedMessage defaultMessage="Conventions for clients' use of e and p tags in text events" />;
case 11:
return <FormattedMessage defaultMessage="Relay Information Document" />;
case 13:
return <FormattedMessage defaultMessage="Proof of Work" />;
case 14:
return <FormattedMessage defaultMessage="Subject tag in text events" />;
case 15:
return <FormattedMessage defaultMessage="Nostr Marketplace (for resilient marketplaces)" />;
case 17:
return <FormattedMessage defaultMessage="Private Direct Messages" />;
case 18:
return <FormattedMessage defaultMessage="Reposts" />;
case 19:
return <FormattedMessage defaultMessage="bech32-encoded entities" />;
case 21:
return <FormattedMessage defaultMessage="nostr: URI scheme" />;
case 23:
return <FormattedMessage defaultMessage="Long-form Content" />;
case 24:
return <FormattedMessage defaultMessage="Extra metadata fields and tags" />;
case 25:
return <FormattedMessage defaultMessage="Reactions" />;
case 26:
return <FormattedMessage defaultMessage="Delegated Event Signing" />;
case 27:
return <FormattedMessage defaultMessage="Text Note References" />;
case 28:
return <FormattedMessage defaultMessage="Public Chat" />;
case 29:
return <FormattedMessage defaultMessage="Relay-based Groups" />;
case 30:
return <FormattedMessage defaultMessage="Custom Emoji" />;
case 31:
return <FormattedMessage defaultMessage="Dealing with Unknown Events" />;
case 32:
return <FormattedMessage defaultMessage="Labeling" />;
case 34:
return <FormattedMessage defaultMessage="git stuff" />;
case 35:
return <FormattedMessage defaultMessage="Torrents" />;
case 36:
return <FormattedMessage defaultMessage="Sensitive Content" />;
case 38:
return <FormattedMessage defaultMessage="User Statuses" />;
case 39:
return <FormattedMessage defaultMessage="External Identities in Profiles" />;
case 40:
return <FormattedMessage defaultMessage="Expiration Timestamp" />;
case 42:
return <FormattedMessage defaultMessage="Authentication of clients to relays" />;
case 44:
return <FormattedMessage defaultMessage="Versioned Encryption" />;
case 45:
return <FormattedMessage defaultMessage="Counting results" />;
case 46:
return <FormattedMessage defaultMessage="Nostr Connect" />;
case 47:
return <FormattedMessage defaultMessage="Wallet Connect" />;
case 48:
return <FormattedMessage defaultMessage="Proxy Tags" />;
case 49:
return <FormattedMessage defaultMessage="Private Key Encryption" />;
case 50:
return <FormattedMessage defaultMessage="Search Capability" />;
case 51:
return <FormattedMessage defaultMessage="Lists" />;
case 52:
return <FormattedMessage defaultMessage="Calendar Events" />;
case 53:
return <FormattedMessage defaultMessage="Live Activities" />;
case 54:
return <FormattedMessage defaultMessage="Wiki" />;
case 55:
return <FormattedMessage defaultMessage="Android Signer Application" />;
case 56:
return <FormattedMessage defaultMessage="Reporting" />;
case 57:
return <FormattedMessage defaultMessage="Lightning Zaps" />;
case 58:
return <FormattedMessage defaultMessage="Badges" />;
case 59:
return <FormattedMessage defaultMessage="Gift Wrap" />;
case 64:
return <FormattedMessage defaultMessage="Chess (PGN)" />;
case 65:
return <FormattedMessage defaultMessage="Relay List Metadata" />;
case 70:
return <FormattedMessage defaultMessage="Protected Events" />;
case 71:
return <FormattedMessage defaultMessage="Video Events" />;
case 72:
return <FormattedMessage defaultMessage="Moderated Communities" />;
case 73:
return <FormattedMessage defaultMessage="External Content IDs" />;
case 75:
return <FormattedMessage defaultMessage="Zap Goals" />;
case 78:
return <FormattedMessage defaultMessage="Application-specific data" />;
case 84:
return <FormattedMessage defaultMessage="Highlights" />;
case 89:
return <FormattedMessage defaultMessage="Recommended Application Handlers" />;
case 90:
return <FormattedMessage defaultMessage="Data Vending Machines" />;
case 92:
return <FormattedMessage defaultMessage="Media Attachments" />;
case 94:
return <FormattedMessage defaultMessage="File Metadata" />;
case 96:
return <FormattedMessage defaultMessage="HTTP File Storage Integration" />;
case 98:
return <FormattedMessage defaultMessage="HTTP Auth" />;
case 99:
return <FormattedMessage defaultMessage="Classified Listings" />;
default:
return (
<FormattedMessage
defaultMessage="Unknown NIP-{x}"
values={{
x: nip.toString().padStart(2, "0"),
}}
/>
);
}
}

View File

@ -1,126 +1,212 @@
import { Connection } from "@snort/system"; import { RelayInfo as RI } from "@snort/system";
import { FormattedMessage } from "react-intl"; import { useEffect, useState, useSyncExternalStore } from "react";
import { useNavigate, useParams } from "react-router-dom"; import { FormattedMessage, FormattedNumber } from "react-intl";
import { Link, useParams } from "react-router-dom";
import AsyncButton from "@/Components/Button/AsyncButton"; import { RelayMetrics } from "@/Cache";
import ProfilePreview from "@/Components/User/ProfilePreview"; import { CollapsedSection } from "@/Components/Collapsed";
import NipDescription from "@/Components/nip";
import RelayPaymentLabel from "@/Components/Relay/paid";
import RelayPermissions from "@/Components/Relay/permissions";
import { RelayFavicon } from "@/Components/Relay/RelaysMetadata";
import RelaySoftware from "@/Components/Relay/software";
import RelayStatusLabel from "@/Components/Relay/status-label";
import ProfileImage from "@/Components/User/ProfileImage";
import useRelayState from "@/Feed/RelayState"; import useRelayState from "@/Feed/RelayState";
import useEventPublisher from "@/Hooks/useEventPublisher"; import { getRelayName, parseId } from "@/Utils";
import useLogin from "@/Hooks/useLogin";
import { parseId, unwrap } from "@/Utils";
import messages from "./messages"; import RelayUptime from "./relays/uptime";
const RelayInfo = () => { const RelayInfo = () => {
const params = useParams(); const params = useParams();
const navigate = useNavigate(); const [info, setInfo] = useState<RI>();
const login = useLogin();
const { system } = useEventPublisher();
const conn = [...system.pool].find(([, a]) => a.id === params.id)?.[1]; const conn = useRelayState(params.id ?? "");
async function loadRelayInfo() {
const u = new URL(params.id ?? "");
const rsp = await fetch(`${u.protocol === "wss:" ? "https:" : "http:"}//${u.host}`, {
headers: {
accept: "application/nostr+json",
},
});
if (rsp.ok) {
const data = await rsp.json();
for (const [k, v] of Object.entries(data)) {
if (v === "unset" || v === "" || v === "~") {
data[k] = undefined;
}
}
setInfo(data);
}
}
useEffect(() => {
loadRelayInfo().catch(console.error);
}, []);
const stats = useSyncExternalStore(
c => RelayMetrics.hook(c, "*"),
() => RelayMetrics.snapshot(),
).find(a => a.addr === params.id);
const stats = useRelayState(conn?.address ?? "");
return ( return (
<> <>
<h3 className="pointer" onClick={() => navigate("/settings/relays")}> <div className="flex flex-col gap-4">
<FormattedMessage {...messages.Relays} /> <div className="flex justify-between">
</h3> <div className="flex gap-4 items-center">
<div> <RelayFavicon url={params.id ?? ""} size={80} />
<h3>{stats?.info?.name}</h3> <div className="flex flex-col gap-2">
<p>{stats?.info?.description}</p> <div className="flex items-center gap-2">
<div className="text-2xl font-bold">{info?.name ?? getRelayName(params.id ?? "")}</div>
{stats?.info?.pubkey && ( {info && <RelayPaymentLabel info={info} />}
<> </div>
<h4> <div className="text-gray-light">{params.id}</div>
<FormattedMessage {...messages.Owner} />
</h4>
<ProfilePreview pubkey={parseId(stats.info.pubkey)} />
</>
)}
{stats?.info?.software && (
<div className="flex">
<h4 className="grow">
<FormattedMessage {...messages.Software} />
</h4>
<div className="flex flex-col">
{stats.info.software.startsWith("http") ? (
<a href={stats.info.software} target="_blank" rel="noreferrer">
{stats.info.software}
</a>
) : (
<>{stats.info.software}</>
)}
<small>
{!stats.info.version?.startsWith("v") && "v"}
{stats.info.version}
</small>
</div> </div>
</div> </div>
)}
{stats?.info?.contact && (
<div className="flex">
<h4 className="grow">
<FormattedMessage {...messages.Contact} />
</h4>
<a
href={`${stats.info.contact.startsWith("mailto:") ? "" : "mailto:"}${stats.info.contact}`}
target="_blank"
rel="noreferrer">
{stats.info.contact}
</a>
</div>
)}
{stats?.info?.supported_nips && (
<>
<h4>
<FormattedMessage {...messages.Supports} />
</h4>
<div className="grow">
{stats.info?.supported_nips?.map(a => (
<a key={a} target="_blank" rel="noreferrer" href={`https://nips.be/${a}`} className="pill">
NIP-{a.toString().padStart(2, "0")}
</a>
))}
</div>
</>
)}
{conn instanceof Connection && (
<>
<h4>
<FormattedMessage defaultMessage="Active Subscriptions" />
</h4>
<div className="grow">
{conn.ActiveRequests.map(a => (
<span className="pill" key={a}>
{a}
</span>
))}
</div>
</>
)}
{conn instanceof Connection && (
<>
<h4>
<FormattedMessage defaultMessage="Pending Subscriptions" />
</h4>
<div className="grow">
{conn.PendingRequests.map(a => (
<span className="pill" key={a.obj[1]}>
{a.obj[1]}
</span>
))}
</div>
</>
)}
<div className="flex mt10 justify-end">
<AsyncButton
onClick={async () => {
await login.state.removeRelay(unwrap(conn).address, true);
navigate("/settings/relays");
}}>
<FormattedMessage {...messages.Remove} />
</AsyncButton>
</div> </div>
{info && (
<div className="grid grid-cols-3 gap-4">
<div className="flex flex-col gap-2">
<div className="uppercase text-secondary font-bold text-sm">
<FormattedMessage defaultMessage="Admin" />
</div>
<div>{info?.pubkey && <ProfileImage pubkey={parseId(info.pubkey)} size={30} />}</div>
</div>
<div className="flex flex-col gap-2">
<div className="uppercase text-secondary font-bold text-sm">
<FormattedMessage defaultMessage="Contact" />
</div>
<div>
{info?.contact && (
<a
href={`${info.contact.startsWith("mailto:") ? "" : "mailto:"}${info.contact}`}
target="_blank"
rel="noreferrer">
{info.contact.replace("mailto:", "")}
</a>
)}
</div>
</div>
<div className="flex flex-col gap-2">
<div className="uppercase text-secondary font-bold text-sm">
<FormattedMessage defaultMessage="Software" />
</div>
<div>{info?.software && <RelaySoftware software={info.software} />}</div>
</div>
{conn && (
<>
<div className="flex flex-col gap-2">
<div className="uppercase text-secondary font-bold text-sm">
<FormattedMessage defaultMessage="Status" />
</div>
<div>
<RelayStatusLabel conn={conn} />
</div>
</div>
<div className="flex flex-col gap-2">
<div className="uppercase text-secondary font-bold text-sm">
<FormattedMessage defaultMessage="Permissions" />
</div>
<div>
<RelayPermissions conn={conn} />
</div>
</div>
<div className="flex flex-col gap-2">
<div className="uppercase text-secondary font-bold text-sm">
<FormattedMessage defaultMessage="Uptime" />
</div>
<div>
<RelayUptime url={conn.address} />
</div>
</div>
</>
)}
</div>
)}
<hr className="border-border-color" />
{stats && (
<CollapsedSection
title={
<div className="text-xl font-semibold">
<FormattedMessage defaultMessage="Relay Stats" />
</div>
}
startClosed={false}>
<ul className="list-disc">
<li>
<span className="text-gray-light">
<FormattedMessage defaultMessage="Total Events:" />
</span>
&nbsp;
<FormattedNumber value={stats.events} />
</li>
<li>
<span className="text-gray-light">
<FormattedMessage defaultMessage="Connection Success:" />
</span>
&nbsp;
<FormattedNumber value={stats.connects} />
</li>
<li>
<span className="text-gray-light">
<FormattedMessage defaultMessage="Connection Failed:" />
</span>
&nbsp;
<FormattedNumber value={stats.disconnects} />
</li>
<li>
<span className="text-gray-light">
<FormattedMessage defaultMessage="Average Latency:" />
</span>
&nbsp;
<FormattedMessage
defaultMessage="{n} ms"
values={{
n: (
<FormattedNumber
maximumFractionDigits={0}
value={stats.latency.reduce((acc, v) => acc + v, 0) / stats.latency.length}
/>
),
}}
/>
</li>
<li>
<span className="text-gray-light">
<FormattedMessage defaultMessage="Last Seen:" />
</span>
&nbsp;
{new Date(stats.lastSeen).toLocaleString()}
</li>
</ul>
</CollapsedSection>
)}
<hr className="border-border-color" />
{info?.supported_nips && (
<CollapsedSection
title={
<div className="text-xl font-semibold">
<FormattedMessage defaultMessage="Supported NIPs" />
</div>
}
startClosed={false}>
<ul className="list-disc">
{info.supported_nips.map(n => (
<li key={n}>
<Link
target="_blank"
to={`https://github.com/nostr-protocol/nips/blob/master/${n.toString().padStart(2, "0")}.md`}>
<NipDescription nip={n} />
</Link>
</li>
))}
</ul>
</CollapsedSection>
)}
</div> </div>
</> </>
); );

View File

@ -3,6 +3,7 @@ import { OutboxModel } from "@snort/system";
import { SnortContext } from "@snort/system-react"; import { SnortContext } from "@snort/system-react";
import { useContext, useMemo, useSyncExternalStore } from "react"; import { useContext, useMemo, useSyncExternalStore } from "react";
import { FormattedMessage } from "react-intl"; import { FormattedMessage } from "react-intl";
import { Link } from "react-router-dom";
import { RelayMetrics } from "@/Cache"; import { RelayMetrics } from "@/Cache";
import AsyncButton from "@/Components/Button/AsyncButton"; import AsyncButton from "@/Components/Button/AsyncButton";
@ -89,9 +90,11 @@ export function DiscoverRelays() {
.slice(0, 20) .slice(0, 20)
.map(a => ( .map(a => (
<tr key={a.relay}> <tr key={a.relay}>
<td className="flex gap-2 items-center"> <td>
<RelayFavicon url={a.relay} /> <Link to={`/settings/relays/${encodeURIComponent(a.relay)}`} className="flex gap-2 items-center">
{getRelayName(a.relay)} <RelayFavicon url={a.relay} />
{getRelayName(a.relay)}
</Link>
</td> </td>
<td className="text-center"> <td className="text-center">
<RelayUptime url={a.relay} /> <RelayUptime url={a.relay} />
@ -135,9 +138,11 @@ export function DiscoverRelays() {
<tbody> <tbody>
{reliableRelays.slice(0, 40).map(a => ( {reliableRelays.slice(0, 40).map(a => (
<tr key={a.addr}> <tr key={a.addr}>
<td className="flex gap-2 items-center" title={a.addr}> <td title={a.addr}>
<RelayFavicon url={a.addr} /> <Link to={`/settings/relays/${encodeURIComponent(a.addr)}`} className="flex gap-2 items-center">
{getRelayName(a.addr)} <RelayFavicon url={a.addr} />
{getRelayName(a.addr)}
</Link>
</td> </td>
<td className="text-center"> <td className="text-center">
<UptimeLabel avgPing={a.avgLatency} /> <UptimeLabel avgPing={a.avgLatency} />

View File

@ -54,6 +54,7 @@
--primary-bg: #ff3f15; --primary-bg: #ff3f15;
--cashu-gradient: linear-gradient(90deg, #40b039, #adff2a); --cashu-gradient: linear-gradient(90deg, #40b039, #adff2a);
--pro: #ffdd65; --pro: #ffdd65;
--free: #1a5aff;
} }
::-webkit-scrollbar { ::-webkit-scrollbar {
@ -121,6 +122,10 @@ code {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;
} }
ul {
padding-inline-start: 2rem;
}
a { a {
color: inherit; color: inherit;
line-height: 1.3em; line-height: 1.3em;
@ -227,7 +232,8 @@ a.ext {
small { small {
color: var(--font-secondary-color); color: var(--font-secondary-color);
font-size: 14px; font-size: 14px;
line-height: 22px; /* 157.143% */ line-height: 22px;
/* 157.143% */
} }
.button { .button {
@ -898,6 +904,7 @@ svg.repeat {
border: 1px solid var(--border-color); border: 1px solid var(--border-color);
box-shadow: rgba(0, 0, 0, 0.08) 0 1px 1px; box-shadow: rgba(0, 0, 0, 0.08) 0 1px 1px;
} }
.light button.primary { .light button.primary {
background: var(--primary-bg); background: var(--primary-bg);
color: #fff; color: #fff;
@ -909,6 +916,7 @@ svg.repeat {
.light button.secondary:hover { .light button.secondary:hover {
box-shadow: rgba(0, 0, 0, 0.2) 0 1px 3px !important; box-shadow: rgba(0, 0, 0, 0.2) 0 1px 3px !important;
} }
.light button.primary:hover { .light button.primary:hover {
box-shadow: 0px 0px 10px var(--primary-bg) !important; box-shadow: 0px 0px 10px var(--primary-bg) !important;
} }
@ -923,7 +931,8 @@ svg.repeat {
} }
.hide-scrollbar::-webkit-scrollbar { .hide-scrollbar::-webkit-scrollbar {
display: none; /* Safari and Chrome */ display: none;
/* Safari and Chrome */
} }
.pb-safe-area { .pb-safe-area {

View File

@ -8,6 +8,9 @@
"+QM0PJ": { "+QM0PJ": {
"defaultMessage": "Sync all events for your profile into local cache" "defaultMessage": "Sync all events for your profile into local cache"
}, },
"+QMdsy": {
"defaultMessage": "Relay Stats"
},
"+UjDmN": { "+UjDmN": {
"defaultMessage": "Logged in with write access" "defaultMessage": "Logged in with write access"
}, },
@ -44,6 +47,9 @@
"/JE/X+": { "/JE/X+": {
"defaultMessage": "Account Support" "defaultMessage": "Account Support"
}, },
"/T7HId": {
"defaultMessage": "HTTP File Storage Integration"
},
"/Xf4UW": { "/Xf4UW": {
"defaultMessage": "Send anonymous usage metrics" "defaultMessage": "Send anonymous usage metrics"
}, },
@ -77,6 +83,9 @@
"0jOEtS": { "0jOEtS": {
"defaultMessage": "Invalid LNURL" "defaultMessage": "Invalid LNURL"
}, },
"0kOBMu": {
"defaultMessage": "Handling Mentions"
},
"0mch2Y": { "0mch2Y": {
"defaultMessage": "name has disallowed characters" "defaultMessage": "name has disallowed characters"
}, },
@ -93,6 +102,9 @@
"defaultMessage": "Go", "defaultMessage": "Go",
"description": "Button text after entering username in quick signup" "description": "Button text after entering username in quick signup"
}, },
"1/BFEj": {
"defaultMessage": "git stuff"
},
"1Mo59U": { "1Mo59U": {
"defaultMessage": "Are you sure you want to remove this note from bookmarks?" "defaultMessage": "Are you sure you want to remove this note from bookmarks?"
}, },
@ -126,6 +138,15 @@
"25WwxF": { "25WwxF": {
"defaultMessage": "Don't have an account?" "defaultMessage": "Don't have an account?"
}, },
"28oKbu": {
"defaultMessage": "Moderated Communities"
},
"29sHFE": {
"defaultMessage": "Wallet Connect"
},
"2BBGxX": {
"defaultMessage": "Subject tag in text events"
},
"2IFGap": { "2IFGap": {
"defaultMessage": "Donate" "defaultMessage": "Donate"
}, },
@ -147,12 +168,18 @@
"2oCF7O": { "2oCF7O": {
"defaultMessage": "Followed by friends of friends" "defaultMessage": "Followed by friends of friends"
}, },
"2raFAu": {
"defaultMessage": "Application-specific data"
},
"2ukA4d": { "2ukA4d": {
"defaultMessage": "{n} hours" "defaultMessage": "{n} hours"
}, },
"39AHJm": { "39AHJm": {
"defaultMessage": "Sign Up" "defaultMessage": "Sign Up"
}, },
"3GWu6/": {
"defaultMessage": "User Statuses"
},
"3KNMbJ": { "3KNMbJ": {
"defaultMessage": "Articles" "defaultMessage": "Articles"
}, },
@ -177,9 +204,18 @@
"3yk8fB": { "3yk8fB": {
"defaultMessage": "Wallet" "defaultMessage": "Wallet"
}, },
"40VR6s": {
"defaultMessage": "Nostr Connect"
},
"41BSaT": {
"defaultMessage": "Total Events:"
},
"450Fty": { "450Fty": {
"defaultMessage": "None" "defaultMessage": "None"
}, },
"47E53q": {
"defaultMessage": "Wiki"
},
"47FYwb": { "47FYwb": {
"defaultMessage": "Cancel" "defaultMessage": "Cancel"
}, },
@ -195,6 +231,9 @@
"4OB335": { "4OB335": {
"defaultMessage": "Dislike" "defaultMessage": "Dislike"
}, },
"4P/kKm": {
"defaultMessage": "Private Key Encryption"
},
"4Vmpt4": { "4Vmpt4": {
"defaultMessage": "Nostr Plebs is one of the first NIP-05 providers in the space and offers a good collection of domains at reasonable prices" "defaultMessage": "Nostr Plebs is one of the first NIP-05 providers in the space and offers a good collection of domains at reasonable prices"
}, },
@ -207,6 +246,9 @@
"4rYCjn": { "4rYCjn": {
"defaultMessage": "Note to Self" "defaultMessage": "Note to Self"
}, },
"4wgYpI": {
"defaultMessage": "Recommended Application Handlers"
},
"5BVs2e": { "5BVs2e": {
"defaultMessage": "zap" "defaultMessage": "zap"
}, },
@ -219,6 +261,9 @@
"5oTnfy": { "5oTnfy": {
"defaultMessage": "Buy Handle" "defaultMessage": "Buy Handle"
}, },
"5qEWCr": {
"defaultMessage": "File Metadata"
},
"5u6iEc": { "5u6iEc": {
"defaultMessage": "Transfer to Pubkey" "defaultMessage": "Transfer to Pubkey"
}, },
@ -234,6 +279,9 @@
"62nsdy": { "62nsdy": {
"defaultMessage": "Retry" "defaultMessage": "Retry"
}, },
"634VVz": {
"defaultMessage": "Connection Failed:"
},
"6559gb": { "6559gb": {
"defaultMessage": "New follow list length {length}" "defaultMessage": "New follow list length {length}"
}, },
@ -255,6 +303,9 @@
"6mr8WU": { "6mr8WU": {
"defaultMessage": "Followed by" "defaultMessage": "Followed by"
}, },
"6pdxsi": {
"defaultMessage": "Extra metadata fields and tags"
},
"6uMqL1": { "6uMqL1": {
"defaultMessage": "Unpaid" "defaultMessage": "Unpaid"
}, },
@ -267,6 +318,12 @@
"712i26": { "712i26": {
"defaultMessage": "Proxy uses HODL invoices to forward the payment, which hides the pubkey of your node" "defaultMessage": "Proxy uses HODL invoices to forward the payment, which hides the pubkey of your node"
}, },
"77nkEO": {
"defaultMessage": "Relay Information Document"
},
"7LFU8U": {
"defaultMessage": "Search Capability"
},
"7UOvbT": { "7UOvbT": {
"defaultMessage": "Offline" "defaultMessage": "Offline"
}, },
@ -282,6 +339,9 @@
"89q5wc": { "89q5wc": {
"defaultMessage": "Confirm Reposts" "defaultMessage": "Confirm Reposts"
}, },
"8BDFvJ": {
"defaultMessage": "Conventions for clients' use of e and p tags in text events"
},
"8ED/4u": { "8ED/4u": {
"defaultMessage": "Reply To" "defaultMessage": "Reply To"
}, },
@ -300,6 +360,9 @@
"8g2vyB": { "8g2vyB": {
"defaultMessage": "name too long" "defaultMessage": "name too long"
}, },
"8jmwT8": {
"defaultMessage": "bech32-encoded entities"
},
"8v1NN+": { "8v1NN+": {
"defaultMessage": "Pairing phrase" "defaultMessage": "Pairing phrase"
}, },
@ -379,6 +442,9 @@
"BGCM48": { "BGCM48": {
"defaultMessage": "Write access to Snort relay, with 1 year of event retention" "defaultMessage": "Write access to Snort relay, with 1 year of event retention"
}, },
"BQW4gi": {
"defaultMessage": "Relay-based Groups"
},
"BWpuKl": { "BWpuKl": {
"defaultMessage": "Update" "defaultMessage": "Update"
}, },
@ -389,6 +455,9 @@
"defaultMessage": "Relay", "defaultMessage": "Relay",
"description": "Relay name (URL)" "description": "Relay name (URL)"
}, },
"Bo+O//": {
"defaultMessage": "HTTP Auth"
},
"C1LjMx": { "C1LjMx": {
"defaultMessage": "Lightning Donation" "defaultMessage": "Lightning Donation"
}, },
@ -431,6 +500,9 @@
"CzHZoc": { "CzHZoc": {
"defaultMessage": "Social Graph" "defaultMessage": "Social Graph"
}, },
"D++Njw": {
"defaultMessage": "Text Note References"
},
"D+KzKd": { "D+KzKd": {
"defaultMessage": "Automatically zap every note when loaded" "defaultMessage": "Automatically zap every note when loaded"
}, },
@ -500,9 +572,15 @@
"F3l7xL": { "F3l7xL": {
"defaultMessage": "Add Account" "defaultMessage": "Add Account"
}, },
"F4eJ/3": {
"defaultMessage": "Classified Listings"
},
"FDguSC": { "FDguSC": {
"defaultMessage": "{n} Zaps" "defaultMessage": "{n} Zaps"
}, },
"FHvSk3": {
"defaultMessage": "Authentication of clients to relays"
},
"FMfjrl": { "FMfjrl": {
"defaultMessage": "Show status messages on profile pages" "defaultMessage": "Show status messages on profile pages"
}, },
@ -539,6 +617,9 @@
"GFOoEE": { "GFOoEE": {
"defaultMessage": "Salt" "defaultMessage": "Salt"
}, },
"GIqktu": {
"defaultMessage": "Supported NIPs"
},
"GL8aXW": { "GL8aXW": {
"defaultMessage": "Bookmarks ({n})" "defaultMessage": "Bookmarks ({n})"
}, },
@ -564,6 +645,9 @@
"defaultMessage": "Hex Key..", "defaultMessage": "Hex Key..",
"description": "Hexidecimal 'key' input for improxy" "description": "Hexidecimal 'key' input for improxy"
}, },
"H/oroO": {
"defaultMessage": "Dealing with Unknown Events"
},
"H0JBH6": { "H0JBH6": {
"defaultMessage": "Log Out" "defaultMessage": "Log Out"
}, },
@ -594,6 +678,9 @@
"HqRNN8": { "HqRNN8": {
"defaultMessage": "Support" "defaultMessage": "Support"
}, },
"HzSFeV": {
"defaultMessage": "Expiration Timestamp"
},
"I1AoOu": { "I1AoOu": {
"defaultMessage": "Last post {time}" "defaultMessage": "Last post {time}"
}, },
@ -615,6 +702,9 @@
"IWz1ta": { "IWz1ta": {
"defaultMessage": "Auto Translate" "defaultMessage": "Auto Translate"
}, },
"IcHcWj": {
"defaultMessage": "Last Seen:"
},
"Ig9/a1": { "Ig9/a1": {
"defaultMessage": "Sent {n} sats to {name}" "defaultMessage": "Sent {n} sats to {name}"
}, },
@ -678,27 +768,45 @@
"JymXbw": { "JymXbw": {
"defaultMessage": "Private Key" "defaultMessage": "Private Key"
}, },
"K1wl1/": {
"defaultMessage": "Average Latency:"
},
"K3r6DQ": { "K3r6DQ": {
"defaultMessage": "Delete" "defaultMessage": "Delete"
}, },
"K7AkdL": { "K7AkdL": {
"defaultMessage": "Show" "defaultMessage": "Show"
}, },
"K9zklU": {
"defaultMessage": "External Content IDs"
},
"KAhAcM": { "KAhAcM": {
"defaultMessage": "Enter LNDHub config" "defaultMessage": "Enter LNDHub config"
}, },
"KGmQjH": {
"defaultMessage": "Highlights"
},
"KQvWvD": { "KQvWvD": {
"defaultMessage": "Deleted" "defaultMessage": "Deleted"
}, },
"KT9nox": {
"defaultMessage": "Protected Events"
},
"KahimY": { "KahimY": {
"defaultMessage": "Unknown event kind: {kind}" "defaultMessage": "Unknown event kind: {kind}"
}, },
"KipVeG": {
"defaultMessage": "Mapping Nostr keys to DNS-based internet identifiers"
},
"KtsyO0": { "KtsyO0": {
"defaultMessage": "Enter Pin" "defaultMessage": "Enter Pin"
}, },
"LBAnc7": { "LBAnc7": {
"defaultMessage": "View as user?" "defaultMessage": "View as user?"
}, },
"LEmxc8": {
"defaultMessage": "Zap Goals"
},
"LKw/ue": { "LKw/ue": {
"defaultMessage": "Check out the code {link}" "defaultMessage": "Check out the code {link}"
}, },
@ -720,6 +828,9 @@
"Lu5/Bj": { "Lu5/Bj": {
"defaultMessage": "Open on Zapstr" "defaultMessage": "Open on Zapstr"
}, },
"LuDBLj": {
"defaultMessage": "Torrents"
},
"Lw+I+J": { "Lw+I+J": {
"defaultMessage": "{n,plural,=0{{name} zapped} other{{name} & {n} others zapped}}" "defaultMessage": "{n,plural,=0{{name} zapped} other{{name} & {n} others zapped}}"
}, },
@ -748,6 +859,9 @@
"MiMipu": { "MiMipu": {
"defaultMessage": "Set as primary Nostr address (nip05)" "defaultMessage": "Set as primary Nostr address (nip05)"
}, },
"MkQ4FX": {
"defaultMessage": "Proxy Tags"
},
"Ml7+RS": { "Ml7+RS": {
"defaultMessage": "Send this link to your friends and share the magic of the nostr." "defaultMessage": "Send this link to your friends and share the magic of the nostr."
}, },
@ -757,6 +871,9 @@
"MuVeKe": { "MuVeKe": {
"defaultMessage": "Buy nostr address" "defaultMessage": "Buy nostr address"
}, },
"Muhna4": {
"defaultMessage": "Counting results"
},
"MzRYWH": { "MzRYWH": {
"defaultMessage": "Buying {item}" "defaultMessage": "Buying {item}"
}, },
@ -781,6 +898,9 @@
"NndBJE": { "NndBJE": {
"defaultMessage": "New users page" "defaultMessage": "New users page"
}, },
"Nr9Yyx": {
"defaultMessage": "Reposts"
},
"NxzeNU": { "NxzeNU": {
"defaultMessage": "Dead" "defaultMessage": "Dead"
}, },
@ -790,6 +910,12 @@
"OEW7yJ": { "OEW7yJ": {
"defaultMessage": "Zaps" "defaultMessage": "Zaps"
}, },
"OIqnZN": {
"defaultMessage": "OpenTimestamps Attestations for Events"
},
"OJHKIL": {
"defaultMessage": "Gift Wrap"
},
"OKhRC6": { "OKhRC6": {
"defaultMessage": "Share" "defaultMessage": "Share"
}, },
@ -808,6 +934,9 @@
"OoZgbB": { "OoZgbB": {
"defaultMessage": "Failed to update, please try again" "defaultMessage": "Failed to update, please try again"
}, },
"OuProE": {
"defaultMessage": "Long-form Content"
},
"OxPdQ0": { "OxPdQ0": {
"defaultMessage": "Scanning {date}" "defaultMessage": "Scanning {date}"
}, },
@ -850,6 +979,9 @@
"Qxv0B2": { "Qxv0B2": {
"defaultMessage": "You currently have {number} sats in your zap pool." "defaultMessage": "You currently have {number} sats in your zap pool."
}, },
"Qy6/Ft": {
"defaultMessage": "Private Direct Messages"
},
"R/6nsx": { "R/6nsx": {
"defaultMessage": "Subscription" "defaultMessage": "Subscription"
}, },
@ -871,6 +1003,9 @@
"RhDAoS": { "RhDAoS": {
"defaultMessage": "Are you sure you want to delete {id}" "defaultMessage": "Are you sure you want to delete {id}"
}, },
"RmxSZo": {
"defaultMessage": "Data Vending Machines"
},
"RoOyAh": { "RoOyAh": {
"defaultMessage": "Relays" "defaultMessage": "Relays"
}, },
@ -937,6 +1072,9 @@
"TdtZQ5": { "TdtZQ5": {
"defaultMessage": "Crypto" "defaultMessage": "Crypto"
}, },
"TgDKhI": {
"defaultMessage": "Calendar Events"
},
"TpgeGw": { "TpgeGw": {
"defaultMessage": "Hex Salt..", "defaultMessage": "Hex Salt..",
"description": "Hexidecimal 'salt' input for imgproxy" "description": "Hexidecimal 'salt' input for imgproxy"
@ -953,9 +1091,6 @@
"U1aPPi": { "U1aPPi": {
"defaultMessage": "Stop listening" "defaultMessage": "Stop listening"
}, },
"UDYlxu": {
"defaultMessage": "Pending Subscriptions"
},
"UJTWqI": { "UJTWqI": {
"defaultMessage": "Remove from my relays" "defaultMessage": "Remove from my relays"
}, },
@ -989,6 +1124,9 @@
"UxgyeY": { "UxgyeY": {
"defaultMessage": "Your referral code is {code}" "defaultMessage": "Your referral code is {code}"
}, },
"V20Og0": {
"defaultMessage": "Labeling"
},
"VOjC1i": { "VOjC1i": {
"defaultMessage": "Pick which upload service you want to upload attachments to" "defaultMessage": "Pick which upload service you want to upload attachments to"
}, },
@ -1064,6 +1202,9 @@
"YR2I9M": { "YR2I9M": {
"defaultMessage": "No keys, no {app}, There is no way to reset it if you don't back up. It only takes a minute." "defaultMessage": "No keys, no {app}, There is no way to reset it if you don't back up. It only takes a minute."
}, },
"YU7ZYp": {
"defaultMessage": "Public Chat"
},
"YXA3AH": { "YXA3AH": {
"defaultMessage": "Enable reactions" "defaultMessage": "Enable reactions"
}, },
@ -1073,6 +1214,9 @@
"Z4BMCZ": { "Z4BMCZ": {
"defaultMessage": "Enter pairing phrase" "defaultMessage": "Enter pairing phrase"
}, },
"Z7kkeJ": {
"defaultMessage": "Delegated Event Signing"
},
"ZKORll": { "ZKORll": {
"defaultMessage": "Activate Now" "defaultMessage": "Activate Now"
}, },
@ -1185,6 +1329,9 @@
"cuV2gK": { "cuV2gK": {
"defaultMessage": "name is registered" "defaultMessage": "name is registered"
}, },
"cw1Ftc": {
"defaultMessage": "Live Activities"
},
"cyR7Kh": { "cyR7Kh": {
"defaultMessage": "Back" "defaultMessage": "Back"
}, },
@ -1242,6 +1389,9 @@
"eXT2QQ": { "eXT2QQ": {
"defaultMessage": "Group Chat" "defaultMessage": "Group Chat"
}, },
"eZtOxB": {
"defaultMessage": "window.nostr capability for web browsers"
},
"egib+2": { "egib+2": {
"defaultMessage": "{n,plural,=1{& {n} other} other{& {n} others}}" "defaultMessage": "{n,plural,=1{& {n} other} other{& {n} others}}"
}, },
@ -1317,9 +1467,18 @@
"gjBiyj": { "gjBiyj": {
"defaultMessage": "Loading..." "defaultMessage": "Loading..."
}, },
"gkMmvC": {
"defaultMessage": "Android Signer Application"
},
"gl1NeW": {
"defaultMessage": "Lists"
},
"grQ+mI": { "grQ+mI": {
"defaultMessage": "Proof of Work" "defaultMessage": "Proof of Work"
}, },
"gtNjNP": {
"defaultMessage": "Basic protocol flow description"
},
"h7jvCs": { "h7jvCs": {
"defaultMessage": "{site} is more fun together!" "defaultMessage": "{site} is more fun together!"
}, },
@ -1374,6 +1533,9 @@
"iGT1eE": { "iGT1eE": {
"defaultMessage": "Prevent fake accounts from imitating you" "defaultMessage": "Prevent fake accounts from imitating you"
}, },
"iHN12u": {
"defaultMessage": "Admin"
},
"iICVoL": { "iICVoL": {
"defaultMessage": "{x} follows ({y} duplicates)" "defaultMessage": "{x} follows ({y} duplicates)"
}, },
@ -1455,6 +1617,9 @@
"l3H1EK": { "l3H1EK": {
"defaultMessage": "Invite your friends" "defaultMessage": "Invite your friends"
}, },
"l3nTjd": {
"defaultMessage": "Basic key derivation from mnemonic seed phrase"
},
"lCILNz": { "lCILNz": {
"defaultMessage": "Buy Now" "defaultMessage": "Buy Now"
}, },
@ -1551,9 +1716,6 @@
"p4N05H": { "p4N05H": {
"defaultMessage": "Upload" "defaultMessage": "Upload"
}, },
"p85Uwy": {
"defaultMessage": "Active Subscriptions"
},
"p9Ps2l": { "p9Ps2l": {
"defaultMessage": "{x}/{y} have relays ({percent})" "defaultMessage": "{x}/{y} have relays ({percent})"
}, },
@ -1566,9 +1728,15 @@
"pRess9": { "pRess9": {
"defaultMessage": "ZapPool" "defaultMessage": "ZapPool"
}, },
"plOM0t": {
"defaultMessage": "Custom Emoji"
},
"puLNUJ": { "puLNUJ": {
"defaultMessage": "Pin" "defaultMessage": "Pin"
}, },
"pyjJ5f": {
"defaultMessage": "Nostr Marketplace (for resilient marketplaces)"
},
"pzTOmv": { "pzTOmv": {
"defaultMessage": "Followers" "defaultMessage": "Followers"
}, },
@ -1626,15 +1794,27 @@
"r5srDR": { "r5srDR": {
"defaultMessage": "Enter wallet password" "defaultMessage": "Enter wallet password"
}, },
"rAQG0X": {
"defaultMessage": "Relay List Metadata"
},
"rMgF34": { "rMgF34": {
"defaultMessage": "Back up now" "defaultMessage": "Back up now"
}, },
"rRRXtB": {
"defaultMessage": "Lightning Zaps"
},
"rT14Ow": { "rT14Ow": {
"defaultMessage": "Add Relays" "defaultMessage": "Add Relays"
}, },
"reFEEC": {
"defaultMessage": "Reporting"
},
"rfuMjE": { "rfuMjE": {
"defaultMessage": "(Default)" "defaultMessage": "(Default)"
}, },
"rkM7l8": {
"defaultMessage": "Encrypted Direct Message"
},
"rmdsT4": { "rmdsT4": {
"defaultMessage": "{n} days" "defaultMessage": "{n} days"
}, },
@ -1656,12 +1836,30 @@
"saInmO": { "saInmO": {
"defaultMessage": "The relay name shown is not the same as the full URL entered." "defaultMessage": "The relay name shown is not the same as the full URL entered."
}, },
"saorw+": {
"defaultMessage": "Event Deletion Request"
},
"sfL/O+": { "sfL/O+": {
"defaultMessage": "Muted notes will not be shown" "defaultMessage": "Muted notes will not be shown"
}, },
"t79a6U": {
"defaultMessage": "Connection Success:"
},
"tO1oq9": {
"defaultMessage": "Video Events"
},
"tOdNiY": { "tOdNiY": {
"defaultMessage": "Dark" "defaultMessage": "Dark"
}, },
"tRGdV1": {
"defaultMessage": "Versioned Encryption"
},
"tU0ADf": {
"defaultMessage": "Unknown NIP-{x}"
},
"tf1lIh": {
"defaultMessage": "Free"
},
"th5lxp": { "th5lxp": {
"defaultMessage": "Send note to a subset of your write relays" "defaultMessage": "Send note to a subset of your write relays"
}, },
@ -1692,6 +1890,9 @@
"uCk8r+": { "uCk8r+": {
"defaultMessage": "Already have an account?" "defaultMessage": "Already have an account?"
}, },
"uD7Els": {
"defaultMessage": "External Identities in Profiles"
},
"uSV4Ti": { "uSV4Ti": {
"defaultMessage": "Reposts need to be manually confirmed" "defaultMessage": "Reposts need to be manually confirmed"
}, },
@ -1749,6 +1950,9 @@
"wSZR47": { "wSZR47": {
"defaultMessage": "Submit" "defaultMessage": "Submit"
}, },
"wc9st7": {
"defaultMessage": "Media Attachments"
},
"whSrs+": { "whSrs+": {
"defaultMessage": "Nostr Public Chat" "defaultMessage": "Nostr Public Chat"
}, },
@ -1782,6 +1986,9 @@
"xIoGG9": { "xIoGG9": {
"defaultMessage": "Go to" "defaultMessage": "Go to"
}, },
"xPCyu+": {
"defaultMessage": "nostr: URI scheme"
},
"xSoIUU": { "xSoIUU": {
"defaultMessage": "Worker Relay" "defaultMessage": "Worker Relay"
}, },
@ -1836,6 +2043,9 @@
"zcaOTs": { "zcaOTs": {
"defaultMessage": "Zap amount in sats" "defaultMessage": "Zap amount in sats"
}, },
"zi9MdS": {
"defaultMessage": "Chess (PGN)"
},
"zm6qS1": { "zm6qS1": {
"defaultMessage": "{n} mins to read" "defaultMessage": "{n} mins to read"
}, },

View File

@ -2,6 +2,7 @@
"+D82kt": "Are you sure you want to repost: {id}", "+D82kt": "Are you sure you want to repost: {id}",
"+PzQ9Y": "Payout Now", "+PzQ9Y": "Payout Now",
"+QM0PJ": "Sync all events for your profile into local cache", "+QM0PJ": "Sync all events for your profile into local cache",
"+QMdsy": "Relay Stats",
"+UjDmN": "Logged in with write access", "+UjDmN": "Logged in with write access",
"+Vxixo": "Secret Group Chat", "+Vxixo": "Secret Group Chat",
"+aZY2h": "Zap Type", "+aZY2h": "Zap Type",
@ -14,6 +15,7 @@
"/B8zwF": "Your space the way you want it 😌", "/B8zwF": "Your space the way you want it 😌",
"/GCoTA": "Clear", "/GCoTA": "Clear",
"/JE/X+": "Account Support", "/JE/X+": "Account Support",
"/T7HId": "HTTP File Storage Integration",
"/Xf4UW": "Send anonymous usage metrics", "/Xf4UW": "Send anonymous usage metrics",
"/clOBU": "Weekly", "/clOBU": "Weekly",
"/d6vEc": "Make your profile easier to find and share", "/d6vEc": "Make your profile easier to find and share",
@ -25,11 +27,13 @@
"0BUTMv": "Search...", "0BUTMv": "Search...",
"0MndVW": "Generic LNDHub wallet (BTCPayServer / Alby / LNBits)", "0MndVW": "Generic LNDHub wallet (BTCPayServer / Alby / LNBits)",
"0jOEtS": "Invalid LNURL", "0jOEtS": "Invalid LNURL",
"0kOBMu": "Handling Mentions",
"0mch2Y": "name has disallowed characters", "0mch2Y": "name has disallowed characters",
"0siT4z": "Politics", "0siT4z": "Politics",
"0uoY11": "Show Status", "0uoY11": "Show Status",
"0yO7wF": "{n} secs", "0yO7wF": "{n} secs",
"0zASjL": "Go", "0zASjL": "Go",
"1/BFEj": "git stuff",
"1Mo59U": "Are you sure you want to remove this note from bookmarks?", "1Mo59U": "Are you sure you want to remove this note from bookmarks?",
"1R43+L": "Enter Nostr Wallet Connect config", "1R43+L": "Enter Nostr Wallet Connect config",
"1UWegE": "Be sure to back up your keys!", "1UWegE": "Be sure to back up your keys!",
@ -41,6 +45,9 @@
"2/2yg+": "Add", "2/2yg+": "Add",
"25V4l1": "Banner", "25V4l1": "Banner",
"25WwxF": "Don't have an account?", "25WwxF": "Don't have an account?",
"28oKbu": "Moderated Communities",
"29sHFE": "Wallet Connect",
"2BBGxX": "Subject tag in text events",
"2IFGap": "Donate", "2IFGap": "Donate",
"2LbrkB": "Enter password", "2LbrkB": "Enter password",
"2O2sfp": "Finish", "2O2sfp": "Finish",
@ -48,8 +55,10 @@
"2k0Cv+": "Dislikes ({n})", "2k0Cv+": "Dislikes ({n})",
"2mcwT8": "New Note", "2mcwT8": "New Note",
"2oCF7O": "Followed by friends of friends", "2oCF7O": "Followed by friends of friends",
"2raFAu": "Application-specific data",
"2ukA4d": "{n} hours", "2ukA4d": "{n} hours",
"39AHJm": "Sign Up", "39AHJm": "Sign Up",
"3GWu6/": "User Statuses",
"3KNMbJ": "Articles", "3KNMbJ": "Articles",
"3QwfJR": "~{amount}", "3QwfJR": "~{amount}",
"3cc4Ct": "Light", "3cc4Ct": "Light",
@ -58,25 +67,32 @@
"3t3kok": "{n,plural,=1{{n} new note} other{{n} new notes}}", "3t3kok": "{n,plural,=1{{n} new note} other{{n} new notes}}",
"3tVy+Z": "{n} Followers", "3tVy+Z": "{n} Followers",
"3yk8fB": "Wallet", "3yk8fB": "Wallet",
"40VR6s": "Nostr Connect",
"41BSaT": "Total Events:",
"450Fty": "None", "450Fty": "None",
"47E53q": "Wiki",
"47FYwb": "Cancel", "47FYwb": "Cancel",
"4IPzdn": "Primary Developers", "4IPzdn": "Primary Developers",
"4L2vUY": "Your new NIP-05 handle is:", "4L2vUY": "Your new NIP-05 handle is:",
"4MjsHk": "Life", "4MjsHk": "Life",
"4OB335": "Dislike", "4OB335": "Dislike",
"4P/kKm": "Private Key Encryption",
"4Vmpt4": "Nostr Plebs is one of the first NIP-05 providers in the space and offers a good collection of domains at reasonable prices", "4Vmpt4": "Nostr Plebs is one of the first NIP-05 providers in the space and offers a good collection of domains at reasonable prices",
"4Z3t5i": "Use imgproxy to compress images", "4Z3t5i": "Use imgproxy to compress images",
"4emo2p": "Missing Relays", "4emo2p": "Missing Relays",
"4rYCjn": "Note to Self", "4rYCjn": "Note to Self",
"4wgYpI": "Recommended Application Handlers",
"5BVs2e": "zap", "5BVs2e": "zap",
"5CB6zB": "Zap Splits", "5CB6zB": "Zap Splits",
"5PRWs7": "Notifications API Enabled", "5PRWs7": "Notifications API Enabled",
"5oTnfy": "Buy Handle", "5oTnfy": "Buy Handle",
"5qEWCr": "File Metadata",
"5u6iEc": "Transfer to Pubkey", "5u6iEc": "Transfer to Pubkey",
"5vMmmR": "Usernames are not unique on Nostr. The nostr address is your unique human-readable address that is unique to you upon registration.", "5vMmmR": "Usernames are not unique on Nostr. The nostr address is your unique human-readable address that is unique to you upon registration.",
"5ykRmX": "Send zap", "5ykRmX": "Send zap",
"6/hB3S": "Watch Replay", "6/hB3S": "Watch Replay",
"62nsdy": "Retry", "62nsdy": "Retry",
"634VVz": "Connection Failed:",
"6559gb": "New follow list length {length}", "6559gb": "New follow list length {length}",
"65BmHb": "Failed to proxy image from {host}, click here to load directly", "65BmHb": "Failed to proxy image from {host}, click here to load directly",
"6OSOXl": "Reason: <i>{reason}</i>", "6OSOXl": "Reason: <i>{reason}</i>",
@ -84,21 +100,26 @@
"6ewQqw": "Likes ({n})", "6ewQqw": "Likes ({n})",
"6k7xfM": "Trending notes", "6k7xfM": "Trending notes",
"6mr8WU": "Followed by", "6mr8WU": "Followed by",
"6pdxsi": "Extra metadata fields and tags",
"6uMqL1": "Unpaid", "6uMqL1": "Unpaid",
"6xap9L": "Good", "6xap9L": "Good",
"7+Domh": "Notes", "7+Domh": "Notes",
"712i26": "Proxy uses HODL invoices to forward the payment, which hides the pubkey of your node", "712i26": "Proxy uses HODL invoices to forward the payment, which hides the pubkey of your node",
"77nkEO": "Relay Information Document",
"7LFU8U": "Search Capability",
"7UOvbT": "Offline", "7UOvbT": "Offline",
"7YkSA2": "Community Leader", "7YkSA2": "Community Leader",
"7hp70g": "NIP-05", "7hp70g": "NIP-05",
"8/vBbP": "Reposts ({n})", "8/vBbP": "Reposts ({n})",
"89q5wc": "Confirm Reposts", "89q5wc": "Confirm Reposts",
"8BDFvJ": "Conventions for clients' use of e and p tags in text events",
"8ED/4u": "Reply To", "8ED/4u": "Reply To",
"8HJxXG": "Sign up", "8HJxXG": "Sign up",
"8QDesP": "Zap {n} sats", "8QDesP": "Zap {n} sats",
"8Rkoyb": "Recipient", "8Rkoyb": "Recipient",
"8Y6bZQ": "Invalid zap split: {input}", "8Y6bZQ": "Invalid zap split: {input}",
"8g2vyB": "name too long", "8g2vyB": "name too long",
"8jmwT8": "bech32-encoded entities",
"8v1NN+": "Pairing phrase", "8v1NN+": "Pairing phrase",
"9+Ddtu": "Next", "9+Ddtu": "Next",
"9HU8vw": "Reply", "9HU8vw": "Reply",
@ -125,9 +146,11 @@
"B6H7eJ": "nsec, npub, nip-05, hex", "B6H7eJ": "nsec, npub, nip-05, hex",
"B7wvUM": "You can add a single or multiple relays, one per line.", "B7wvUM": "You can add a single or multiple relays, one per line.",
"BGCM48": "Write access to Snort relay, with 1 year of event retention", "BGCM48": "Write access to Snort relay, with 1 year of event retention",
"BQW4gi": "Relay-based Groups",
"BWpuKl": "Update", "BWpuKl": "Update",
"BjNwZW": "Nostr address (nip05)", "BjNwZW": "Nostr address (nip05)",
"Blxcdx": "Relay", "Blxcdx": "Relay",
"Bo+O//": "HTTP Auth",
"C1LjMx": "Lightning Donation", "C1LjMx": "Lightning Donation",
"C7642/": "Quote Repost", "C7642/": "Quote Repost",
"C81/uG": "Logout", "C81/uG": "Logout",
@ -142,6 +165,7 @@
"CsCUYo": "{n} sats", "CsCUYo": "{n} sats",
"Cu/K85": "Translated from {lang}", "Cu/K85": "Translated from {lang}",
"CzHZoc": "Social Graph", "CzHZoc": "Social Graph",
"D++Njw": "Text Note References",
"D+KzKd": "Automatically zap every note when loaded", "D+KzKd": "Automatically zap every note when loaded",
"D3idYv": "Settings", "D3idYv": "Settings",
"DBiVK1": "Cache", "DBiVK1": "Cache",
@ -165,7 +189,9 @@
"EjFyoR": "On-chain Donation Address", "EjFyoR": "On-chain Donation Address",
"EnCOBJ": "Buy", "EnCOBJ": "Buy",
"F3l7xL": "Add Account", "F3l7xL": "Add Account",
"F4eJ/3": "Classified Listings",
"FDguSC": "{n} Zaps", "FDguSC": "{n} Zaps",
"FHvSk3": "Authentication of clients to relays",
"FMfjrl": "Show status messages on profile pages", "FMfjrl": "Show status messages on profile pages",
"FSYL8G": "Trending Users", "FSYL8G": "Trending Users",
"FcNSft": "Redirect issues HTTP redirect to the supplied lightning address", "FcNSft": "Redirect issues HTTP redirect to the supplied lightning address",
@ -178,6 +204,7 @@
"G1BGCg": "Select Wallet", "G1BGCg": "Select Wallet",
"G3A56c": "Subscribed to Push", "G3A56c": "Subscribed to Push",
"GFOoEE": "Salt", "GFOoEE": "Salt",
"GIqktu": "Supported NIPs",
"GL8aXW": "Bookmarks ({n})", "GL8aXW": "Bookmarks ({n})",
"GSye7T": "Lightning Address", "GSye7T": "Lightning Address",
"GUlSVG": "Claim your included Snort nostr address", "GUlSVG": "Claim your included Snort nostr address",
@ -186,6 +213,7 @@
"GspYR7": "{n} Dislike", "GspYR7": "{n} Dislike",
"Gxcr08": "Broadcast Event", "Gxcr08": "Broadcast Event",
"H+vHiz": "Hex Key..", "H+vHiz": "Hex Key..",
"H/oroO": "Dealing with Unknown Events",
"H0JBH6": "Log Out", "H0JBH6": "Log Out",
"H0OG3T": "Leader Info", "H0OG3T": "Leader Info",
"H6/kLh": "Order Paid!", "H6/kLh": "Order Paid!",
@ -196,6 +224,7 @@
"HbefNb": "Open Wallet", "HbefNb": "Open Wallet",
"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": "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.",
"HqRNN8": "Support", "HqRNN8": "Support",
"HzSFeV": "Expiration Timestamp",
"I1AoOu": "Last post {time}", "I1AoOu": "Last post {time}",
"IEwZvs": "Are you sure you want to unpin this note?", "IEwZvs": "Are you sure you want to unpin this note?",
"IIOul1": "Account Data", "IIOul1": "Account Data",
@ -203,6 +232,7 @@
"IOu4Xh": "You must be a {tier} subscriber to access {app} deck", "IOu4Xh": "You must be a {tier} subscriber to access {app} deck",
"IVbtTS": "Zap all {n} sats", "IVbtTS": "Zap all {n} sats",
"IWz1ta": "Auto Translate", "IWz1ta": "Auto Translate",
"IcHcWj": "Last Seen:",
"Ig9/a1": "Sent {n} sats to {name}", "Ig9/a1": "Sent {n} sats to {name}",
"IgsWFG": "Not followed by anyone you follow", "IgsWFG": "Not followed by anyone you follow",
"IoQq+a": "Click here to load anyway", "IoQq+a": "Click here to load anyway",
@ -224,13 +254,19 @@
"JkLHGw": "Website", "JkLHGw": "Website",
"JmcxzF": "Relays are servers you connect to for sending and receiving events. Aim for 4-8 relays.", "JmcxzF": "Relays are servers you connect to for sending and receiving events. Aim for 4-8 relays.",
"JymXbw": "Private Key", "JymXbw": "Private Key",
"K1wl1/": "Average Latency:",
"K3r6DQ": "Delete", "K3r6DQ": "Delete",
"K7AkdL": "Show", "K7AkdL": "Show",
"K9zklU": "External Content IDs",
"KAhAcM": "Enter LNDHub config", "KAhAcM": "Enter LNDHub config",
"KGmQjH": "Highlights",
"KQvWvD": "Deleted", "KQvWvD": "Deleted",
"KT9nox": "Protected Events",
"KahimY": "Unknown event kind: {kind}", "KahimY": "Unknown event kind: {kind}",
"KipVeG": "Mapping Nostr keys to DNS-based internet identifiers",
"KtsyO0": "Enter Pin", "KtsyO0": "Enter Pin",
"LBAnc7": "View as user?", "LBAnc7": "View as user?",
"LEmxc8": "Zap Goals",
"LKw/ue": "Check out the code {link}", "LKw/ue": "Check out the code {link}",
"LR1XjT": "Pin too short", "LR1XjT": "Pin too short",
"LXxsbk": "Anonymous", "LXxsbk": "Anonymous",
@ -238,6 +274,7 @@
"LhLvRx": "Name must be between 8 and 15 characters", "LhLvRx": "Name must be between 8 and 15 characters",
"LmdPXO": "Cannot verify Nostr Address", "LmdPXO": "Cannot verify Nostr Address",
"Lu5/Bj": "Open on Zapstr", "Lu5/Bj": "Open on Zapstr",
"LuDBLj": "Torrents",
"Lw+I+J": "{n,plural,=0{{name} zapped} other{{name} & {n} others zapped}}", "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.", "LwYmVi": "Zaps on this note will be split to the following users.",
"M3Oirc": "Debug Menus", "M3Oirc": "Debug Menus",
@ -247,9 +284,11 @@
"MP54GY": "Wallet password", "MP54GY": "Wallet password",
"MWTx65": "Default Page", "MWTx65": "Default Page",
"MiMipu": "Set as primary Nostr address (nip05)", "MiMipu": "Set as primary Nostr address (nip05)",
"MkQ4FX": "Proxy Tags",
"Ml7+RS": "Send this link to your friends and share the magic of the nostr.", "Ml7+RS": "Send this link to your friends and share the magic of the nostr.",
"Mrpkot": "Pay for subscription", "Mrpkot": "Pay for subscription",
"MuVeKe": "Buy nostr address", "MuVeKe": "Buy nostr address",
"Muhna4": "Counting results",
"MzRYWH": "Buying {item}", "MzRYWH": "Buying {item}",
"Mzizei": "Iris.to account", "Mzizei": "Iris.to account",
"N2IrpM": "Confirm", "N2IrpM": "Confirm",
@ -258,15 +297,19 @@
"NdOYJJ": "Hmm nothing here.. Checkout {newUsersPage} to follow some recommended nostrich's!", "NdOYJJ": "Hmm nothing here.. Checkout {newUsersPage} to follow some recommended nostrich's!",
"NepkXH": "Can't vote with {amount} sats, please set a different default zap amount", "NepkXH": "Can't vote with {amount} sats, please set a different default zap amount",
"NndBJE": "New users page", "NndBJE": "New users page",
"Nr9Yyx": "Reposts",
"NxzeNU": "Dead", "NxzeNU": "Dead",
"O3Jz4E": "Use your invite code to earn sats!", "O3Jz4E": "Use your invite code to earn sats!",
"OEW7yJ": "Zaps", "OEW7yJ": "Zaps",
"OIqnZN": "OpenTimestamps Attestations for Events",
"OJHKIL": "Gift Wrap",
"OKhRC6": "Share", "OKhRC6": "Share",
"OLEm6z": "Unknown login error", "OLEm6z": "Unknown login error",
"OQSOJF": "Get a free nostr address", "OQSOJF": "Get a free nostr address",
"OQXnew": "You subscription is still active, you can't renew yet", "OQXnew": "You subscription is still active, you can't renew yet",
"ORGv1Q": "Created", "ORGv1Q": "Created",
"OoZgbB": "Failed to update, please try again", "OoZgbB": "Failed to update, please try again",
"OuProE": "Long-form Content",
"OxPdQ0": "Scanning {date}", "OxPdQ0": "Scanning {date}",
"P2o+ZZ": "Invalid Nostr Address", "P2o+ZZ": "Invalid Nostr Address",
"P61BTu": "Copy Event JSON", "P61BTu": "Copy Event JSON",
@ -281,6 +324,7 @@
"QJfhKt": "The private key is like a password, but it cannot be reset. Guard it carefully and never show it to anyone. Once someone has your private key, they will have access to your account forever.", "QJfhKt": "The private key is like a password, but it cannot be reset. Guard it carefully and never show it to anyone. Once someone has your private key, they will have access to your account forever.",
"QWhotP": "Zap Pool only works if you use one of the supported wallet connections (WebLN, LNC, LNDHub or Nostr Wallet Connect)", "QWhotP": "Zap Pool only works if you use one of the supported wallet connections (WebLN, LNC, LNDHub or Nostr Wallet Connect)",
"Qxv0B2": "You currently have {number} sats in your zap pool.", "Qxv0B2": "You currently have {number} sats in your zap pool.",
"Qy6/Ft": "Private Direct Messages",
"R/6nsx": "Subscription", "R/6nsx": "Subscription",
"R81upa": "People you follow", "R81upa": "People you follow",
"RDha9y": "Service Worker Not Running", "RDha9y": "Service Worker Not Running",
@ -288,6 +332,7 @@
"RahCRH": "Expired", "RahCRH": "Expired",
"RfhLwC": "By: {author}", "RfhLwC": "By: {author}",
"RhDAoS": "Are you sure you want to delete {id}", "RhDAoS": "Are you sure you want to delete {id}",
"RmxSZo": "Data Vending Machines",
"RoOyAh": "Relays", "RoOyAh": "Relays",
"RrCui3": "Summary", "RrCui3": "Summary",
"Rs4kCE": "Bookmark", "Rs4kCE": "Bookmark",
@ -310,12 +355,12 @@
"TaeBqw": "Sign in with Nostr Extension", "TaeBqw": "Sign in with Nostr Extension",
"TdTXXf": "Learn more", "TdTXXf": "Learn more",
"TdtZQ5": "Crypto", "TdtZQ5": "Crypto",
"TgDKhI": "Calendar Events",
"TpgeGw": "Hex Salt..", "TpgeGw": "Hex Salt..",
"Tpy00S": "People", "Tpy00S": "People",
"TvKqBp": "liked", "TvKqBp": "liked",
"TwyMau": "Account", "TwyMau": "Account",
"U1aPPi": "Stop listening", "U1aPPi": "Stop listening",
"UDYlxu": "Pending Subscriptions",
"UJTWqI": "Remove from my relays", "UJTWqI": "Remove from my relays",
"ULXFfP": "Receive", "ULXFfP": "Receive",
"UNjfWJ": "Check all event signatures received from relays", "UNjfWJ": "Check all event signatures received from relays",
@ -327,6 +372,7 @@
"Ups2/p": "Your application is pending", "Ups2/p": "Your application is pending",
"UrKTqQ": "You have an active iris.to account", "UrKTqQ": "You have an active iris.to account",
"UxgyeY": "Your referral code is {code}", "UxgyeY": "Your referral code is {code}",
"V20Og0": "Labeling",
"VOjC1i": "Pick which upload service you want to upload attachments to", "VOjC1i": "Pick which upload service you want to upload attachments to",
"VR5eHw": "Public key (npub/nprofile)", "VR5eHw": "Public key (npub/nprofile)",
"VcwrfF": "Yes please", "VcwrfF": "Yes please",
@ -352,9 +398,11 @@
"YDMrKK": "Users", "YDMrKK": "Users",
"YDURw6": "Service URL", "YDURw6": "Service URL",
"YR2I9M": "No keys, no {app}, There is no way to reset it if you don't back up. It only takes a minute.", "YR2I9M": "No keys, no {app}, There is no way to reset it if you don't back up. It only takes a minute.",
"YU7ZYp": "Public Chat",
"YXA3AH": "Enable reactions", "YXA3AH": "Enable reactions",
"Yf3DwC": "Connect a wallet to send instant payments", "Yf3DwC": "Connect a wallet to send instant payments",
"Z4BMCZ": "Enter pairing phrase", "Z4BMCZ": "Enter pairing phrase",
"Z7kkeJ": "Delegated Event Signing",
"ZKORll": "Activate Now", "ZKORll": "Activate Now",
"ZLmyG9": "Contributors", "ZLmyG9": "Contributors",
"ZS+jRE": "Send zap splits to", "ZS+jRE": "Send zap splits to",
@ -392,6 +440,7 @@
"cg1VJ2": "Connect Wallet", "cg1VJ2": "Connect Wallet",
"cuP16y": "Multi account support", "cuP16y": "Multi account support",
"cuV2gK": "name is registered", "cuV2gK": "name is registered",
"cw1Ftc": "Live Activities",
"cyR7Kh": "Back", "cyR7Kh": "Back",
"d+6YsV": "Lists to mute:", "d+6YsV": "Lists to mute:",
"d2ebEu": "Not Subscribed to Push", "d2ebEu": "Not Subscribed to Push",
@ -411,6 +460,7 @@
"eJj8HD": "Get Verified", "eJj8HD": "Get Verified",
"eSzf2G": "A single zap of {nIn} sats will allocate {nOut} sats to the zap pool.", "eSzf2G": "A single zap of {nIn} sats will allocate {nOut} sats to the zap pool.",
"eXT2QQ": "Group Chat", "eXT2QQ": "Group Chat",
"eZtOxB": "window.nostr capability for web browsers",
"egib+2": "{n,plural,=1{& {n} other} other{& {n} others}}", "egib+2": "{n,plural,=1{& {n} other} other{& {n} others}}",
"ejEGdx": "Home", "ejEGdx": "Home",
"eoV49s": "Poor", "eoV49s": "Poor",
@ -436,7 +486,10 @@
"gczcC5": "Subscribe", "gczcC5": "Subscribe",
"geppt8": "{count} ({count2} in memory)", "geppt8": "{count} ({count2} in memory)",
"gjBiyj": "Loading...", "gjBiyj": "Loading...",
"gkMmvC": "Android Signer Application",
"gl1NeW": "Lists",
"grQ+mI": "Proof of Work", "grQ+mI": "Proof of Work",
"gtNjNP": "Basic protocol flow description",
"h7jvCs": "{site} is more fun together!", "h7jvCs": "{site} is more fun together!",
"h8XMJL": "Badges", "h8XMJL": "Badges",
"hF6IN2": "Prune Follow List", "hF6IN2": "Prune Follow List",
@ -455,6 +508,7 @@
"iCqGww": "Reactions ({n})", "iCqGww": "Reactions ({n})",
"iEoXYx": "DeepL translations", "iEoXYx": "DeepL translations",
"iGT1eE": "Prevent fake accounts from imitating you", "iGT1eE": "Prevent fake accounts from imitating you",
"iHN12u": "Admin",
"iICVoL": "{x} follows ({y} duplicates)", "iICVoL": "{x} follows ({y} duplicates)",
"iNWbVV": "Handle", "iNWbVV": "Handle",
"iXPL0Z": "Can't login with private key on an insecure connection, please use a Nostr key manager extension instead", "iXPL0Z": "Can't login with private key on an insecure connection, please use a Nostr key manager extension instead",
@ -482,6 +536,7 @@
"kuPHYE": "{n,plural,=0{{name} liked} other{{name} & {n} others liked}}", "kuPHYE": "{n,plural,=0{{name} liked} other{{name} & {n} others liked}}",
"l+ikU1": "Everything in {plan}", "l+ikU1": "Everything in {plan}",
"l3H1EK": "Invite your friends", "l3H1EK": "Invite your friends",
"l3nTjd": "Basic key derivation from mnemonic seed phrase",
"lCILNz": "Buy Now", "lCILNz": "Buy Now",
"lD3+8a": "Pay", "lD3+8a": "Pay",
"lEnclp": "My events: {n}", "lEnclp": "My events: {n}",
@ -514,12 +569,13 @@
"odFwjL": "Follows only", "odFwjL": "Follows only",
"ojzbwv": "Hey, it looks like you dont have a Nostr Address yet, you should get one! Check out {link}", "ojzbwv": "Hey, it looks like you dont have a Nostr Address yet, you should get one! Check out {link}",
"p4N05H": "Upload", "p4N05H": "Upload",
"p85Uwy": "Active Subscriptions",
"p9Ps2l": "{x}/{y} have relays ({percent})", "p9Ps2l": "{x}/{y} have relays ({percent})",
"pEEBFk": "Reliable Relays", "pEEBFk": "Reliable Relays",
"pI+77w": "Downloadable backups from Snort relay", "pI+77w": "Downloadable backups from Snort relay",
"pRess9": "ZapPool", "pRess9": "ZapPool",
"plOM0t": "Custom Emoji",
"puLNUJ": "Pin", "puLNUJ": "Pin",
"pyjJ5f": "Nostr Marketplace (for resilient marketplaces)",
"pzTOmv": "Followers", "pzTOmv": "Followers",
"qD9EUF": "Email <> DM bridge for your Snort nostr address", "qD9EUF": "Email <> DM bridge for your Snort nostr address",
"qDwvZ4": "Unknown error", "qDwvZ4": "Unknown error",
@ -539,9 +595,13 @@
"qz9fty": "Incorrect pin", "qz9fty": "Incorrect pin",
"r3C4x/": "Software", "r3C4x/": "Software",
"r5srDR": "Enter wallet password", "r5srDR": "Enter wallet password",
"rAQG0X": "Relay List Metadata",
"rMgF34": "Back up now", "rMgF34": "Back up now",
"rRRXtB": "Lightning Zaps",
"rT14Ow": "Add Relays", "rT14Ow": "Add Relays",
"reFEEC": "Reporting",
"rfuMjE": "(Default)", "rfuMjE": "(Default)",
"rkM7l8": "Encrypted Direct Message",
"rmdsT4": "{n} days", "rmdsT4": "{n} days",
"rn52n9": "Public Chat Channels", "rn52n9": "Public Chat Channels",
"rx1i0i": "Short link", "rx1i0i": "Short link",
@ -549,8 +609,14 @@
"sUNhQE": "user", "sUNhQE": "user",
"sZQzjQ": "Failed to parse zap split: {input}", "sZQzjQ": "Failed to parse zap split: {input}",
"saInmO": "The relay name shown is not the same as the full URL entered.", "saInmO": "The relay name shown is not the same as the full URL entered.",
"saorw+": "Event Deletion Request",
"sfL/O+": "Muted notes will not be shown", "sfL/O+": "Muted notes will not be shown",
"t79a6U": "Connection Success:",
"tO1oq9": "Video Events",
"tOdNiY": "Dark", "tOdNiY": "Dark",
"tRGdV1": "Versioned Encryption",
"tU0ADf": "Unknown NIP-{x}",
"tf1lIh": "Free",
"th5lxp": "Send note to a subset of your write relays", "th5lxp": "Send note to a subset of your write relays",
"thnRpU": "Getting NIP-05 verified can help:", "thnRpU": "Getting NIP-05 verified can help:",
"tj6kdX": "{sign} {amount} sats", "tj6kdX": "{sign} {amount} sats",
@ -561,6 +627,7 @@
"u81G9+": "Uptime", "u81G9+": "Uptime",
"u9NoC1": "Name must be less than {limit} characters", "u9NoC1": "Name must be less than {limit} characters",
"uCk8r+": "Already have an account?", "uCk8r+": "Already have an account?",
"uD7Els": "External Identities in Profiles",
"uSV4Ti": "Reposts need to be manually confirmed", "uSV4Ti": "Reposts need to be manually confirmed",
"uc0din": "Send sats splits to", "uc0din": "Send sats splits to",
"ufvXH1": "Found {n} events", "ufvXH1": "Found {n} events",
@ -580,6 +647,7 @@
"w6qrwX": "NSFW", "w6qrwX": "NSFW",
"wEQDC6": "Edit", "wEQDC6": "Edit",
"wSZR47": "Submit", "wSZR47": "Submit",
"wc9st7": "Media Attachments",
"whSrs+": "Nostr Public Chat", "whSrs+": "Nostr Public Chat",
"wih7iJ": "name is blocked", "wih7iJ": "name is blocked",
"wofVHy": "Moderation", "wofVHy": "Moderation",
@ -591,6 +659,7 @@
"xEjBS7": "For you", "xEjBS7": "For you",
"xIcAOU": "Votes by {type}", "xIcAOU": "Votes by {type}",
"xIoGG9": "Go to", "xIoGG9": "Go to",
"xPCyu+": "nostr: URI scheme",
"xSoIUU": "Worker Relay", "xSoIUU": "Worker Relay",
"xaj9Ba": "Provider", "xaj9Ba": "Provider",
"xbVgIm": "Automatically load media", "xbVgIm": "Automatically load media",
@ -609,6 +678,7 @@
"zINlao": "Owner", "zINlao": "Owner",
"zQvVDJ": "All", "zQvVDJ": "All",
"zcaOTs": "Zap amount in sats", "zcaOTs": "Zap amount in sats",
"zi9MdS": "Chess (PGN)",
"zm6qS1": "{n} mins to read", "zm6qS1": "{n} mins to read",
"zonsdq": "Failed to load LNURL service", "zonsdq": "Failed to load LNURL service",
"zvCDao": "Automatically show latest notes", "zvCDao": "Automatically show latest notes",